diff --git a/cubedash/_stac.py b/cubedash/_stac.py index a82586bec..cad5cd493 100644 --- a/cubedash/_stac.py +++ b/cubedash/_stac.py @@ -840,6 +840,10 @@ def _stac_collection(collection: str) -> Collection: rel="items", target=url_for(".collection_items", collection=collection), ), + Link( + rel="http://www.opengis.net/def/rel/ogc/1.0/queryables", + target=url_for(".collection_queryables", collection=collection), + ), ] ) if all_time_summary.timeline_dataset_counts: @@ -935,6 +939,12 @@ def root(): media_type="application/json", target=url_for(".stac_search"), ), + Link( + title="Queryables", + rel="http://www.opengis.net/def/rel/ogc/1.0/queryables", + media_type="application/json", + target=url_for(".queryables"), + ), # Individual Product Collections *( Link( @@ -1016,6 +1026,90 @@ def collections(): ) +@bp.route("/queryables") +def queryables(): + """ + Define what terms are available for use when writing filter expressions for the entire catalog + Part of basic CQL2 conformance for stac-api filter implementation. + See: https://github.com/stac-api-extensions/filter#queryables + """ + return _utils.as_json( + { + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": flask.request.base_url, + "type": "object", + "title": "", + "properties": { + "id": { + "title": "Item ID", + "description": "Item identifier", + "$ref": "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/" + "item.json#/definitions/core/allOf/2/properties/id", + }, + "collection": { + "description": "Collection", + "$ref": "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/" + "item.json#/collection", + }, + "geometry": { + "description": "Geometry", + "$ref": "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/item.json#/geometry", + }, + "datetime": { + "description": "Datetime", + "$ref": "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/" + "datetime.json#/properties/datetime", + }, + }, + "additionalProperties": True, + } + ) + + +@bp.route("/collections//queryables") +def collection_queryables(collection: str): + """ + The queryables resources for a given collection (barebones implementation) + """ + try: + dataset_type = _model.STORE.get_dataset_type(collection) + except KeyError: + abort(404, f"Unknown collection {collection!r}") + + collection_title = dataset_type.definition.get("description") + return _utils.as_json( + { + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": flask.request.base_url, + "type": "object", + "title": f"Queryables for {collection_title}", + "properties": { + "id": { + "title": "Item ID", + "description": "Item identifier", + "$ref": "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/" + "item.json#/definitions/core/allOf/2/properties/id", + }, + "collection": { + "description": "Collection", + "$ref": "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/" + "item.json#/collection", + }, + "geometry": { + "description": "Geometry", + "$ref": "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/item.json#/geometry", + }, + "datetime": { + "description": "Datetime", + "$ref": "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/" + "datetime.json#/properties/datetime", + }, + }, + "additionalProperties": True, + } + ) + + @bp.route("/collections/") def collection(collection: str): """ diff --git a/integration_tests/test_stac.py b/integration_tests/test_stac.py index 2cc4f86a8..bd53cbcd8 100644 --- a/integration_tests/test_stac.py +++ b/integration_tests/test_stac.py @@ -525,12 +525,7 @@ def expect_404(url: str, message_contains: str = None): "/collections/ls7_nbar_scene/items" "?datetime=2000-01-01/2000-01-01&bbox=-48.206,-14.195,-45.067,-12.272", "/stac/collections/ls7_nbar_scene/items" - + ( - "?datetime=2000-01-01/2000-01-01&bbox=-48.206,-14.195,-45.067,-12.272" - # Flask will auto-escape parameters - # .replace(",", "%2C") - .replace("/", "%2F") - ), + "?datetime=2000-01-01/2000-01-01&bbox=-48.206,-14.195,-45.067,-12.272", ), ( "/collections/ls7_nbar_scene/items/0c5b625e-5432-4911-9f7d-f6b894e27f3c", @@ -587,6 +582,12 @@ def test_stac_links(stac_client: FlaskClient): "type": "application/json", "title": "Item Search", }, + { + "rel": "http://www.opengis.net/def/rel/ogc/1.0/queryables", + "href": "http://localhost/stac/queryables", + "type": "application/json", + "title": "Queryables", + }, ] # All expected products and their dataset counts. @@ -690,6 +691,10 @@ def test_stac_collection(stac_client: FlaskClient): "rel": "items", "href": stac_url("collections/high_tide_comp_20p/items"), }, + { + "rel": "http://www.opengis.net/def/rel/ogc/1.0/queryables", + "href": stac_url("collections/high_tide_comp_20p/queryables"), + }, { "rel": "child", "href": stac_url("catalogs/high_tide_comp_20p/2008-6"),