Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions datamind/capabilities/kb/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,26 @@ def matches_metadata(metadata: dict[str, Any], where: dict[str, Any] | None) ->
continue
op, value = next(iter(expected.items()))
try:
ok = {
"$eq": actual == value,
"$ne": actual != value,
"$in": actual in value,
"$nin": actual not in value,
"$gt": actual > value,
"$gte": actual >= value,
"$lt": actual < value,
"$lte": actual <= value,
}[op]
# Dispatch before evaluating the operation. Building a mapping of
# boolean results evaluates every comparator, so an unrelated
# ordering or membership operation can turn a valid match into a
# false negative (for example, 42 == 42 also evaluates 42 in 42).
if op == "$eq":
ok = actual == value
elif op == "$ne":
ok = actual != value
elif op == "$in":
ok = actual in value
elif op == "$nin":
ok = actual not in value
elif op == "$gt":
ok = actual > value
elif op == "$gte":
ok = actual >= value
elif op == "$lt":
ok = actual < value
else:
ok = actual <= value
except (TypeError, KeyError):
ok = False
if not ok:
Expand Down
43 changes: 43 additions & 0 deletions datamind/tests/test_filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Metadata comparator dispatch tests."""
from __future__ import annotations

import pytest

from datamind.capabilities.kb.filters import matches_metadata


@pytest.mark.parametrize(
("actual", "operator", "expected", "matched"),
[
(42, "$eq", 42, True),
(42, "$eq", 41, False),
(42, "$ne", 41, True),
(42, "$ne", 42, False),
("a", "$in", ["a", "b"], True),
("c", "$in", ["a", "b"], False),
("c", "$nin", ["a", "b"], True),
("a", "$nin", ["a", "b"], False),
(42, "$gt", 40, True),
(42, "$gt", 42, False),
(42, "$gte", 42, True),
(42, "$gte", 43, False),
(40, "$lt", 42, True),
(42, "$lt", 42, False),
(42, "$lte", 42, True),
(43, "$lte", 42, False),
],
)
def test_matches_metadata_dispatches_only_the_requested_comparator(
actual, operator, expected, matched,
):
assert matches_metadata({"value": actual}, {"value": {operator: expected}}) is matched


def test_nested_boolean_filters_keep_comparator_dispatch_local():
assert matches_metadata(
{"age": 42, "tag": "a"},
{"$and": [
{"age": {"$gt": 40}},
{"tag": {"$in": ["a", "b"]}},
]},
)