fix(qdrant): fix MatchText comment and validate logical operator inputs

Corrects the MatchText comment to accurately describe Qdrant behavior
(tokenized match with a full-text index; exact substring without one),
and adds ValueError validation when AND/OR/NOT filter values are not
lists, replacing unhelpful AttributeError crashes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
kartik-mem0
2026-03-21 18:07:07 +05:30
parent a930603c12
commit 72c2a7f322
2 changed files with 26 additions and 2 deletions
+11 -2
View File
@@ -187,8 +187,10 @@ class Qdrant(VectorStoreBase):
elif "nin" in value:
return FieldCondition(key=key, match=MatchExcept(**{"except": value["nin"]}))
elif "contains" in value or "icontains" in value:
# MatchText performs case-insensitive substring search on full-text indexed fields.
# Note: icontains behaves identically to contains for Qdrant keyword payloads.
# MatchText: with a full-text index, tokenized matching (all words must appear).
# Without a full-text index, exact substring match.
# Note: icontains maps to the same MatchText — case sensitivity depends on
# the full-text index tokenizer configuration, not on this operator name.
text = value.get("contains") or value.get("icontains")
return FieldCondition(key=key, match=MatchText(text=text))
else:
@@ -220,6 +222,13 @@ class Qdrant(VectorStoreBase):
must_not = []
for key, value in filters.items():
if key in ("AND", "OR", "NOT"):
if not isinstance(value, list):
raise ValueError(
f"{key} filter value must be a list of filter dicts, "
f"got {type(value).__name__}"
)
if key == "AND":
for sub in value:
built = self._create_filter(sub)
+15
View File
@@ -568,5 +568,20 @@ class TestQdrantEnhancedFilters(unittest.TestCase):
result = self.qdrant._create_filter({"category": "*"})
self.assertIsNone(result)
def test_and_with_non_list_raises_error(self):
"""AND with non-list value should raise ValueError."""
with self.assertRaises(ValueError):
self.qdrant._create_filter({"AND": "not_a_list"})
def test_or_with_non_list_raises_error(self):
"""OR with non-list value should raise ValueError."""
with self.assertRaises(ValueError):
self.qdrant._create_filter({"OR": {"category": "work"}})
def test_not_with_non_list_raises_error(self):
"""NOT with non-list value should raise ValueError."""
with self.assertRaises(ValueError):
self.qdrant._create_filter({"NOT": "invalid"})
def tearDown(self):
del self.qdrant