fix: implement $not filter support in ChromaDB vector store (#5485)
This commit is contained in:
@@ -316,8 +316,32 @@ class ChromaDB(VectorStoreBase):
|
|||||||
processed_filters.append(or_conditions[0])
|
processed_filters.append(or_conditions[0])
|
||||||
|
|
||||||
elif key == "$not":
|
elif key == "$not":
|
||||||
# Handle NOT conditions - ChromaDB doesn't have direct NOT, so we'll skip for now
|
negate_op = {
|
||||||
continue
|
"eq": "$ne", "ne": "$eq",
|
||||||
|
"gt": "$lte", "gte": "$lt",
|
||||||
|
"lt": "$gte", "lte": "$gt",
|
||||||
|
"in": "$nin", "nin": "$in",
|
||||||
|
}
|
||||||
|
negated_per_group = []
|
||||||
|
for condition in value:
|
||||||
|
negated_fields = []
|
||||||
|
for sub_key, sub_value in condition.items():
|
||||||
|
if isinstance(sub_value, dict):
|
||||||
|
for op, val in sub_value.items():
|
||||||
|
neg = negate_op.get(op)
|
||||||
|
if neg:
|
||||||
|
negated_fields.append({sub_key: {neg: val}})
|
||||||
|
else:
|
||||||
|
negated_fields.append({sub_key: {"$ne": sub_value}})
|
||||||
|
if len(negated_fields) > 1:
|
||||||
|
negated_per_group.append({"$or": negated_fields})
|
||||||
|
elif len(negated_fields) == 1:
|
||||||
|
negated_per_group.append(negated_fields[0])
|
||||||
|
|
||||||
|
if len(negated_per_group) > 1:
|
||||||
|
processed_filters.append({"$and": negated_per_group})
|
||||||
|
elif len(negated_per_group) == 1:
|
||||||
|
processed_filters.append(negated_per_group[0])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Regular condition
|
# Regular condition
|
||||||
|
|||||||
@@ -252,6 +252,48 @@ def test_generate_where_clause_non_string_values():
|
|||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_where_clause_not_single_equality():
|
||||||
|
"""Test $not with a single equality condition."""
|
||||||
|
filters = {"$not": [{"status": "archived"}]}
|
||||||
|
result = ChromaDB._generate_where_clause(filters)
|
||||||
|
assert result == {"status": {"$ne": "archived"}}
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_where_clause_not_multiple_conditions():
|
||||||
|
"""Test $not with multiple conditions (OR semantics, negated to AND)."""
|
||||||
|
filters = {"$not": [{"status": "archived"}, {"type": "draft"}]}
|
||||||
|
result = ChromaDB._generate_where_clause(filters)
|
||||||
|
assert result == {"$and": [{"status": {"$ne": "archived"}}, {"type": {"$ne": "draft"}}]}
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_where_clause_not_with_operators():
|
||||||
|
"""Test $not negates comparison operators correctly."""
|
||||||
|
filters = {"$not": [{"count": {"gt": 5}}]}
|
||||||
|
result = ChromaDB._generate_where_clause(filters)
|
||||||
|
assert result == {"count": {"$lte": 5}}
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_where_clause_not_in_to_nin():
|
||||||
|
"""Test $not converts 'in' to $nin."""
|
||||||
|
filters = {"$not": [{"status": {"in": ["archived", "deleted"]}}]}
|
||||||
|
result = ChromaDB._generate_where_clause(filters)
|
||||||
|
assert result == {"status": {"$nin": ["archived", "deleted"]}}
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_where_clause_not_multi_field_condition():
|
||||||
|
"""Test $not with multi-field condition uses De Morgan's (AND -> OR)."""
|
||||||
|
filters = {"$not": [{"status": "archived", "type": "draft"}]}
|
||||||
|
result = ChromaDB._generate_where_clause(filters)
|
||||||
|
assert result == {"$or": [{"status": {"$ne": "archived"}}, {"type": {"$ne": "draft"}}]}
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_where_clause_not_combined_with_other_filters():
|
||||||
|
"""Test $not combined with regular filters."""
|
||||||
|
filters = {"user_id": "alice", "$not": [{"status": "archived"}]}
|
||||||
|
result = ChromaDB._generate_where_clause(filters)
|
||||||
|
assert result == {"$and": [{"user_id": {"$eq": "alice"}}, {"status": {"$ne": "archived"}}]}
|
||||||
|
|
||||||
|
|
||||||
def test_chroma_config_accepts_default_tmp_path():
|
def test_chroma_config_accepts_default_tmp_path():
|
||||||
"""Test that ChromaDbConfig accepts the default /tmp/chroma path."""
|
"""Test that ChromaDbConfig accepts the default /tmp/chroma path."""
|
||||||
config = ChromaDbConfig(path="/tmp/chroma")
|
config = ChromaDbConfig(path="/tmp/chroma")
|
||||||
|
|||||||
Reference in New Issue
Block a user