diff --git a/CHANGELOG.md b/CHANGELOG.md index 8602fba5..8f392131 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Added + +- Added support for Collections search + ### Changed - updated `numReturned` & `numMatched` fields in itemCollection return to `numberReturned` & `numberMatched`. [#446](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/446) diff --git a/stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/app.py b/stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/app.py index 6e046044..248d2c1f 100644 --- a/stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/app.py +++ b/stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/app.py @@ -37,6 +37,7 @@ from stac_fastapi.extensions.core import ( AggregationExtension, CollectionSearchExtension, + CollectionSearchFilterExtension, FilterExtension, FreeTextExtension, SortExtension, @@ -45,6 +46,7 @@ ) from stac_fastapi.extensions.core.fields import FieldsConformanceClasses from stac_fastapi.extensions.core.filter import FilterConformanceClasses +from stac_fastapi.extensions.core.free_text import FreeTextConformanceClasses from stac_fastapi.extensions.core.query import QueryConformanceClasses from stac_fastapi.extensions.core.sort import SortConformanceClasses from stac_fastapi.extensions.third_party import BulkTransactionExtension @@ -86,6 +88,7 @@ aggregation_extension.POST = EsAggregationExtensionPostRequest aggregation_extension.GET = EsAggregationExtensionGetRequest +# Base search extensions (without CollectionSearchExtension to avoid duplicates) fields_extension = FieldsExtension() fields_extension.conformance_classes.append(FieldsConformanceClasses.ITEMS) @@ -120,8 +123,29 @@ ), ) +# Initialize extensions with just the search and aggregation extensions +# Initialize with base extensions extensions = [aggregation_extension] + search_extensions +# Create collection search extensions +collection_search_extensions = [ + QueryExtension(conformance_classes=[QueryConformanceClasses.COLLECTIONS]), + SortExtension(conformance_classes=[SortConformanceClasses.COLLECTIONS]), + FieldsExtension(conformance_classes=[FieldsConformanceClasses.COLLECTIONS]), + CollectionSearchFilterExtension( + conformance_classes=[FilterConformanceClasses.COLLECTIONS] + ), + FreeTextExtension(conformance_classes=[FreeTextConformanceClasses.COLLECTIONS]), +] + +# Initialize collection search with its extensions +collection_search_ext = CollectionSearchExtension.from_extensions( + collection_search_extensions +) +collections_get_request_model = collection_search_ext.GET + +extensions.append(collection_search_ext) + database_logic.extensions = [type(ext).__name__ for ext in extensions] post_request_model = create_post_request_model(search_extensions) diff --git a/stac_fastapi/opensearch/stac_fastapi/opensearch/app.py b/stac_fastapi/opensearch/stac_fastapi/opensearch/app.py index 7ded95c9..15d21943 100644 --- a/stac_fastapi/opensearch/stac_fastapi/opensearch/app.py +++ b/stac_fastapi/opensearch/stac_fastapi/opensearch/app.py @@ -31,6 +31,7 @@ from stac_fastapi.extensions.core import ( AggregationExtension, CollectionSearchExtension, + CollectionSearchFilterExtension, FilterExtension, FreeTextExtension, SortExtension, @@ -39,6 +40,7 @@ ) from stac_fastapi.extensions.core.fields import FieldsConformanceClasses from stac_fastapi.extensions.core.filter import FilterConformanceClasses +from stac_fastapi.extensions.core.free_text import FreeTextConformanceClasses from stac_fastapi.extensions.core.query import QueryConformanceClasses from stac_fastapi.extensions.core.sort import SortConformanceClasses from stac_fastapi.extensions.third_party import BulkTransactionExtension @@ -71,7 +73,6 @@ # Adding collection search extension for compatibility with stac-auth-proxy # (https://github.com/developmentseed/stac-auth-proxy) -# The extension is not fully implemented yet but is required for collection filtering support collection_search_extension = CollectionSearchExtension() collection_search_extension.conformance_classes.append( "https://api.stacspec.org/v1.0.0-rc.1/collection-search#filter" @@ -85,6 +86,7 @@ aggregation_extension.POST = EsAggregationExtensionPostRequest aggregation_extension.GET = EsAggregationExtensionGetRequest +# Base search extensions (without CollectionSearchExtension to avoid duplicates) fields_extension = FieldsExtension() fields_extension.conformance_classes.append(FieldsConformanceClasses.ITEMS) @@ -98,7 +100,6 @@ collection_search_extension, ] - if TRANSACTIONS_EXTENSIONS: search_extensions.insert( 0, @@ -120,8 +121,29 @@ ), ) +# Initialize extensions with just the search and aggregation extensions +# Initialize with base extensions extensions = [aggregation_extension] + search_extensions +# Create collection search extensions +collection_search_extensions = [ + QueryExtension(conformance_classes=[QueryConformanceClasses.COLLECTIONS]), + SortExtension(conformance_classes=[SortConformanceClasses.COLLECTIONS]), + FieldsExtension(conformance_classes=[FieldsConformanceClasses.COLLECTIONS]), + CollectionSearchFilterExtension( + conformance_classes=[FilterConformanceClasses.COLLECTIONS] + ), + FreeTextExtension(conformance_classes=[FreeTextConformanceClasses.COLLECTIONS]), +] + +# Initialize collection search with its extensions +collection_search_ext = CollectionSearchExtension.from_extensions( + collection_search_extensions +) +collections_get_request_model = collection_search_ext.GET + +extensions.append(collection_search_ext) + database_logic.extensions = [type(ext).__name__ for ext in extensions] post_request_model = create_post_request_model(search_extensions) diff --git a/stac_fastapi/sfeos_helpers/stac_fastapi/sfeos_helpers/mappings.py b/stac_fastapi/sfeos_helpers/stac_fastapi/sfeos_helpers/mappings.py index 17cdd1ea..a90a9c33 100644 --- a/stac_fastapi/sfeos_helpers/stac_fastapi/sfeos_helpers/mappings.py +++ b/stac_fastapi/sfeos_helpers/stac_fastapi/sfeos_helpers/mappings.py @@ -160,8 +160,17 @@ class Geometry(Protocol): # noqa "dynamic_templates": ES_MAPPINGS_DYNAMIC_TEMPLATES, "properties": { "id": {"type": "keyword"}, - "extent.spatial.bbox": {"type": "long"}, - "extent.temporal.interval": {"type": "date"}, + "bbox_shape": {"type": "geo_shape"}, # Only this is used for spatial queries + "extent": { + "properties": {"temporal": {"properties": {"interval": {"type": "date"}}}} + }, + "properties": { + "properties": { + "datetime": {"type": "date"}, + "start_datetime": {"type": "date"}, + "end_datetime": {"type": "date"}, + } + }, "providers": {"type": "object", "enabled": False}, "links": {"type": "object", "enabled": False}, "item_assets": {"type": "object", "enabled": get_bool_env("STAC_INDEX_ASSETS")},