Skip to content

Commit c39a85d

Browse files
committed
move return_date
1 parent 36504af commit c39a85d

File tree

7 files changed

+89
-122
lines changed

7 files changed

+89
-122
lines changed

stac_fastapi/core/stac_fastapi/core/core.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from stac_fastapi.core.base_database_logic import BaseDatabaseLogic
2323
from stac_fastapi.core.base_settings import ApiBaseSettings
24-
from stac_fastapi.core.datetime_utils import format_datetime_range, return_date
24+
from stac_fastapi.core.datetime_utils import format_datetime_range
2525
from stac_fastapi.core.models.links import PagingLinks
2626
from stac_fastapi.core.serializers import CollectionSerializer, ItemSerializer
2727
from stac_fastapi.core.session import Session
@@ -316,9 +316,8 @@ async def item_collection(
316316
)
317317

318318
if datetime:
319-
datetime_search = return_date(datetime)
320319
search = self.database.apply_datetime_filter(
321-
search=search, datetime_search=datetime_search
320+
search=search, interval=datetime
322321
)
323322

324323
if bbox:
@@ -493,9 +492,8 @@ async def post_search(
493492
)
494493

495494
if search_request.datetime:
496-
datetime_search = return_date(search_request.datetime)
497495
search = self.database.apply_datetime_filter(
498-
search=search, datetime_search=datetime_search
496+
search=search, interval=search_request.datetime
499497
)
500498

501499
if search_request.bbox:

stac_fastapi/core/stac_fastapi/core/datetime_utils.py

Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,7 @@
11
"""Utility functions to handle datetime parsing."""
2-
from datetime import datetime
3-
from datetime import datetime as datetime_type
4-
from datetime import timezone
5-
from typing import Dict, Optional, Union
2+
from datetime import datetime, timezone
63

7-
from stac_fastapi.types.rfc3339 import DateTimeType, rfc3339_str_to_datetime
8-
9-
10-
def return_date(
11-
interval: Optional[Union[DateTimeType, str]]
12-
) -> Dict[str, Optional[str]]:
13-
"""
14-
Convert a date interval.
15-
16-
(which may be a datetime, a tuple of one or two datetimes a string
17-
representing a datetime or range, or None) into a dictionary for filtering
18-
search results with Elasticsearch.
19-
20-
This function ensures the output dictionary contains 'gte' and 'lte' keys,
21-
even if they are set to None, to prevent KeyError in the consuming logic.
22-
23-
Args:
24-
interval (Optional[Union[DateTimeType, str]]): The date interval, which might be a single datetime,
25-
a tuple with one or two datetimes, a string, or None.
26-
27-
Returns:
28-
dict: A dictionary representing the date interval for use in filtering search results,
29-
always containing 'gte' and 'lte' keys.
30-
"""
31-
result: Dict[str, Optional[str]] = {"gte": None, "lte": None}
32-
33-
if interval is None:
34-
return result
35-
36-
if isinstance(interval, str):
37-
if "/" in interval:
38-
parts = interval.split("/")
39-
result["gte"] = parts[0] if parts[0] != ".." else None
40-
result["lte"] = parts[1] if len(parts) > 1 and parts[1] != ".." else None
41-
else:
42-
converted_time = interval if interval != ".." else None
43-
result["gte"] = result["lte"] = converted_time
44-
return result
45-
46-
if isinstance(interval, datetime_type):
47-
datetime_iso = interval.isoformat()
48-
result["gte"] = result["lte"] = datetime_iso
49-
elif isinstance(interval, tuple):
50-
start, end = interval
51-
# Ensure datetimes are converted to UTC and formatted with 'Z'
52-
if start:
53-
result["gte"] = start.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
54-
if end:
55-
result["lte"] = end.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
56-
57-
return result
4+
from stac_fastapi.types.rfc3339 import rfc3339_str_to_datetime
585

596

607
def format_datetime_range(date_str: str) -> str:

