33import logging
44from datetime import datetime as datetime_type
55from datetime import timezone
6- from typing import List , Optional , Type , Union
6+ from typing import Any , Dict , List , Optional , Type , Union
77from urllib .parse import urljoin
88
99import attr
2121from stac_fastapi .elasticsearch .models .links import PagingLinks
2222from stac_fastapi .elasticsearch .serializers import CollectionSerializer , ItemSerializer
2323from stac_fastapi .elasticsearch .session import Session
24+ from stac_fastapi .extensions .core .filter .request import FilterLang
2425from stac_fastapi .extensions .third_party .bulk_transactions import (
2526 BaseBulkTransactionsClient ,
2627 Items ,
2728)
2829from stac_fastapi .types import stac as stac_types
29- from stac_fastapi .types .core import AsyncBaseCoreClient , AsyncBaseTransactionsClient
30+ from stac_fastapi .types .core import (
31+ AsyncBaseCoreClient ,
32+ AsyncBaseFiltersClient ,
33+ AsyncBaseTransactionsClient ,
34+ )
3035from stac_fastapi .types .links import CollectionLinks
3136from stac_fastapi .types .stac import Collection , Collections , Item , ItemCollection
3237
@@ -172,6 +177,8 @@ async def get_search(
172177 token : Optional [str ] = None ,
173178 fields : Optional [List [str ]] = None ,
174179 sortby : Optional [str ] = None ,
180+ # filter: Optional[str] = None, # todo: requires fastapi > 2.3 unreleased
181+ # filter_lang: Optional[str] = None, # todo: requires fastapi > 2.3 unreleased
175182 ** kwargs ,
176183 ) -> ItemCollection :
177184 """GET search catalog."""
@@ -183,8 +190,10 @@ async def get_search(
183190 "token" : token ,
184191 "query" : json .loads (query ) if query else query ,
185192 }
193+
186194 if datetime :
187195 base_args ["datetime" ] = datetime
196+
188197 if sortby :
189198 # https://github.com/radiantearth/stac-spec/tree/master/api-spec/extensions/sort#http-get-or-post-form
190199 sort_param = []
@@ -197,6 +206,13 @@ async def get_search(
197206 )
198207 base_args ["sortby" ] = sort_param
199208
209+ # todo: requires fastapi > 2.3 unreleased
210+ # if filter:
211+ # if filter_lang == "cql2-text":
212+ # base_args["filter-lang"] = "cql2-json"
213+ # base_args["filter"] = orjson.loads(to_cql2(parse_cql2_text(filter)))
214+ # print(f'>>> {base_args["filter"]}')
215+
200216 # if fields:
201217 # includes = set()
202218 # excludes = set()
@@ -264,6 +280,15 @@ async def post_search(
264280 search = search , op = op , field = field , value = value
265281 )
266282
283+ filter_lang = getattr (search_request , "filter_lang" , None )
284+
285+ if hasattr (search_request , "filter" ):
286+ cql2_filter = getattr (search_request , "filter" , None )
287+ if filter_lang in [None , FilterLang .cql2_json ]:
288+ search = self .database .apply_cql2_filter (search , cql2_filter )
289+ else :
290+ raise Exception ("CQL2-Text is not supported with POST" )
291+
267292 sort = None
268293 if search_request .sortby :
269294 sort = self .database .populate_sort (search_request .sortby )
@@ -455,3 +480,68 @@ def bulk_item_insert(
455480 )
456481
457482 return f"Successfully added { len (processed_items )} Items."
483+
484+
485+ @attr .s
486+ class EsAsyncBaseFiltersClient (AsyncBaseFiltersClient ):
487+ """Defines a pattern for implementing the STAC filter extension."""
488+
489+ # todo: use the ES _mapping endpoint to dynamically find what fields exist
490+ async def get_queryables (
491+ self , collection_id : Optional [str ] = None , ** kwargs
492+ ) -> Dict [str , Any ]:
493+ """Get the queryables available for the given collection_id.
494+
495+ If collection_id is None, returns the intersection of all
496+ queryables over all collections.
497+
498+ This base implementation returns a blank queryable schema. This is not allowed
499+ under OGC CQL but it is allowed by the STAC API Filter Extension
500+
501+ https://github.com/radiantearth/stac-api-spec/tree/master/fragments/filter#queryables
502+ """
503+ return {
504+ "$schema" : "https://json-schema.org/draft/2019-09/schema" ,
505+ "$id" : "https://stac-api.example.com/queryables" ,
506+ "type" : "object" ,
507+ "title" : "Queryables for Example STAC API" ,
508+ "description" : "Queryable names for the example STAC API Item Search filter." ,
509+ "properties" : {
510+ "id" : {
511+ "description" : "ID" ,
512+ "$ref" : "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/item.json#/id" ,
513+ },
514+ "collection" : {
515+ "description" : "Collection" ,
516+ "$ref" : "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/item.json#/collection" ,
517+ },
518+ "geometry" : {
519+ "description" : "Geometry" ,
520+ "$ref" : "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/item.json#/geometry" ,
521+ },
522+ "datetime" : {
523+ "description" : "Acquisition Timestamp" ,
524+ "$ref" : "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/datetime.json#/properties/datetime" ,
525+ },
526+ "created" : {
527+ "description" : "Creation Timestamp" ,
528+ "$ref" : "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/datetime.json#/properties/created" ,
529+ },
530+ "updated" : {
531+ "description" : "Creation Timestamp" ,
532+ "$ref" : "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/datetime.json#/properties/updated" ,
533+ },
534+ "cloud_cover" : {
535+ "description" : "Cloud Cover" ,
536+ "$ref" : "https://stac-extensions.github.io/eo/v1.0.0/schema.json#/definitions/fields/properties/eo:cloud_cover" ,
537+ },
538+ "cloud_shadow_percentage" : {
539+ "description" : "Cloud Shadow Percentage" ,
540+ "title" : "Cloud Shadow Percentage" ,
541+ "type" : "number" ,
542+ "minimum" : 0 ,
543+ "maximum" : 100 ,
544+ },
545+ },
546+ "additionalProperties" : True ,
547+ }
0 commit comments