1
- """Item crud client."""
1
+ """Core client."""
2
2
import logging
3
3
import re
4
4
from datetime import datetime as datetime_type
15
15
from pygeofilter .backends .cql2_json import to_cql2
16
16
from pygeofilter .parsers .cql2_text import parse as parse_cql2_text
17
17
from stac_pydantic .links import Relations
18
- from stac_pydantic .shared import MimeTypes
18
+ from stac_pydantic .shared import BBox , MimeTypes
19
19
from stac_pydantic .version import STAC_VERSION
20
20
21
21
from stac_fastapi .core .base_database_logic import BaseDatabaseLogic
38
38
from stac_fastapi .types .conformance import BASE_CONFORMANCE_CLASSES
39
39
from stac_fastapi .types .extension import ApiExtension
40
40
from stac_fastapi .types .requests import get_base_url
41
+ from stac_fastapi .types .rfc3339 import DateTimeType
41
42
from stac_fastapi .types .search import BaseSearchPostRequest
42
43
from stac_fastapi .types .stac import Collection , Collections , Item , ItemCollection
43
44
@@ -244,8 +245,8 @@ async def get_collection(self, collection_id: str, **kwargs) -> Collection:
244
245
async def item_collection (
245
246
self ,
246
247
collection_id : str ,
247
- bbox : Optional [List [ NumType ] ] = None ,
248
- datetime : Union [ str , datetime_type , None ] = None ,
248
+ bbox : Optional [BBox ] = None ,
249
+ datetime : Optional [ DateTimeType ] = None ,
249
250
limit : int = 10 ,
250
251
token : str = None ,
251
252
** kwargs ,
@@ -254,8 +255,8 @@ async def item_collection(
254
255
255
256
Args:
256
257
collection_id (str): The identifier of the collection to read items from.
257
- bbox (Optional[List[NumType] ]): The bounding box to filter items by.
258
- datetime (Union[str, datetime_type, None ]): The datetime range to filter items by.
258
+ bbox (Optional[BBox ]): The bounding box to filter items by.
259
+ datetime (Optional[DateTimeType ]): The datetime range to filter items by.
259
260
limit (int): The maximum number of items to return. The default value is 10.
260
261
token (str): A token used for pagination.
261
262
request (Request): The incoming request.
@@ -349,53 +350,64 @@ async def get_item(self, item_id: str, collection_id: str, **kwargs) -> Item:
349
350
return self .item_serializer .db_to_stac (item , base_url )
350
351
351
352
@staticmethod
352
- def _return_date (interval_str ):
353
+ def _return_date (
354
+ interval : Optional [Union [DateTimeType , str ]]
355
+ ) -> Dict [str , Optional [str ]]:
353
356
"""
354
- Convert a date interval string into a dictionary for filtering search results .
357
+ Convert a date interval.
355
358
356
- The date interval string should be formatted as either a single date or a range of dates separated
357
- by "/". The date format should be ISO-8601 (YYYY-MM-DDTHH:MM:SSZ). If the interval string is a
358
- single date, it will be converted to a dictionary with a single "eq" key whose value is the date in
359
- the ISO-8601 format. If the interval string is a range of dates, it will be converted to a
360
- dictionary with "gte" (greater than or equal to) and "lte" (less than or equal to) keys. If the
361
- interval string is a range of dates with ".." instead of "/", the start and end dates will be
362
- assigned default values to encompass the entire possible date range.
359
+ (which may be a datetime, a tuple of one or two datetimes a string
360
+ representing a datetime or range, or None) into a dictionary for filtering
361
+ search results with Elasticsearch.
362
+
363
+ This function ensures the output dictionary contains 'gte' and 'lte' keys,
364
+ even if they are set to None, to prevent KeyError in the consuming logic.
363
365
364
366
Args:
365
- interval_str (str): The date interval string to be converted.
367
+ interval (Optional[Union[DateTimeType, str]]): The date interval, which might be a single datetime,
368
+ a tuple with one or two datetimes, a string, or None.
366
369
367
370
Returns:
368
- dict: A dictionary representing the date interval for use in filtering search results.
371
+ dict: A dictionary representing the date interval for use in filtering search results,
372
+ always containing 'gte' and 'lte' keys.
369
373
"""
370
- intervals = interval_str .split ("/" )
371
- if len (intervals ) == 1 :
372
- datetime = f"{ intervals [0 ][0 :19 ]} Z"
373
- return {"eq" : datetime }
374
- else :
375
- start_date = intervals [0 ]
376
- end_date = intervals [1 ]
377
- if ".." not in intervals :
378
- start_date = f"{ start_date [0 :19 ]} Z"
379
- end_date = f"{ end_date [0 :19 ]} Z"
380
- elif start_date != ".." :
381
- start_date = f"{ start_date [0 :19 ]} Z"
382
- end_date = "2200-12-01T12:31:12Z"
383
- elif end_date != ".." :
384
- start_date = "1900-10-01T00:00:00Z"
385
- end_date = f"{ end_date [0 :19 ]} Z"
386
- else :
387
- start_date = "1900-10-01T00:00:00Z"
388
- end_date = "2200-12-01T12:31:12Z"
374
+ result : Dict [str , Optional [str ]] = {"gte" : None , "lte" : None }
389
375
390
- return {"lte" : end_date , "gte" : start_date }
376
+ if interval is None :
377
+ return result
378
+
379
+ if isinstance (interval , str ):
380
+ if "/" in interval :
381
+ parts = interval .split ("/" )
382
+ result ["gte" ] = parts [0 ] if parts [0 ] != ".." else None
383
+ result ["lte" ] = (
384
+ parts [1 ] if len (parts ) > 1 and parts [1 ] != ".." else None
385
+ )
386
+ else :
387
+ converted_time = interval if interval != ".." else None
388
+ result ["gte" ] = result ["lte" ] = converted_time
389
+ return result
390
+
391
+ if isinstance (interval , datetime_type ):
392
+ datetime_iso = interval .isoformat ()
393
+ result ["gte" ] = result ["lte" ] = datetime_iso
394
+ elif isinstance (interval , tuple ):
395
+ start , end = interval
396
+ # Ensure datetimes are converted to UTC and formatted with 'Z'
397
+ if start :
398
+ result ["gte" ] = start .strftime ("%Y-%m-%dT%H:%M:%S.%f" )[:- 3 ] + "Z"
399
+ if end :
400
+ result ["lte" ] = end .strftime ("%Y-%m-%dT%H:%M:%S.%f" )[:- 3 ] + "Z"
401
+
402
+ return result
391
403
392
404
async def get_search (
393
405
self ,
394
406
request : Request ,
395
407
collections : Optional [List [str ]] = None ,
396
408
ids : Optional [List [str ]] = None ,
397
- bbox : Optional [List [ NumType ] ] = None ,
398
- datetime : Optional [Union [ str , datetime_type ] ] = None ,
409
+ bbox : Optional [BBox ] = None ,
410
+ datetime : Optional [DateTimeType ] = None ,
399
411
limit : Optional [int ] = 10 ,
400
412
query : Optional [str ] = None ,
401
413
token : Optional [str ] = None ,
@@ -411,8 +423,8 @@ async def get_search(
411
423
Args:
412
424
collections (Optional[List[str]]): List of collection IDs to search in.
413
425
ids (Optional[List[str]]): List of item IDs to search for.
414
- bbox (Optional[List[NumType] ]): Bounding box to search in.
415
- datetime (Optional[Union[str, datetime_type] ]): Filter items based on the datetime field.
426
+ bbox (Optional[BBox ]): Bounding box to search in.
427
+ datetime (Optional[DateTimeType ]): Filter items based on the datetime field.
416
428
limit (Optional[int]): Maximum number of results to return.
417
429
query (Optional[str]): Query string to filter the results.
418
430
token (Optional[str]): Access token to use when searching the catalog.
@@ -459,7 +471,6 @@ async def get_search(
459
471
"direction" : "desc" if sort [0 ] == "-" else "asc" ,
460
472
}
461
473
)
462
- print (sort_param )
463
474
base_args ["sortby" ] = sort_param
464
475
465
476
if filter :
0 commit comments