stac_fastapi/core/stac_fastapi/core/extensions/aggregation.py

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Request model for the Aggregation extension."""
22

33
from datetime import datetime
4-
from datetime import datetime as datetime_type
54
from typing import Dict, List, Literal, Optional, Union
65
from urllib.parse import unquote_plus, urljoin
76

@@ -210,58 +209,6 @@ def extract_date_histogram_interval(self, value: Optional[str]) -> str:
210209
else:
211210
return self.DEFAULT_DATETIME_INTERVAL
212211

213-
@staticmethod
214-
def _return_date(
215-
interval: Optional[Union[DateTimeType, str]]
216-
) -> Dict[str, Optional[str]]:
217-
"""
218-
Convert a date interval.
219-
220-
(which may be a datetime, a tuple of one or two datetimes a string
221-
representing a datetime or range, or None) into a dictionary for filtering
222-
search results with Elasticsearch.
223-
224-
This function ensures the output dictionary contains 'gte' and 'lte' keys,
225-
even if they are set to None, to prevent KeyError in the consuming logic.
226-
227-
Args:
228-
interval (Optional[Union[DateTimeType, str]]): The date interval, which might be a single datetime,
229-
a tuple with one or two datetimes, a string, or None.
230-
231-
Returns:
232-
dict: A dictionary representing the date interval for use in filtering search results,
233-
always containing 'gte' and 'lte' keys.
234-
"""
235-
result: Dict[str, Optional[str]] = {"gte": None, "lte": None}
236-
237-
if interval is None:
238-
return result
239-
240-
if isinstance(interval, str):
241-
if "/" in interval:
242-
parts = interval.split("/")
243-
result["gte"] = parts[0] if parts[0] != ".." else None
244-
result["lte"] = (
245-
parts[1] if len(parts) > 1 and parts[1] != ".." else None
246-
)
247-
else:
248-
converted_time = interval if interval != ".." else None
249-
result["gte"] = result["lte"] = converted_time
250-
return result
251-
252-
if isinstance(interval, datetime_type):
253-
datetime_iso = interval.isoformat()
254-
result["gte"] = result["lte"] = datetime_iso
255-
elif isinstance(interval, tuple):
256-
start, end = interval
257-
# Ensure datetimes are converted to UTC and formatted with 'Z'
258-
if start:
259-
result["gte"] = start.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
260-
if end:
261-
result["lte"] = end.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
262-
263-
return result
264-
265212
def frequency_agg(self, es_aggs, name, data_type):
266213
"""Format an aggregation for a frequency distribution aggregation."""
267214
buckets = []
@@ -418,9 +365,8 @@ async def aggregate(
418365
)
419366

420367
if aggregate_request.datetime:
421-
datetime_search = self._return_date(aggregate_request.datetime)
422368
search = self.database.apply_datetime_filter(
423-
search=search, datetime_search=datetime_search
369+
search=search, interval=aggregate_request.datetime
424370
)
425371

426372
if aggregate_request.bbox:

stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/database_logic.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import logging
66
from base64 import urlsafe_b64decode, urlsafe_b64encode
77
from copy import deepcopy
8-
from typing import Any, Dict, Iterable, List, Optional, Tuple, Type
8+
from typing import Any, Dict, Iterable, List, Optional, Tuple, Type, Union
99

1010
import attr
1111
import elasticsearch.helpers as helpers
@@ -33,6 +33,7 @@
3333
mk_actions,
3434
mk_item_id,
3535
populate_sort_shared,
36+
return_date,
3637
validate_refresh,
3738
)
3839
from stac_fastapi.sfeos_helpers.mappings import (
@@ -44,6 +45,7 @@
4445
Geometry,
4546
)
4647
from stac_fastapi.types.errors import ConflictError, NotFoundError
48+
from stac_fastapi.types.rfc3339 import DateTimeType
4749
from stac_fastapi.types.stac import Collection, Item
4850

4951
logger = logging.getLogger(__name__)
@@ -241,17 +243,20 @@ def apply_collections_filter(search: Search, collection_ids: List[str]):
241243
return search.filter("terms", collection=collection_ids)
242244

243245
@staticmethod
244-
def apply_datetime_filter(search: Search, datetime_search: dict):
246+
def apply_datetime_filter(
247+
search: Search, interval: Optional[Union[DateTimeType, str]]
248+
):
245249
"""Apply a filter to search on datetime, start_datetime, and end_datetime fields.
246250
247251
Args:
248252
search (Search): The search object to filter.
249-
datetime_search (dict): The datetime filter criteria.
253+
interval: Optional[Union[DateTimeType, str]]
250254
251255
Returns:
252256
Search: The filtered search object.
253257
"""
254258
should = []
259+
datetime_search = return_date(interval)
255260

256261
# If the request is a single datetime return
257262
# items with datetimes equal to the requested datetime OR

stac_fastapi/opensearch/stac_fastapi/opensearch/database_logic.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import logging
66
from base64 import urlsafe_b64decode, urlsafe_b64encode
77
from copy import deepcopy
8-
from typing import Any, Dict, Iterable, List, Optional, Tuple, Type
8+
from typing import Any, Dict, Iterable, List, Optional, Tuple, Type, Union
99

1010
import attr
1111
from opensearchpy import exceptions, helpers
@@ -33,6 +33,7 @@
3333
mk_actions,
3434
mk_item_id,
3535
populate_sort_shared,
36+
return_date,
3637
validate_refresh,
3738
)
3839
from stac_fastapi.sfeos_helpers.mappings import (
@@ -47,6 +48,7 @@
4748
Geometry,
4849
)
4950
from stac_fastapi.types.errors import ConflictError, NotFoundError
51+
from stac_fastapi.types.rfc3339 import DateTimeType
5052
from stac_fastapi.types.stac import Collection, Item
5153

5254
logger = logging.getLogger(__name__)
@@ -278,17 +280,20 @@ def apply_free_text_filter(search: Search, free_text_queries: Optional[List[str]
278280
)
279281

280282
@staticmethod
281-
def apply_datetime_filter(search: Search, datetime_search):
283+
def apply_datetime_filter(
284+
search: Search, interval: Optional[Union[DateTimeType, str]]
285+
):
282286
"""Apply a filter to search based on datetime field, start_datetime, and end_datetime fields.
283287
284288
Args:
285289
search (Search): The search object to filter.
286-
datetime_search (dict): The datetime filter criteria.
290+
interval: Optional[Union[DateTimeType, str]]
287291
288292
Returns:
289293
Search: The filtered search object.
290294
"""
291295
should = []
296+
datetime_search = return_date(interval)
292297

293298
# If the request is a single datetime return
294299
# items with datetimes equal to the requested datetime OR

stac_fastapi/sfeos_helpers/stac_fastapi/sfeos_helpers/database/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
3. Mapping functions for working with Elasticsearch/OpenSearch mappings
99
4. Document operations for working with documents
1010
5. Utility functions for database operations
11+
6. Datetime utilities for query formatting
1112
1213
The database package is organized as follows:
1314
- index.py: Index management functions
1415
- query.py: Query building functions
1516
- mapping.py: Mapping functions
1617
- document.py: Document operations
1718
- utils.py: Utility functions
19+
- datetime.py: Datetime utilities for query formatting
1820
1921
When adding new functionality to this package, consider:
2022
1. Will this code be used by both Elasticsearch and OpenSearch implementations?
@@ -28,6 +30,7 @@
2830
"""
2931

