Skip to content

Commit 4cb41f6

Browse files
committed
use minimum should match
1 parent a569587 commit 4cb41f6

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

stac_fastapi/sfeos_helpers/stac_fastapi/sfeos_helpers/filter/transform.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,20 @@ def to_es(queryables_mapping: Dict[str, Any], query: Dict[str, Any]) -> Dict[str
4141
LogicalOp.OR: "should",
4242
LogicalOp.NOT: "must_not",
4343
}[query["op"]]
44-
return {
44+
45+
# For OR conditions, we need to ensure at least one condition must match
46+
bool_query: Dict[str, Any] = {
4547
"bool": {
4648
bool_type: [
4749
to_es(queryables_mapping, sub_query) for sub_query in query["args"]
4850
]
4951
}
5052
}
53+
# Add minimum_should_match for OR conditions
54+
if query["op"] == LogicalOp.OR:
55+
bool_query["bool"]["minimum_should_match"] = 1
56+
57+
return bool_query
5158

5259
elif query["op"] in [
5360
ComparisonOp.EQ,

stac_fastapi/tests/extensions/test_filter.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,3 +674,57 @@ async def test_queryables_enum_platform(
674674
# Clean up
675675
r = await app_client.delete(f"/collections/{collection_id}")
676676
r.raise_for_status()
677+
678+
679+
@pytest.mark.asyncio
680+
async def test_search_filter_ext_or_condition(app_client, ctx):
681+
"""Test that OR conditions work correctly in filters."""
682+
# This test verifies that OR conditions work by checking for items that match
683+
# either of two conditions where only one should match the test item
684+
params = {
685+
"filter": {
686+
"op": "or",
687+
"args": [
688+
{
689+
"op": "<",
690+
"args": [
691+
{"property": "eo:cloud_cover"},
692+
0, # This condition should NOT match (cloud_cover is 0, not < 0)
693+
],
694+
},
695+
{
696+
"op": "=",
697+
"args": [
698+
{"property": "properties.proj:epsg"},
699+
32756, # This condition SHOULD match
700+
],
701+
},
702+
],
703+
}
704+
}
705+
706+
# First verify the test item matches exactly one of the conditions
707+
props = ctx.item.get("properties", {})
708+
matches = [
709+
props.get("eo:cloud_cover", 100) < 0, # Should be False
710+
props.get("proj:epsg") == 32756, # Should be True
711+
]
712+
assert sum(matches) == 1, "Test item should match exactly one condition"
713+
714+
# Now test the API
715+
resp = await app_client.post("/search", json=params)
716+
assert resp.status_code == 200
717+
resp_json = resp.json()
718+
719+
# Should find at least the test item
720+
assert len(resp_json["features"]) >= 1
721+
722+
# Verify at least one feature matches one of the conditions
723+
matched = False
724+
for feature in resp_json["features"]:
725+
props = feature.get("properties", {})
726+
if props.get("eo:cloud_cover", 100) < 0 or props.get("proj:epsg") == 32756:
727+
matched = True
728+
break
729+
730+
assert matched, "No features matched the OR condition"

0 commit comments

Comments
 (0)