stac-fastapi-core 6.7.6__py3-none-any.whl → 6.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -138,3 +138,43 @@ class BaseDatabaseLogic(abc.ABC):
138
138
  ) -> None:
139
139
  """Delete a collection from the database."""
140
140
  pass
141
+
142
+ @abc.abstractmethod
143
+ async def get_queryables_mapping(self, collection_id: str = "*") -> Dict[str, Any]:
144
+ """Retrieve mapping of Queryables for search."""
145
+ pass
146
+
147
+ async def get_all_catalogs(
148
+ self,
149
+ token: Optional[str],
150
+ limit: int,
151
+ request: Any = None,
152
+ sort: Optional[List[Dict[str, Any]]] = None,
153
+ ) -> Tuple[List[Dict[str, Any]], Optional[str], Optional[int]]:
154
+ """Retrieve a list of catalogs from the database, supporting pagination.
155
+
156
+ Args:
157
+ token (Optional[str]): The pagination token.
158
+ limit (int): The number of results to return.
159
+ request (Any, optional): The FastAPI request object. Defaults to None.
160
+ sort (Optional[List[Dict[str, Any]]], optional): Optional sort parameter. Defaults to None.
161
+
162
+ Returns:
163
+ A tuple of (catalogs, next pagination token if any, optional count).
164
+ """
165
+ pass
166
+
167
+ @abc.abstractmethod
168
+ async def create_catalog(self, catalog: Dict, refresh: bool = False) -> None:
169
+ """Create a catalog in the database."""
170
+ pass
171
+
172
+ @abc.abstractmethod
173
+ async def find_catalog(self, catalog_id: str) -> Dict:
174
+ """Find a catalog in the database."""
175
+ pass
176
+
177
+ @abc.abstractmethod
178
+ async def delete_catalog(self, catalog_id: str, refresh: bool = False) -> None:
179
+ """Delete a catalog from the database."""
180
+ pass
stac_fastapi/core/core.py CHANGED
@@ -24,7 +24,15 @@ from stac_fastapi.core.base_database_logic import BaseDatabaseLogic
24
24
  from stac_fastapi.core.base_settings import ApiBaseSettings
25
25
  from stac_fastapi.core.datetime_utils import format_datetime_range
26
26
  from stac_fastapi.core.models.links import PagingLinks
27
- from stac_fastapi.core.serializers import CollectionSerializer, ItemSerializer
27
+ from stac_fastapi.core.queryables import (
28
+ QueryablesCache,
29
+ get_properties_from_cql2_filter,
30
+ )
31
+ from stac_fastapi.core.serializers import (
32
+ CatalogSerializer,
33
+ CollectionSerializer,
34
+ ItemSerializer,
35
+ )
28
36
  from stac_fastapi.core.session import Session
29
37
  from stac_fastapi.core.utilities import filter_fields, get_bool_env
30
38
  from stac_fastapi.extensions.core.transaction import AsyncBaseTransactionsClient
@@ -81,12 +89,28 @@ class CoreClient(AsyncBaseCoreClient):
81
89
  collection_serializer: Type[CollectionSerializer] = attr.ib(
82
90
  default=CollectionSerializer
83
91
  )
92
+ catalog_serializer: Type[CatalogSerializer] = attr.ib(default=CatalogSerializer)
84
93
  post_request_model = attr.ib(default=BaseSearchPostRequest)
85
94
  stac_version: str = attr.ib(default=STAC_VERSION)
86
95
  landing_page_id: str = attr.ib(default="stac-fastapi")
87
96
  title: str = attr.ib(default="stac-fastapi")
88
97
  description: str = attr.ib(default="stac-fastapi")
89
98
 
99
+ def __attrs_post_init__(self):
100
+ """Initialize the queryables cache."""
101
+ self.queryables_cache = QueryablesCache(self.database)
102
+
103
+ def extension_is_enabled(self, extension_name: str) -> bool:
104
+ """Check if an extension is enabled by checking self.extensions.
105
+
106
+ Args:
107
+ extension_name: Name of the extension class to check for.
108
+
109
+ Returns:
110
+ True if the extension is in self.extensions, False otherwise.
111
+ """
112
+ return any(ext.__class__.__name__ == extension_name for ext in self.extensions)
113
+
90
114
  def _landing_page(
91
115
  self,
92
116
  base_url: str,
@@ -150,6 +174,7 @@ class CoreClient(AsyncBaseCoreClient):
150
174
  API landing page, serving as an entry point to the API.
151
175
  """
152
176
  request: Request = kwargs["request"]
177
+
153
178
  base_url = get_base_url(request)
154
179
  landing_page = self._landing_page(
155
180
  base_url=base_url,
@@ -207,6 +232,16 @@ class CoreClient(AsyncBaseCoreClient):
207
232
  ]
208
233
  )
209
234
 
235
+ if self.extension_is_enabled("CatalogsExtension"):
236
+ landing_page["links"].append(
237
+ {
238
+ "rel": "catalogs",
239
+ "type": "application/json",
240
+ "title": "Catalogs",
241
+ "href": urljoin(base_url, "catalogs"),
242
+ }
243
+ )
244
+
210
245
  # Add OpenAPI URL
211
246
  landing_page["links"].append(
212
247
  {
@@ -759,7 +794,7 @@ class CoreClient(AsyncBaseCoreClient):
759
794
 
760
795
  body_limit = None
761
796
  try:
762
- if request.method == "POST" and request.body():
797
+ if request.method == "POST" and await request.body():
763
798
  body_data = await request.json()
764
799
  body_limit = body_data.get("limit")
765
800
  except Exception:
@@ -817,6 +852,8 @@ class CoreClient(AsyncBaseCoreClient):
817
852
  )
818
853
 
819
854
  if hasattr(search_request, "query") and getattr(search_request, "query"):
855
+ query_fields = set(getattr(search_request, "query").keys())
856
+ await self.queryables_cache.validate(query_fields)
820
857
  for field_name, expr in getattr(search_request, "query").items():
821
858
  field = "properties__" + field_name
822
859
  for op, value in expr.items():
@@ -835,7 +872,11 @@ class CoreClient(AsyncBaseCoreClient):
835
872
 
836
873
  if cql2_filter is not None:
837
874
  try:
875
+ query_fields = get_properties_from_cql2_filter(cql2_filter)
876
+ await self.queryables_cache.validate(query_fields)
838
877
  search = await self.database.apply_cql2_filter(search, cql2_filter)
878
+ except HTTPException:
879
+ raise
839
880
  except Exception as e:
840
881
  raise HTTPException(
841
882
  status_code=400, detail=f"Error with cql2 filter: {e}"
@@ -1,5 +1,6 @@
1
1
  """elasticsearch extensions modifications."""
2
2
 
3
+ from .catalogs import CatalogsExtension
3
4
  from .collections_search import CollectionsSearchEndpointExtension
4
5
  from .query import Operator, QueryableTypes, QueryExtension
5
6
 
@@ -8,4 +9,5 @@ __all__ = [
8
9
  "QueryableTypes",
9
10
  "QueryExtension",
10
11
  "CollectionsSearchEndpointExtension",
12
+ "CatalogsExtension",
11
13
  ]