3032
# Re-export all functions for backward compatibility
33+
from .datetime import return_date
3134
from .document import mk_actions, mk_item_id
3235
from .index import (
3336
create_index_templates_shared,
@@ -42,7 +45,7 @@
4245
apply_intersects_filter_shared,
4346
populate_sort_shared,
4447
)
45-
from .utils import validate_refresh
48+
from .utils import get_bool_env, validate_refresh
4649

4750
__all__ = [
4851
# Index operations
@@ -62,4 +65,7 @@
6265
"mk_actions",
6366
# Utility functions
6467
"validate_refresh",
68+
"get_bool_env",
69+
# Datetime utilities
70+
"return_date",
6571
]
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""Elasticsearch/OpenSearch-specific datetime utilities.
2+
3+
This module provides datetime utility functions specifically designed for
4+
Elasticsearch and OpenSearch query formatting.
5+
"""
6+
7+
from datetime import datetime as datetime_type
8+
from typing import Dict, Optional, Union
9+
10+
from stac_fastapi.types.rfc3339 import DateTimeType
11+
12+
13+
def return_date(
14+
interval: Optional[Union[DateTimeType, str]]
15+
) -> Dict[str, Optional[str]]:
16+
"""
17+
Convert a date interval to an Elasticsearch/OpenSearch query format.
18+
19+
This function converts a date interval (which may be a datetime, a tuple of one or two datetimes,
20+
a string representing a datetime or range, or None) into a dictionary for filtering
21+
search results with Elasticsearch/OpenSearch.
22+
23+
This function ensures the output dictionary contains 'gte' and 'lte' keys,
24+
even if they are set to None, to prevent KeyError in the consuming logic.
25+
26+
Args:
27+
interval (Optional[Union[DateTimeType, str]]): The date interval, which might be a single datetime,
28+
a tuple with one or two datetimes, a string, or None.
29+
30+
Returns:
31+
dict: A dictionary representing the date interval for use in filtering search results,
32+
always containing 'gte' and 'lte' keys.
33+
"""
34+
result: Dict[str, Optional[str]] = {"gte": None, "lte": None}
35+
36+
if interval is None:
37+
return result
38+
39+
if isinstance(interval, str):
40+
if "/" in interval:
41+
parts = interval.split("/")
42+
result["gte"] = parts[0] if parts[0] != ".." else None
43+
result["lte"] = parts[1] if len(parts) > 1 and parts[1] != ".." else None
44+
else:
45+
converted_time = interval if interval != ".." else None
46+
result["gte"] = result["lte"] = converted_time
47+
return result
48+
49+
if isinstance(interval, datetime_type):
50+
datetime_iso = interval.isoformat()
51+
result["gte"] = result["lte"] = datetime_iso
52+
elif isinstance(interval, tuple):
53+
start, end = interval
54+
# Ensure datetimes are converted to UTC and formatted with 'Z'
55+
if start:
56+
result["gte"] = start.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
57+
if end:
58+
result["lte"] = end.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
59+
60+
return result

0 commit comments

Comments
 (0)