fix: stabilize metadata filters on postgres (#536)

Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
Paul Hernandez
2026-01-31 22:31:00 -06:00
committed by GitHub
parent 8838571509
commit 009e84926d
3 changed files with 20 additions and 15 deletions
@@ -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"
+2 -2
View File
@@ -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():