Skip to content

Commit 009e849

Browse files
authored
fix: stabilize metadata filters on postgres (#536)
Signed-off-by: phernandez <paul@basicmachines.co>
1 parent 8838571 commit 009e849

3 files changed

Lines changed: 20 additions & 15 deletions

File tree

src/basic_memory/repository/metadata_filters.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,12 @@ def parse_metadata_filters(filters: dict[str, Any]) -> List[ParsedMetadataFilter
8484
continue
8585

8686
if op in {"$gt", "$gte", "$lt", "$lte"}:
87-
normalized = _normalize_scalar(value)
88-
comparison = "numeric" if _is_numeric_value(normalized) else "text"
87+
if _is_numeric_value(value):
88+
normalized = float(value)
89+
comparison = "numeric"
90+
else:
91+
normalized = _normalize_scalar(value)
92+
comparison = "text"
8993
parsed.append(
9094
ParsedMetadataFilter(path_parts, op.lstrip("$"), normalized, comparison)
9195
)
@@ -94,8 +98,12 @@ def parse_metadata_filters(filters: dict[str, Any]) -> List[ParsedMetadataFilter
9498
if op == "$between":
9599
if not isinstance(value, list) or len(value) != 2:
96100
raise ValueError(f"$between requires [min, max] for '{raw_key}'")
97-
normalized = [_normalize_scalar(v) for v in value]
98-
comparison = "numeric" if _is_numeric_collection(normalized) else "text"
101+
if _is_numeric_collection(value):
102+
normalized = [float(v) for v in value]
103+
comparison = "numeric"
104+
else:
105+
normalized = [_normalize_scalar(v) for v in value]
106+
comparison = "text"
99107
parsed.append(ParsedMetadataFilter(path_parts, "between", normalized, comparison))
100108
continue
101109

src/basic_memory/repository/postgres_search_repository.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -332,22 +332,19 @@ async def search(
332332
like_param_single = f"{base_param}_{j}_like_single"
333333
params[like_param_single] = f"%'{val}'%"
334334
tag_conditions.append(
335-
f"({json_expr} @> :{tag_param}::jsonb "
335+
f"({json_expr} @> CAST(:{tag_param} AS jsonb) "
336336
f"OR {text_expr} LIKE :{like_param} "
337337
f"OR {text_expr} LIKE :{like_param_single})"
338338
)
339339
conditions.append(" AND ".join(tag_conditions))
340340
continue
341341

342342
if filt.op in {"gt", "gte", "lt", "lte", "between"}:
343-
if filt.comparison == "numeric":
344-
numeric_expr = (
345-
f"CASE WHEN ({text_expr}) ~ '^-?\\\\d+(\\\\.\\\\d+)?$' "
346-
f"THEN ({text_expr})::double precision END"
347-
)
348-
compare_expr = numeric_expr
349-
else:
350-
compare_expr = text_expr
343+
compare_expr = (
344+
f"({metadata_expr} #>> '{path}')::double precision"
345+
if filt.comparison == "numeric"
346+
else text_expr
347+
)
351348

352349
if filt.op == "between":
353350
min_param = f"meta_val_{idx}_min"

tests/repository/test_metadata_filters.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ def test_parse_in_operator():
3131

3232
def test_parse_comparison_numeric():
3333
parsed = parse_metadata_filters({"schema.confidence": {"$gt": 0.7}})
34-
assert parsed == [ParsedMetadataFilter(["schema", "confidence"], "gt", "0.7", "numeric")]
34+
assert parsed == [ParsedMetadataFilter(["schema", "confidence"], "gt", 0.7, "numeric")]
3535

3636

3737
def test_parse_between_numeric():
3838
parsed = parse_metadata_filters({"score": {"$between": [0.3, 0.6]}})
39-
assert parsed == [ParsedMetadataFilter(["score"], "between", ["0.3", "0.6"], "numeric")]
39+
assert parsed == [ParsedMetadataFilter(["score"], "between", [0.3, 0.6], "numeric")]
4040

4141

4242
def test_parse_between_text():

0 commit comments

Comments
 (0)