Refuse to create a database without naming one

`create=True` had nothing to act on across a set and was accepted anyway,
leaving the first query to fail on whichever database was missing.
This commit is contained in:
Yiorgis Gozadinos 2026-08-24 15:36:09 +03:00
parent bddb32b469
commit 9fefcdb629
No known key found for this signature in database
3 changed files with 43 additions and 0 deletions

View file

@ -232,6 +232,10 @@ the same queries: retrieval MAP 0.9914 with a reranker against 0.9918 for the
same corpus in a single database, and 0.6044 without one against 0.9798. The cost
is that a reranker scores candidates in proportion to the number of databases.
Creating names a database: `create=True` on a client covering the set raises
`AmbiguousDatabaseError`, and `HaikuRAG(config=config, create=True,
sources=["name"])` creates that one.
Converting, chunking and title generation are functions of the configuration
rather than of a database, so they work on a client covering the set. Writing,
rebuilding and vacuuming name one database: asking a set-covering client raises

View file

@ -230,6 +230,12 @@ class HaikuRAG:
"""
selected = self._selected()
if len(selected) > 1:
if self._create:
raise AmbiguousDatabaseError(
"create=True creates one database, and this client covers "
f"{', '.join(sorted(selected))}; name the one to create with "
"sources=[name]"
)
self._federated = selected
return self
if selected:

View file

@ -437,6 +437,39 @@ class TestDatabaseIndependentWork:
assert rag.embedder is rag.store.embedder
class TestCreatingNeedsOneDatabase:
"""Creating names a database. Covering a set, the flag had nothing to act on
and was accepted anyway, leaving the first query to fail on whichever
database turned out to be missing."""
@pytest.mark.asyncio
async def test_creating_a_set_is_refused(self, tmp_path):
config = _config(tmp_path, ["alpha", "beta"])
with pytest.raises(AmbiguousDatabaseError, match="alpha, beta"):
async with HaikuRAG(config=config, create=True):
pass
@pytest.mark.asyncio
async def test_naming_one_of_the_set_creates_it(self, tmp_path):
config = _config(tmp_path, ["alpha", "beta"])
async with HaikuRAG(config=config, create=True, sources=["alpha"]) as rag:
assert await rag.count_documents() == 0
assert (tmp_path / "alpha.lancedb").exists()
assert not (tmp_path / "beta.lancedb").exists()
@pytest.mark.asyncio
async def test_covering_a_set_without_creating_is_unaffected(self, tmp_path):
config = _config(tmp_path, ["alpha", "beta"])
await _seed(config, "alpha", ["alpha one"])
await _seed(config, "beta", ["beta one"])
async with HaikuRAG(config=config) as rag:
assert await rag.count_documents() == 2
class TestOperationsThatNeedOneDatabase:
@pytest.mark.asyncio
async def test_writing_names_the_databases_it_covers(self, tmp_path):