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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user