From 11c96574c0d98282550a76c101760b3dda06f621 Mon Sep 17 00:00:00 2001 From: jonhealy1 Date: Tue, 4 Nov 2025 12:18:10 +0800 Subject: [PATCH 1/3] fix cql2-text between --- stac_fastapi/core/stac_fastapi/core/core.py | 2 +- .../sfeos_helpers/filter/transform.py | 14 +++++++++++++- stac_fastapi/tests/extensions/test_filter.py | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/stac_fastapi/core/stac_fastapi/core/core.py b/stac_fastapi/core/stac_fastapi/core/core.py index 0c3beedc5..42106761a 100644 --- a/stac_fastapi/core/stac_fastapi/core/core.py +++ b/stac_fastapi/core/stac_fastapi/core/core.py @@ -830,7 +830,7 @@ async def post_search( search = await self.database.apply_cql2_filter(search, cql2_filter) except Exception as e: raise HTTPException( - status_code=400, detail=f"Error with cql2_json filter: {e}" + status_code=400, detail=f"Error with cql2 filter: {e}" ) if hasattr(search_request, "q"): diff --git a/stac_fastapi/sfeos_helpers/stac_fastapi/sfeos_helpers/filter/transform.py b/stac_fastapi/sfeos_helpers/stac_fastapi/sfeos_helpers/filter/transform.py index c78b19e59..6945a359e 100644 --- a/stac_fastapi/sfeos_helpers/stac_fastapi/sfeos_helpers/filter/transform.py +++ b/stac_fastapi/sfeos_helpers/stac_fastapi/sfeos_helpers/filter/transform.py @@ -92,7 +92,19 @@ def to_es(queryables_mapping: Dict[str, Any], query: Dict[str, Any]) -> Dict[str elif query["op"] == AdvancedComparisonOp.BETWEEN: field = to_es_field(queryables_mapping, query["args"][0]["property"]) - gte, lte = query["args"][1], query["args"][2] + + # Handle both formats: [property, [lower, upper]] or [property, lower, upper] + if len(query["args"]) == 2 and isinstance(query["args"][1], list): + # Format: [{'property': '...'}, [lower, upper]] + gte, lte = query["args"][1][0], query["args"][1][1] + elif len(query["args"]) == 3: + # Format: [{'property': '...'}, lower, upper] + gte, lte = query["args"][1], query["args"][2] + else: + raise ValueError( + f"BETWEEN operator expects 2 or 3 args, got {len(query['args'])}" + ) + if isinstance(gte, dict) and "timestamp" in gte: gte = gte["timestamp"] if isinstance(lte, dict) and "timestamp" in lte: diff --git a/stac_fastapi/tests/extensions/test_filter.py b/stac_fastapi/tests/extensions/test_filter.py index d60a13be1..e8402eb06 100644 --- a/stac_fastapi/tests/extensions/test_filter.py +++ b/stac_fastapi/tests/extensions/test_filter.py @@ -440,6 +440,24 @@ async def test_search_filter_extension_between(app_client, ctx): assert len(resp.json()["features"]) == 1 +@pytest.mark.asyncio +async def test_search_filter_extension_between_get(app_client, ctx): + """Test BETWEEN operator with GET request using CQL2-text format.""" + sun_elevation = ctx.item["properties"]["view:sun_elevation"] + lower_bound = sun_elevation - 0.01 + upper_bound = sun_elevation + 0.01 + + # Use CQL2-text format for GET request + filter_expr = f"properties.view:sun_elevation BETWEEN {lower_bound} AND {upper_bound} AND id = '{ctx.item['id']}'" + + resp = await app_client.get( + "/search", params={"filter": filter_expr, "filter_lang": "cql2-text"} + ) + + assert resp.status_code == 200 + assert len(resp.json()["features"]) == 1 + + @pytest.mark.asyncio async def test_search_filter_extension_isnull_post(app_client, ctx): # Test for a property that is not null From 5d469f7ebc567c00a2f6d2e7a8ce505bc7211a2b Mon Sep 17 00:00:00 2001 From: jonhealy1 Date: Tue, 4 Nov 2025 12:22:37 +0800 Subject: [PATCH 2/3] update test error message --- stac_fastapi/tests/extensions/test_filter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stac_fastapi/tests/extensions/test_filter.py b/stac_fastapi/tests/extensions/test_filter.py index e8402eb06..e597f285f 100644 --- a/stac_fastapi/tests/extensions/test_filter.py +++ b/stac_fastapi/tests/extensions/test_filter.py @@ -410,7 +410,7 @@ async def test_search_filter_extension_in_no_list(app_client, ctx): assert resp.status_code == 400 assert resp.json() == { - "detail": f"Error with cql2_json filter: Arg {product_id} is not a list" + "detail": f"Error with cql2 filter: Arg {product_id} is not a list" } From b0ae7fcf80121065e235e9d4156225dce9a1cd6c Mon Sep 17 00:00:00 2001 From: jonhealy1 Date: Tue, 4 Nov 2025 12:36:22 +0800 Subject: [PATCH 3/3] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28711b3b4..01f15d9ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +- Fixed "list index out of range" error when using BETWEEN operator in CQL2-text filters. [#521](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/521) + ### Removed ### Updated