Skip to content

Commit

Permalink
Enable search on /items and add queryables links (#89)
Browse files Browse the repository at this point in the history
* Enable search on /items and add queryables links

* add tests and remove unused

* fix

* more tests and update changelog

---------

Co-authored-by: vincentsarago <[email protected]>
  • Loading branch information
m-mohr and vincentsarago authored Aug 1, 2024
1 parent 7bfb9ce commit 1f36485
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 9 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [Unreleased]

- Enable filter extension for `GET /items` requests and add `Queryables` links in `/collections` and `/collections/{collection_id}` responses ([#89](https://github.com/stac-utils/stac-fastapi-pgstac/pull/89))

## [3.0.0a4] - 2024-07-10

- Update stac-fastapi libraries to `~=3.0.0b2`
Expand Down
39 changes: 31 additions & 8 deletions stac_fastapi/pgstac/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ async def all_collections(self, request: Request, **kwargs) -> Collections:
collection_id=coll["id"], request=request
).get_links(extra_links=coll.get("links"))

if self.extension_is_enabled("FilterExtension"):
coll["links"].append(
{
"rel": Relations.queryables.value,
"type": MimeTypes.jsonschema.value,
"title": "Queryables",
"href": urljoin(
base_url, f"collections/{coll['id']}/queryables"
),
}
)

linked_collections.append(coll)

links = [
Expand Down Expand Up @@ -109,6 +121,17 @@ async def get_collection(
collection_id=collection_id, request=request
).get_links(extra_links=collection.get("links"))

if self.extension_is_enabled("FilterExtension"):
base_url = get_base_url(request)
collection["links"].append(
{
"rel": Relations.queryables.value,
"type": MimeTypes.jsonschema.value,
"title": "Queryables",
"href": urljoin(base_url, f"collections/{collection_id}/queryables"),
}
)

return Collection(**collection)

async def _get_base_item(
Expand Down Expand Up @@ -285,6 +308,14 @@ async def item_collection(
"token": token,
}

if self.extension_is_enabled("FilterExtension"):
filter_lang = kwargs.get("filter_lang", None)
filter = kwargs.get("filter", None)
if filter is not None and filter_lang == "cql2-text":
ast = parse_cql2_text(filter.strip())
base_args["filter"] = orjson.loads(to_cql2(ast))
base_args["filter-lang"] = "cql2-json"

clean = {}
for k, v in base_args.items():
if v is not None and v != []:
Expand Down Expand Up @@ -377,14 +408,6 @@ async def get_search( # noqa: C901
Returns:
ItemCollection containing items which match the search criteria.
"""
query_params = str(request.query_params)

# Kludgy fix because using factory does not allow alias for filter-lang
if filter_lang is None:
match = re.search(r"filter-lang=([a-z0-9-]+)", query_params, re.IGNORECASE)
if match:
filter_lang = match.group(1)

# Parse request parameters
base_args = {
"collections": collections,
Expand Down
10 changes: 10 additions & 0 deletions tests/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ async def test_get_search_content_type(app_client):
assert resp.headers["content-type"] == "application/geo+json"


async def test_landing_links(app_client):
"""test landing page links."""
landing = await app_client.get("/")
assert landing.status_code == 200, landing.text
assert "Queryables" in [link.get("title") for link in landing.json()["links"]]


async def test_get_queryables_content_type(app_client, load_test_collection):
resp = await app_client.get("queryables")
assert resp.headers["content-type"] == "application/schema+json"
Expand Down Expand Up @@ -743,6 +750,9 @@ async def test_no_extension(
async with AsyncClient(transport=ASGITransport(app=app)) as client:
landing = await client.get("http://test/")
assert landing.status_code == 200, landing.text
assert "Queryables" not in [
link.get("title") for link in landing.json()["links"]
]

collection = await client.get("http://test/collections/test-collection")
assert collection.status_code == 200, collection.text
Expand Down
5 changes: 4 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,10 @@ def api_client(request, database):
items_get_request_model = create_request_model(
model_name="ItemCollectionUri",
base_model=ItemCollectionUri,
mixins=[TokenPaginationExtension().GET],
mixins=[
TokenPaginationExtension().GET,
FilterExtension(client=FiltersClient()).GET,
],
request_type="GET",
)
search_get_request_model = create_get_request_model(extensions)
Expand Down
16 changes: 16 additions & 0 deletions tests/resources/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,19 @@ async def test_get_collections_forwarded_header(app_client, load_test_collection
)
for link in resp.json()["links"]:
assert link["href"].startswith("https://test:1234/")


@pytest.mark.asyncio
async def test_get_collections_queryables_links(app_client, load_test_collection):
resp = await app_client.get(
"/collections",
)
assert "Queryables" in [
link.get("title") for link in resp.json()["collections"][0]["links"]
]

collection_id = resp.json()["collections"][0]["id"]
resp = await app_client.get(
f"/collections/{collection_id}",
)
assert "Queryables" in [link.get("title") for link in resp.json()["links"]]
8 changes: 8 additions & 0 deletions tests/resources/test_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,14 @@ async def test_get_filter_cql2text(app_client, load_test_data, load_test_collect
resp_json = resp.json()
assert len(resp.json()["features"]) == 0

filter = f"proj:epsg={epsg}"
params = {"filter": filter, "filter-lang": "cql2-text"}
resp = await app_client.get(
f"/collections/{test_item['collection']}/items", params=params
)
resp_json = resp.json()
assert len(resp.json()["features"]) == 1


async def test_item_merge_raster_bands(
app_client, load_test2_item, load_test2_collection
Expand Down

0 comments on commit 1f36485

Please sign in to comment.