mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
fix: stabilize metadata filters on postgres (#536)
Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
@@ -84,8 +84,12 @@ def parse_metadata_filters(filters: dict[str, Any]) -> List[ParsedMetadataFilter
|
||||
continue
|
||||
|
||||
if op in {"$gt", "$gte", "$lt", "$lte"}:
|
||||
normalized = _normalize_scalar(value)
|
||||
comparison = "numeric" if _is_numeric_value(normalized) else "text"
|
||||
if _is_numeric_value(value):
|
||||
normalized = float(value)
|
||||
comparison = "numeric"
|
||||
else:
|
||||
normalized = _normalize_scalar(value)
|
||||
comparison = "text"
|
||||
parsed.append(
|
||||
ParsedMetadataFilter(path_parts, op.lstrip("$"), normalized, comparison)
|
||||
)
|
||||
@@ -94,8 +98,12 @@ def parse_metadata_filters(filters: dict[str, Any]) -> List[ParsedMetadataFilter
|
||||
if op == "$between":
|
||||
if not isinstance(value, list) or len(value) != 2:
|
||||
raise ValueError(f"$between requires [min, max] for '{raw_key}'")
|
||||
normalized = [_normalize_scalar(v) for v in value]
|
||||
comparison = "numeric" if _is_numeric_collection(normalized) else "text"
|
||||
if _is_numeric_collection(value):
|
||||
normalized = [float(v) for v in value]
|
||||
comparison = "numeric"
|
||||
else:
|
||||
normalized = [_normalize_scalar(v) for v in value]
|
||||
comparison = "text"
|
||||
parsed.append(ParsedMetadataFilter(path_parts, "between", normalized, comparison))
|
||||
continue
|
||||
|
||||
|
||||
@@ -332,7 +332,7 @@ class PostgresSearchRepository(SearchRepositoryBase):
|
||||
like_param_single = f"{base_param}_{j}_like_single"
|
||||
params[like_param_single] = f"%'{val}'%"
|
||||
tag_conditions.append(
|
||||
f"({json_expr} @> :{tag_param}::jsonb "
|
||||
f"({json_expr} @> CAST(:{tag_param} AS jsonb) "
|
||||
f"OR {text_expr} LIKE :{like_param} "
|
||||
f"OR {text_expr} LIKE :{like_param_single})"
|
||||
)
|
||||
@@ -340,14 +340,11 @@ class PostgresSearchRepository(SearchRepositoryBase):
|
||||
continue
|
||||
|
||||
if filt.op in {"gt", "gte", "lt", "lte", "between"}:
|
||||
if filt.comparison == "numeric":
|
||||
numeric_expr = (
|
||||
f"CASE WHEN ({text_expr}) ~ '^-?\\\\d+(\\\\.\\\\d+)?$' "
|
||||
f"THEN ({text_expr})::double precision END"
|
||||
)
|
||||
compare_expr = numeric_expr
|
||||
else:
|
||||
compare_expr = text_expr
|
||||
compare_expr = (
|
||||
f"({metadata_expr} #>> '{path}')::double precision"
|
||||
if filt.comparison == "numeric"
|
||||
else text_expr
|
||||
)
|
||||
|
||||
if filt.op == "between":
|
||||
min_param = f"meta_val_{idx}_min"
|
||||
|
||||
@@ -31,12 +31,12 @@ def test_parse_in_operator():
|
||||
|
||||
def test_parse_comparison_numeric():
|
||||
parsed = parse_metadata_filters({"schema.confidence": {"$gt": 0.7}})
|
||||
assert parsed == [ParsedMetadataFilter(["schema", "confidence"], "gt", "0.7", "numeric")]
|
||||
assert parsed == [ParsedMetadataFilter(["schema", "confidence"], "gt", 0.7, "numeric")]
|
||||
|
||||
|
||||
def test_parse_between_numeric():
|
||||
parsed = parse_metadata_filters({"score": {"$between": [0.3, 0.6]}})
|
||||
assert parsed == [ParsedMetadataFilter(["score"], "between", ["0.3", "0.6"], "numeric")]
|
||||
assert parsed == [ParsedMetadataFilter(["score"], "between", [0.3, 0.6], "numeric")]
|
||||
|
||||
|
||||
def test_parse_between_text():
|
||||
|
||||
Reference in New Issue
Block a user