Skip to content

Commit c34cddb

Browse files
authored
feat: add filtering (#23)
* feat: add filtering * feat: better filtering
1 parent db3cd71 commit c34cddb

File tree

5 files changed

+66
-12
lines changed

5 files changed

+66
-12
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dependencies = [
1111
"obstore>=0.6.0",
1212
"pydantic>=2.10.4",
1313
"pystac>=1.13.0",
14-
"rustac==0.7.0b4",
14+
"rustac==0.7.0b5",
1515
"stac-fastapi-api>=5.0.2",
1616
"stac-fastapi-extensions>=5.0.2",
1717
"stac-fastapi-types>=5.0.2",

src/stac_fastapi/geoparquet/api.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import stac_fastapi.api.models
1313
from stac_fastapi.api.app import StacApi
14+
from stac_fastapi.extensions.core.filter import SearchFilterExtension
1415
from stac_fastapi.extensions.core.pagination import OffsetPaginationExtension
1516
from stac_fastapi.types.search import BaseSearchPostRequest
1617

@@ -23,12 +24,14 @@
2324
GetSearchRequestModel = stac_fastapi.api.models.create_request_model(
2425
model_name="SearchGetRequest",
2526
base_model=FixedSearchGetRequest,
27+
extensions=[SearchFilterExtension()],
2628
mixins=[OffsetPaginationExtension().GET],
2729
request_type="GET",
2830
)
2931
PostSearchRequestModel = stac_fastapi.api.models.create_request_model(
3032
model_name="SearchPostRequest",
3133
base_model=BaseSearchPostRequest,
34+
extensions=[SearchFilterExtension()],
3235
mixins=[OffsetPaginationExtension().POST],
3336
request_type="POST",
3437
)

src/stac_fastapi/geoparquet/client.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,12 @@ def search(
164164
else:
165165
collections = list(hrefs.keys())
166166

167-
search_dict = search.model_dump(exclude_none=True)
167+
search_dict = search.model_dump(exclude_none=True, by_alias=True)
168+
kwargs.pop("filter_crs", None)
169+
if filter_expr := kwargs.pop("filter_expr", None):
170+
kwargs["filter"] = filter_expr
171+
if "filter" not in kwargs:
172+
kwargs.pop("filter_lang", None)
168173
search_dict.update(**kwargs)
169174

170175
limit = search_dict.get("limit", DEFAULT_LIMIT)

tests/test_search.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,49 @@ def test_multiple_collections(client: TestClient) -> None:
8282
(link for link in data["links"] if link["rel"] == "next"), None
8383
)
8484
assert len(items) == 20
85+
86+
87+
def test_filter(client: TestClient) -> None:
88+
params = {"limit": 1, "filter": "naip:year='notayear'"}
89+
response = client.get("/search", params=params)
90+
response.raise_for_status()
91+
assert not response.json()["features"]
92+
93+
94+
def test_filter_post(client: TestClient) -> None:
95+
params = {
96+
"limit": 1,
97+
"filter": {"op": "=", "args": [{"property": "naip:year"}, "2022"]},
98+
}
99+
response = client.post("/search", json=params)
100+
response.raise_for_status()
101+
assert len(response.json()["features"]) == 1
102+
103+
params = {
104+
"limit": 1,
105+
"filter": {"op": "=", "args": [{"property": "naip:year"}, "notayear"]},
106+
}
107+
response = client.post("/search", json=params)
108+
response.raise_for_status()
109+
assert len(response.json()["features"]) == 0
110+
111+
112+
def test_paging_filter(client: TestClient) -> None:
113+
params = {"limit": 1, "filter": "naip:year='2022'"}
114+
response = client.get("/search", params=params)
115+
assert response.status_code == 200
116+
assert response.json()["features"][0]["id"] == "ne_m_4110264_sw_13_060_20220827"
117+
next_link = next(
118+
(link for link in response.json()["links"] if link["rel"] == "next")
119+
)
120+
url = urllib.parse.urlparse(next_link["href"])
121+
assert urllib.parse.parse_qs(url.query) == {
122+
"limit": ["1"],
123+
"offset": ["1"],
124+
"collections": ["naip,naip-10,openaerialmap-10,openaerialmap"],
125+
"filter": ["naip:year='2022'"],
126+
"filter_lang": ["cql2-text"],
127+
}
128+
response = client.get("/search", params=url.query)
129+
assert response.status_code == 200
130+
assert response.json()["features"][0]["id"] == "ne_m_4110263_sw_13_060_20220820"

uv.lock

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)