diff --git a/src/llm/search.py b/src/llm/search.py index cd8cc6a..7ffb76a 100644 --- a/src/llm/search.py +++ b/src/llm/search.py @@ -78,7 +78,13 @@ def _store_filter(filters: dict[str, str]) -> dict[str, Any]: } theme = str(filters.get("theme") or "") if theme: - out["$or"] = [{f"theme_{i}": theme} for i in range(1, 4)] + # langchain-postgres accepts either a mapping of field keys or a + # single operator at the top level, never both — so field + # conditions and the theme $or nest under one $and. + theme_or = {"$or": [{f"theme_{i}": theme} for i in range(1, 4)]} + if out: + return {"$and": [*({k: v} for k, v in out.items()), theme_or]} + return theme_or return out diff --git a/tests/llm/test_search.py b/tests/llm/test_search.py index 78a7a0b..d0d3b2d 100644 --- a/tests/llm/test_search.py +++ b/tests/llm/test_search.py @@ -393,10 +393,16 @@ class TestThemeFilter: assert _theme_ok({}, "") def test_theme_is_pushed_down_as_an_or_of_rank_keys(self): - out = _store_filter({"theme": "telehealth", "doctype": "manual"}) - assert out["doctype"] == "manual" - assert out["$or"] == [ - {"theme_1": "telehealth"}, - {"theme_2": "telehealth"}, - {"theme_3": "telehealth"}, - ] + theme_or = { + "$or": [ + {"theme_1": "telehealth"}, + {"theme_2": "telehealth"}, + {"theme_3": "telehealth"}, + ] + } + # field keys and an operator never share the top level (the store + # rejects that): fields and the theme $or nest under one $and + assert _store_filter({"theme": "telehealth", "doctype": "manual"}) == { + "$and": [{"doctype": "manual"}, theme_or] + } + assert _store_filter({"theme": "telehealth"}) == theme_or