Skip to content

Commit fbdd993

Browse files
authored
Pgstac queryables (#474)
* add queryables * bump pgstac version * add tests for queryables * make id refer to current url * update content type, add changelog
1 parent 25879af commit fbdd993

File tree

8 files changed

+77
-5
lines changed

8 files changed

+77
-5
lines changed

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
### Added
66

7+
* Add support in pgstac backend for /queryables and /collections/{collection_id}/queryables endpoints with functions exposed in pgstac 0.6.8
8+
* Update pgstac requirement to 0.6.8
9+
710
### Changed
811

912
### Removed

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ services:
6363

6464
database:
6565
container_name: stac-db
66-
image: ghcr.io/stac-utils/pgstac:v0.6.6
66+
image: ghcr.io/stac-utils/pgstac:v0.6.8
6767
environment:
6868
- POSTGRES_USER=username
6969
- POSTGRES_PASSWORD=password

stac_fastapi/extensions/stac_fastapi/extensions/core/transaction.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
class PostItem(CollectionUri):
1919
"""Create Item."""
2020

21-
item: stac_types.Item = attr.ib(default=Body())
21+
item: stac_types.Item = attr.ib(default=Body(None))
2222

2323

2424
@attr.s
2525
class PutItem(ItemUri):
2626
"""Update Item."""
2727

28-
item: stac_types.Item = attr.ib(default=Body())
28+
item: stac_types.Item = attr.ib(default=Body(None))
2929

3030

3131
@attr.s

stac_fastapi/pgstac/stac_fastapi/pgstac/app.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from stac_fastapi.extensions.core import (
77
ContextExtension,
88
FieldsExtension,
9+
FilterExtension,
910
SortExtension,
1011
TokenPaginationExtension,
1112
TransactionExtension,
@@ -15,6 +16,7 @@
1516
from stac_fastapi.pgstac.core import CoreCrudClient
1617
from stac_fastapi.pgstac.db import close_db_connection, connect_to_db
1718
from stac_fastapi.pgstac.extensions import QueryExtension
19+
from stac_fastapi.pgstac.extensions.filter import FiltersClient
1820
from stac_fastapi.pgstac.transactions import BulkTransactionsClient, TransactionsClient
1921
from stac_fastapi.pgstac.types.search import PgstacSearch
2022

@@ -30,6 +32,7 @@
3032
FieldsExtension(),
3133
TokenPaginationExtension(),
3234
ContextExtension(),
35+
FilterExtension(client=FiltersClient()),
3336
BulkTransactionExtension(client=BulkTransactionsClient()),
3437
]
3538

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""pgstac extension customisations."""
22

3+
from .filter import FiltersClient
34
from .query import QueryExtension
45

5-
__all__ = ["QueryExtension"]
6+
__all__ = ["QueryExtension", "FiltersClient"]
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Get Queryables."""
2+
from typing import Any, Optional
3+
4+
from buildpg import render
5+
from fastapi import Request
6+
from fastapi.responses import JSONResponse
7+
8+
from stac_fastapi.types.core import AsyncBaseFiltersClient
9+
10+
11+
class FiltersClient(AsyncBaseFiltersClient):
12+
"""Defines a pattern for implementing the STAC filter extension."""
13+
14+
async def get_queryables(
15+
self, request: Request, collection_id: Optional[str] = None, **kwargs: Any
16+
) -> JSONResponse:
17+
"""Get the queryables available for the given collection_id.
18+
19+
If collection_id is None, returns the intersection of all
20+
queryables over all collections.
21+
This base implementation returns a blank queryable schema. This is not allowed
22+
under OGC CQL but it is allowed by the STAC API Filter Extension
23+
https://github.com/radiantearth/stac-api-spec/tree/master/fragments/filter#queryables
24+
"""
25+
pool = request.app.state.readpool
26+
27+
async with pool.acquire() as conn:
28+
q, p = render(
29+
"""
30+
SELECT * FROM get_queryables(:collection::text);
31+
""",
32+
collection=collection_id,
33+
)
34+
queryables = await conn.fetchval(q, *p)
35+
queryables["$id"] = str(request.url)
36+
headers = {"Content-Type": "application/schema+json"}
37+
return JSONResponse(queryables, headers=headers)

stac_fastapi/pgstac/tests/api/test_api.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,27 @@ async def test_search_duplicate_forward_headers(
391391
for feature in features:
392392
for link in feature["links"]:
393393
assert link["href"].startswith("https://test:1234/")
394+
395+
396+
@pytest.mark.asyncio
397+
async def test_base_queryables(load_test_data, app_client, load_test_collection):
398+
resp = await app_client.get("/queryables")
399+
assert resp.headers["Content-Type"] == "application/schema+json"
400+
q = resp.json()
401+
assert q["$id"].endswith("/queryables")
402+
assert q["type"] == "object"
403+
assert "properties" in q
404+
assert "id" in q["properties"]
405+
assert "eo:cloud_cover" in q["properties"]
406+
407+
408+
@pytest.mark.asyncio
409+
async def test_collection_queryables(load_test_data, app_client, load_test_collection):
410+
resp = await app_client.get("/collections/test-collection/queryables")
411+
assert resp.headers["Content-Type"] == "application/schema+json"
412+
q = resp.json()
413+
assert q["$id"].endswith("/collections/test-collection/queryables")
414+
assert q["type"] == "object"
415+
assert "properties" in q
416+
assert "id" in q["properties"]
417+
assert "eo:cloud_cover" in q["properties"]

stac_fastapi/pgstac/tests/conftest.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from stac_fastapi.api.app import StacApi
1818
from stac_fastapi.api.models import create_get_request_model, create_post_request_model
1919
from stac_fastapi.extensions.core import (
20+
ContextExtension,
2021
FieldsExtension,
2122
FilterExtension,
2223
SortExtension,
@@ -28,6 +29,7 @@
2829
from stac_fastapi.pgstac.core import CoreCrudClient
2930
from stac_fastapi.pgstac.db import close_db_connection, connect_to_db
3031
from stac_fastapi.pgstac.extensions import QueryExtension
32+
from stac_fastapi.pgstac.extensions.filter import FiltersClient
3133
from stac_fastapi.pgstac.transactions import BulkTransactionsClient, TransactionsClient
3234
from stac_fastapi.pgstac.types.search import PgstacSearch
3335

@@ -133,12 +135,14 @@ def api_client(request, pg):
133135
extensions = [
134136
TransactionExtension(client=TransactionsClient(), settings=settings),
135137
QueryExtension(),
136-
FilterExtension(),
137138
SortExtension(),
138139
FieldsExtension(),
139140
TokenPaginationExtension(),
141+
ContextExtension(),
142+
FilterExtension(client=FiltersClient()),
140143
BulkTransactionExtension(client=BulkTransactionsClient()),
141144
]
145+
142146
post_request_model = create_post_request_model(extensions, base_model=PgstacSearch)
143147
api = StacApi(
144148
settings=api_settings,

0 commit comments

Comments
 (0)