stac-fastapi-opensearch 6.7.6__tar.gz → 6.8.0__tar.gz
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.
- {stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/PKG-INFO +6 -6
- {stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/README.md +1 -1
- {stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/pyproject.toml +4 -4
- {stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/stac_fastapi/opensearch/app.py +20 -1
- {stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/stac_fastapi/opensearch/config.py +1 -1
- {stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/stac_fastapi/opensearch/database_logic.py +243 -31
- {stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/stac_fastapi/opensearch/version.py +1 -1
- {stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/.gitignore +0 -0
- {stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/pytest.ini +0 -0
- {stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/stac_fastapi/opensearch/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stac_fastapi_opensearch
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.8.0
|
|
4
4
|
Summary: An implementation of STAC API based on the FastAPI framework with Opensearch.
|
|
5
5
|
Project-URL: Homepage, https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch
|
|
6
6
|
License: MIT
|
|
@@ -16,8 +16,8 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
16
16
|
Requires-Python: >=3.11
|
|
17
17
|
Requires-Dist: opensearch-py[async]~=2.8.0
|
|
18
18
|
Requires-Dist: opensearch-py~=2.8.0
|
|
19
|
-
Requires-Dist: sfeos-helpers==6.
|
|
20
|
-
Requires-Dist: stac-fastapi-core==6.
|
|
19
|
+
Requires-Dist: sfeos-helpers==6.8.0
|
|
20
|
+
Requires-Dist: stac-fastapi-core==6.8.0
|
|
21
21
|
Requires-Dist: starlette<0.36.0,>=0.35.0
|
|
22
22
|
Requires-Dist: uvicorn~=0.23.0
|
|
23
23
|
Provides-Extra: dev
|
|
@@ -29,13 +29,13 @@ Requires-Dist: pytest-cov~=4.0.0; extra == 'dev'
|
|
|
29
29
|
Requires-Dist: pytest~=8.0; extra == 'dev'
|
|
30
30
|
Requires-Dist: redis~=6.4.0; extra == 'dev'
|
|
31
31
|
Requires-Dist: retry~=0.9.2; extra == 'dev'
|
|
32
|
-
Requires-Dist: stac-fastapi-core[redis]==6.
|
|
32
|
+
Requires-Dist: stac-fastapi-core[redis]==6.8.0; extra == 'dev'
|
|
33
33
|
Provides-Extra: docs
|
|
34
34
|
Requires-Dist: mkdocs-material~=9.0.0; extra == 'docs'
|
|
35
35
|
Requires-Dist: mkdocs~=1.4.0; extra == 'docs'
|
|
36
36
|
Requires-Dist: pdocs~=1.2.0; extra == 'docs'
|
|
37
37
|
Provides-Extra: redis
|
|
38
|
-
Requires-Dist: stac-fastapi-core[redis]==6.
|
|
38
|
+
Requires-Dist: stac-fastapi-core[redis]==6.8.0; extra == 'redis'
|
|
39
39
|
Provides-Extra: server
|
|
40
40
|
Requires-Dist: uvicorn[standard]~=0.23.0; extra == 'server'
|
|
41
41
|
Description-Content-Type: text/markdown
|
|
@@ -52,7 +52,7 @@ Description-Content-Type: text/markdown
|
|
|
52
52
|
[](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/network/members)
|
|
53
53
|
[](https://pypi.org/project/stac-fastapi-elasticsearch/)
|
|
54
54
|
[](https://github.com/radiantearth/stac-spec/tree/v1.1.0)
|
|
55
|
-
[](https://github.com/stac-utils/stac-fastapi)
|
|
56
56
|
|
|
57
57
|
This is the OpenSearch backend for stac-fastapi. For full documentation, please see the [main README](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/blob/main/README.md).
|
|
58
58
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/network/members)
|
|
11
11
|
[](https://pypi.org/project/stac-fastapi-elasticsearch/)
|
|
12
12
|
[](https://github.com/radiantearth/stac-spec/tree/v1.1.0)
|
|
13
|
-
[](https://github.com/stac-utils/stac-fastapi)
|
|
14
14
|
|
|
15
15
|
This is the OpenSearch backend for stac-fastapi. For full documentation, please see the [main README](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/blob/main/README.md).
|
|
16
16
|
|
|
@@ -28,8 +28,8 @@ keywords = [
|
|
|
28
28
|
]
|
|
29
29
|
dynamic = ["version"]
|
|
30
30
|
dependencies = [
|
|
31
|
-
"stac-fastapi-core==6.
|
|
32
|
-
"sfeos-helpers==6.
|
|
31
|
+
"stac-fastapi-core==6.8.0",
|
|
32
|
+
"sfeos-helpers==6.8.0",
|
|
33
33
|
"opensearch-py~=2.8.0",
|
|
34
34
|
"opensearch-py[async]~=2.8.0",
|
|
35
35
|
"uvicorn~=0.23.0",
|
|
@@ -49,7 +49,7 @@ dev = [
|
|
|
49
49
|
"httpx>=0.24.0,<0.28.0",
|
|
50
50
|
"redis~=6.4.0",
|
|
51
51
|
"retry~=0.9.2",
|
|
52
|
-
"stac-fastapi-core[redis]==6.
|
|
52
|
+
"stac-fastapi-core[redis]==6.8.0",
|
|
53
53
|
]
|
|
54
54
|
docs = [
|
|
55
55
|
"mkdocs~=1.4.0",
|
|
@@ -57,7 +57,7 @@ docs = [
|
|
|
57
57
|
"pdocs~=1.2.0",
|
|
58
58
|
]
|
|
59
59
|
redis = [
|
|
60
|
-
"stac-fastapi-core[redis]==6.
|
|
60
|
+
"stac-fastapi-core[redis]==6.8.0",
|
|
61
61
|
]
|
|
62
62
|
server = [
|
|
63
63
|
"uvicorn[standard]~=0.23.0",
|
{stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/stac_fastapi/opensearch/app.py
RENAMED
|
@@ -23,6 +23,7 @@ from stac_fastapi.core.extensions.aggregation import (
|
|
|
23
23
|
EsAggregationExtensionGetRequest,
|
|
24
24
|
EsAggregationExtensionPostRequest,
|
|
25
25
|
)
|
|
26
|
+
from stac_fastapi.core.extensions.catalogs import CatalogsExtension
|
|
26
27
|
from stac_fastapi.core.extensions.collections_search import (
|
|
27
28
|
CollectionsSearchEndpointExtension,
|
|
28
29
|
)
|
|
@@ -65,11 +66,13 @@ ENABLE_COLLECTIONS_SEARCH = get_bool_env("ENABLE_COLLECTIONS_SEARCH", default=Tr
|
|
|
65
66
|
ENABLE_COLLECTIONS_SEARCH_ROUTE = get_bool_env(
|
|
66
67
|
"ENABLE_COLLECTIONS_SEARCH_ROUTE", default=False
|
|
67
68
|
)
|
|
69
|
+
ENABLE_CATALOGS_ROUTE = get_bool_env("ENABLE_CATALOGS_ROUTE", default=False)
|
|
68
70
|
logger.info("TRANSACTIONS_EXTENSIONS is set to %s", TRANSACTIONS_EXTENSIONS)
|
|
69
71
|
logger.info("ENABLE_COLLECTIONS_SEARCH is set to %s", ENABLE_COLLECTIONS_SEARCH)
|
|
70
72
|
logger.info(
|
|
71
73
|
"ENABLE_COLLECTIONS_SEARCH_ROUTE is set to %s", ENABLE_COLLECTIONS_SEARCH_ROUTE
|
|
72
74
|
)
|
|
75
|
+
logger.info("ENABLE_CATALOGS_ROUTE is set to %s", ENABLE_CATALOGS_ROUTE)
|
|
73
76
|
|
|
74
77
|
settings = OpensearchSettings()
|
|
75
78
|
session = Session.create_from_settings(settings)
|
|
@@ -201,6 +204,22 @@ if ENABLE_COLLECTIONS_SEARCH_ROUTE:
|
|
|
201
204
|
extensions.append(collections_search_endpoint_ext)
|
|
202
205
|
|
|
203
206
|
|
|
207
|
+
if ENABLE_CATALOGS_ROUTE:
|
|
208
|
+
catalogs_extension = CatalogsExtension(
|
|
209
|
+
client=CoreClient(
|
|
210
|
+
database=database_logic,
|
|
211
|
+
session=session,
|
|
212
|
+
post_request_model=collection_search_post_request_model,
|
|
213
|
+
landing_page_id=os.getenv("STAC_FASTAPI_LANDING_PAGE_ID", "stac-fastapi"),
|
|
214
|
+
),
|
|
215
|
+
settings=settings,
|
|
216
|
+
conformance_classes=[
|
|
217
|
+
"https://api.stacspec.org/v1.0.0-beta.1/catalogs-endpoint",
|
|
218
|
+
],
|
|
219
|
+
)
|
|
220
|
+
extensions.append(catalogs_extension)
|
|
221
|
+
|
|
222
|
+
|
|
204
223
|
database_logic.extensions = [type(ext).__name__ for ext in extensions]
|
|
205
224
|
|
|
206
225
|
post_request_model = create_post_request_model(search_extensions)
|
|
@@ -224,7 +243,7 @@ items_get_request_model = create_request_model(
|
|
|
224
243
|
app_config = {
|
|
225
244
|
"title": os.getenv("STAC_FASTAPI_TITLE", "stac-fastapi-opensearch"),
|
|
226
245
|
"description": os.getenv("STAC_FASTAPI_DESCRIPTION", "stac-fastapi-opensearch"),
|
|
227
|
-
"api_version": os.getenv("STAC_FASTAPI_VERSION", "6.
|
|
246
|
+
"api_version": os.getenv("STAC_FASTAPI_VERSION", "6.8.0"),
|
|
228
247
|
"settings": settings,
|
|
229
248
|
"extensions": extensions,
|
|
230
249
|
"client": CoreClient(
|
{stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/stac_fastapi/opensearch/config.py
RENAMED
|
@@ -56,7 +56,7 @@ def _es_config() -> Dict[str, Any]:
|
|
|
56
56
|
|
|
57
57
|
# Include timeout setting if set
|
|
58
58
|
if timeout := os.getenv("ES_TIMEOUT"):
|
|
59
|
-
config["timeout"] = timeout
|
|
59
|
+
config["timeout"] = int(timeout)
|
|
60
60
|
|
|
61
61
|
# Explicitly exclude SSL settings when not using SSL
|
|
62
62
|
if not use_ssl:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Database logic."""
|
|
2
|
-
|
|
3
2
|
import asyncio
|
|
4
3
|
import logging
|
|
4
|
+
import os
|
|
5
5
|
from base64 import urlsafe_b64decode, urlsafe_b64encode
|
|
6
6
|
from collections.abc import Iterable
|
|
7
7
|
from copy import deepcopy
|
|
@@ -15,6 +15,7 @@ from opensearchpy.helpers.query import Q
|
|
|
15
15
|
from opensearchpy.helpers.search import Search
|
|
16
16
|
from starlette.requests import Request
|
|
17
17
|
|
|
18
|
+
import stac_fastapi.sfeos_helpers.filter as filter_module
|
|
18
19
|
from stac_fastapi.core.base_database_logic import BaseDatabaseLogic
|
|
19
20
|
from stac_fastapi.core.serializers import CollectionSerializer, ItemSerializer
|
|
20
21
|
from stac_fastapi.core.utilities import MAX_LIMIT, bbox2polygon, get_bool_env
|
|
@@ -27,7 +28,6 @@ from stac_fastapi.opensearch.config import (
|
|
|
27
28
|
AsyncOpensearchSettings as AsyncSearchSettings,
|
|
28
29
|
)
|
|
29
30
|
from stac_fastapi.opensearch.config import OpensearchSettings as SyncSearchSettings
|
|
30
|
-
from stac_fastapi.sfeos_helpers import filter as filter_module
|
|
31
31
|
from stac_fastapi.sfeos_helpers.database import (
|
|
32
32
|
add_bbox_shape_to_collection,
|
|
33
33
|
apply_collections_bbox_filter_shared,
|
|
@@ -154,6 +154,26 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
154
154
|
|
|
155
155
|
aggregation_mapping: Dict[str, Dict[str, Any]] = AGGREGATION_MAPPING
|
|
156
156
|
|
|
157
|
+
# constants for field names
|
|
158
|
+
# they are used in multiple methods
|
|
159
|
+
# and could be overwritten in subclasses used with alternate opensearch mappings.
|
|
160
|
+
PROPERTIES_DATETIME_FIELD = os.getenv(
|
|
161
|
+
"STAC_FIELD_PROP_DATETIME", "properties.datetime"
|
|
162
|
+
)
|
|
163
|
+
PROPERTIES_START_DATETIME_FIELD = os.getenv(
|
|
164
|
+
"STAC_FIELD_PROP_START_DATETIME", "properties.start_datetime"
|
|
165
|
+
)
|
|
166
|
+
PROPERTIES_END_DATETIME_FIELD = os.getenv(
|
|
167
|
+
"STAC_FIELD_PROP_END_DATETIME", "properties.end_datetime"
|
|
168
|
+
)
|
|
169
|
+
COLLECTION_FIELD = os.getenv("STAC_FIELD_COLLECTION", "collection")
|
|
170
|
+
GEOMETRY_FIELD = os.getenv("STAC_FIELD_GEOMETRY", "geometry")
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def __nested_field__(field: str):
|
|
174
|
+
"""Convert opensearch field to nested field format."""
|
|
175
|
+
return field.replace(".", "__")
|
|
176
|
+
|
|
157
177
|
"""CORE LOGIC"""
|
|
158
178
|
|
|
159
179
|
async def get_all_collections(
|
|
@@ -436,7 +456,10 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
436
456
|
@staticmethod
|
|
437
457
|
def apply_collections_filter(search: Search, collection_ids: List[str]):
|
|
438
458
|
"""Database logic to search a list of STAC collection ids."""
|
|
439
|
-
|
|
459
|
+
collection_nested_field = DatabaseLogic.__nested_field__(
|
|
460
|
+
DatabaseLogic.COLLECTION_FIELD
|
|
461
|
+
)
|
|
462
|
+
return search.filter("terms", **{collection_nested_field: collection_ids})
|
|
440
463
|
|
|
441
464
|
@staticmethod
|
|
442
465
|
def apply_free_text_filter(search: Search, free_text_queries: Optional[List[str]]):
|
|
@@ -479,6 +502,16 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
479
502
|
# False: Always search only by start/end datetime
|
|
480
503
|
USE_DATETIME = get_bool_env("USE_DATETIME", default=True)
|
|
481
504
|
|
|
505
|
+
nested_datetime_field = DatabaseLogic.__nested_field__(
|
|
506
|
+
DatabaseLogic.PROPERTIES_DATETIME_FIELD
|
|
507
|
+
)
|
|
508
|
+
nested_start_datetime_field = DatabaseLogic.__nested_field__(
|
|
509
|
+
DatabaseLogic.PROPERTIES_START_DATETIME_FIELD
|
|
510
|
+
)
|
|
511
|
+
nested_end_datetime_field = DatabaseLogic.__nested_field__(
|
|
512
|
+
DatabaseLogic.PROPERTIES_END_DATETIME_FIELD
|
|
513
|
+
)
|
|
514
|
+
|
|
482
515
|
if USE_DATETIME:
|
|
483
516
|
if "eq" in datetime_search:
|
|
484
517
|
# For exact matches, include:
|
|
@@ -488,28 +521,42 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
488
521
|
Q(
|
|
489
522
|
"bool",
|
|
490
523
|
filter=[
|
|
491
|
-
Q("exists", field=
|
|
524
|
+
Q("exists", field=DatabaseLogic.PROPERTIES_DATETIME_FIELD),
|
|
492
525
|
Q(
|
|
493
526
|
"term",
|
|
494
|
-
**{
|
|
527
|
+
**{nested_datetime_field: datetime_search["eq"]},
|
|
495
528
|
),
|
|
496
529
|
],
|
|
497
530
|
),
|
|
498
531
|
Q(
|
|
499
532
|
"bool",
|
|
500
|
-
must_not=[
|
|
533
|
+
must_not=[
|
|
534
|
+
Q("exists", field=DatabaseLogic.PROPERTIES_DATETIME_FIELD)
|
|
535
|
+
],
|
|
501
536
|
filter=[
|
|
502
|
-
Q(
|
|
503
|
-
|
|
537
|
+
Q(
|
|
538
|
+
"exists",
|
|
539
|
+
field=DatabaseLogic.PROPERTIES_START_DATETIME_FIELD,
|
|
540
|
+
),
|
|
541
|
+
Q(
|
|
542
|
+
"exists",
|
|
543
|
+
field=DatabaseLogic.PROPERTIES_END_DATETIME_FIELD,
|
|
544
|
+
),
|
|
504
545
|
Q(
|
|
505
546
|
"range",
|
|
506
|
-
|
|
507
|
-
|
|
547
|
+
**{
|
|
548
|
+
nested_start_datetime_field: {
|
|
549
|
+
"lte": datetime_search["eq"]
|
|
550
|
+
}
|
|
508
551
|
},
|
|
509
552
|
),
|
|
510
553
|
Q(
|
|
511
554
|
"range",
|
|
512
|
-
|
|
555
|
+
**{
|
|
556
|
+
nested_end_datetime_field: {
|
|
557
|
+
"gte": datetime_search["eq"]
|
|
558
|
+
}
|
|
559
|
+
},
|
|
513
560
|
),
|
|
514
561
|
],
|
|
515
562
|
),
|
|
@@ -522,32 +569,46 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
522
569
|
Q(
|
|
523
570
|
"bool",
|
|
524
571
|
filter=[
|
|
525
|
-
Q("exists", field=
|
|
572
|
+
Q("exists", field=DatabaseLogic.PROPERTIES_DATETIME_FIELD),
|
|
526
573
|
Q(
|
|
527
574
|
"range",
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
575
|
+
**{
|
|
576
|
+
nested_datetime_field: {
|
|
577
|
+
"gte": datetime_search["gte"],
|
|
578
|
+
"lte": datetime_search["lte"],
|
|
579
|
+
}
|
|
531
580
|
},
|
|
532
581
|
),
|
|
533
582
|
],
|
|
534
583
|
),
|
|
535
584
|
Q(
|
|
536
585
|
"bool",
|
|
537
|
-
must_not=[
|
|
586
|
+
must_not=[
|
|
587
|
+
Q("exists", field=DatabaseLogic.PROPERTIES_DATETIME_FIELD)
|
|
588
|
+
],
|
|
538
589
|
filter=[
|
|
539
|
-
Q(
|
|
540
|
-
|
|
590
|
+
Q(
|
|
591
|
+
"exists",
|
|
592
|
+
field=DatabaseLogic.PROPERTIES_START_DATETIME_FIELD,
|
|
593
|
+
),
|
|
594
|
+
Q(
|
|
595
|
+
"exists",
|
|
596
|
+
field=DatabaseLogic.PROPERTIES_END_DATETIME_FIELD,
|
|
597
|
+
),
|
|
541
598
|
Q(
|
|
542
599
|
"range",
|
|
543
|
-
|
|
544
|
-
|
|
600
|
+
**{
|
|
601
|
+
nested_start_datetime_field: {
|
|
602
|
+
"lte": datetime_search["lte"]
|
|
603
|
+
}
|
|
545
604
|
},
|
|
546
605
|
),
|
|
547
606
|
Q(
|
|
548
607
|
"range",
|
|
549
|
-
|
|
550
|
-
|
|
608
|
+
**{
|
|
609
|
+
nested_end_datetime_field: {
|
|
610
|
+
"gte": datetime_search["gte"]
|
|
611
|
+
}
|
|
551
612
|
},
|
|
552
613
|
),
|
|
553
614
|
],
|
|
@@ -563,15 +624,26 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
563
624
|
filter_query = Q(
|
|
564
625
|
"bool",
|
|
565
626
|
filter=[
|
|
566
|
-
Q(
|
|
567
|
-
|
|
627
|
+
Q(
|
|
628
|
+
"exists",
|
|
629
|
+
field=DatabaseLogic.PROPERTIES_START_DATETIME_FIELD,
|
|
630
|
+
),
|
|
631
|
+
Q("exists", field=DatabaseLogic.PROPERTIES_END_DATETIME_FIELD),
|
|
568
632
|
Q(
|
|
569
633
|
"range",
|
|
570
|
-
|
|
634
|
+
**{
|
|
635
|
+
nested_start_datetime_field: {
|
|
636
|
+
"lte": datetime_search["eq"]
|
|
637
|
+
}
|
|
638
|
+
},
|
|
571
639
|
),
|
|
572
640
|
Q(
|
|
573
641
|
"range",
|
|
574
|
-
|
|
642
|
+
**{
|
|
643
|
+
nested_end_datetime_field: {
|
|
644
|
+
"gte": datetime_search["eq"]
|
|
645
|
+
}
|
|
646
|
+
},
|
|
575
647
|
),
|
|
576
648
|
],
|
|
577
649
|
)
|
|
@@ -579,15 +651,26 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
579
651
|
filter_query = Q(
|
|
580
652
|
"bool",
|
|
581
653
|
filter=[
|
|
582
|
-
Q(
|
|
583
|
-
|
|
654
|
+
Q(
|
|
655
|
+
"exists",
|
|
656
|
+
field=DatabaseLogic.PROPERTIES_START_DATETIME_FIELD,
|
|
657
|
+
),
|
|
658
|
+
Q("exists", field=DatabaseLogic.PROPERTIES_END_DATETIME_FIELD),
|
|
584
659
|
Q(
|
|
585
660
|
"range",
|
|
586
|
-
|
|
661
|
+
**{
|
|
662
|
+
nested_start_datetime_field: {
|
|
663
|
+
"lte": datetime_search["lte"]
|
|
664
|
+
}
|
|
665
|
+
},
|
|
587
666
|
),
|
|
588
667
|
Q(
|
|
589
668
|
"range",
|
|
590
|
-
|
|
669
|
+
**{
|
|
670
|
+
nested_end_datetime_field: {
|
|
671
|
+
"gte": datetime_search["gte"]
|
|
672
|
+
}
|
|
673
|
+
},
|
|
591
674
|
),
|
|
592
675
|
],
|
|
593
676
|
)
|
|
@@ -612,7 +695,7 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
612
695
|
Q(
|
|
613
696
|
{
|
|
614
697
|
"geo_shape": {
|
|
615
|
-
|
|
698
|
+
DatabaseLogic.GEOMETRY_FIELD: {
|
|
616
699
|
"shape": {
|
|
617
700
|
"type": "polygon",
|
|
618
701
|
"coordinates": bbox2polygon(*bbox),
|
|
@@ -1723,3 +1806,132 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1723
1806
|
body={"query": {"match_all": {}}},
|
|
1724
1807
|
wait_for_completion=True,
|
|
1725
1808
|
)
|
|
1809
|
+
|
|
1810
|
+
"""CATALOGS LOGIC"""
|
|
1811
|
+
|
|
1812
|
+
async def get_all_catalogs(
|
|
1813
|
+
self,
|
|
1814
|
+
token: Optional[str],
|
|
1815
|
+
limit: int,
|
|
1816
|
+
request: Any = None,
|
|
1817
|
+
sort: Optional[List[Dict[str, Any]]] = None,
|
|
1818
|
+
) -> Tuple[List[Dict[str, Any]], Optional[str], Optional[int]]:
|
|
1819
|
+
"""Retrieve a list of catalogs from OpenSearch, supporting pagination.
|
|
1820
|
+
|
|
1821
|
+
Args:
|
|
1822
|
+
token (Optional[str]): The pagination token.
|
|
1823
|
+
limit (int): The number of results to return.
|
|
1824
|
+
request (Any, optional): The FastAPI request object. Defaults to None.
|
|
1825
|
+
sort (Optional[List[Dict[str, Any]]], optional): Optional sort parameter. Defaults to None.
|
|
1826
|
+
|
|
1827
|
+
Returns:
|
|
1828
|
+
A tuple of (catalogs, next pagination token if any, optional count).
|
|
1829
|
+
"""
|
|
1830
|
+
# Define sortable fields for catalogs
|
|
1831
|
+
sortable_fields = ["id"]
|
|
1832
|
+
|
|
1833
|
+
# Format the sort parameter
|
|
1834
|
+
formatted_sort = []
|
|
1835
|
+
if sort:
|
|
1836
|
+
for item in sort:
|
|
1837
|
+
field = item.get("field")
|
|
1838
|
+
direction = item.get("direction", "asc")
|
|
1839
|
+
if field and field in sortable_fields:
|
|
1840
|
+
formatted_sort.append({field: {"order": direction}})
|
|
1841
|
+
|
|
1842
|
+
if not formatted_sort:
|
|
1843
|
+
formatted_sort = [{"id": {"order": "asc"}}]
|
|
1844
|
+
|
|
1845
|
+
body = {
|
|
1846
|
+
"sort": formatted_sort,
|
|
1847
|
+
"size": limit,
|
|
1848
|
+
"query": {"term": {"type": "Catalog"}},
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
# Handle search_after token
|
|
1852
|
+
search_after = None
|
|
1853
|
+
if token:
|
|
1854
|
+
try:
|
|
1855
|
+
search_after = token.split("|")
|
|
1856
|
+
if len(search_after) != len(formatted_sort):
|
|
1857
|
+
search_after = None
|
|
1858
|
+
except Exception:
|
|
1859
|
+
search_after = None
|
|
1860
|
+
|
|
1861
|
+
if search_after is not None:
|
|
1862
|
+
body["search_after"] = search_after
|
|
1863
|
+
|
|
1864
|
+
# Search for catalogs in collections index
|
|
1865
|
+
response = await self.client.search(
|
|
1866
|
+
index=COLLECTIONS_INDEX,
|
|
1867
|
+
body=body,
|
|
1868
|
+
)
|
|
1869
|
+
|
|
1870
|
+
hits = response["hits"]["hits"]
|
|
1871
|
+
catalogs = [hit["_source"] for hit in hits]
|
|
1872
|
+
|
|
1873
|
+
next_token = None
|
|
1874
|
+
if len(hits) == limit:
|
|
1875
|
+
next_token_values = hits[-1].get("sort")
|
|
1876
|
+
if next_token_values:
|
|
1877
|
+
next_token = "|".join(str(val) for val in next_token_values)
|
|
1878
|
+
|
|
1879
|
+
# Get the total count
|
|
1880
|
+
matched = (
|
|
1881
|
+
response["hits"]["total"]["value"]
|
|
1882
|
+
if response["hits"]["total"]["relation"] == "eq"
|
|
1883
|
+
else None
|
|
1884
|
+
)
|
|
1885
|
+
|
|
1886
|
+
return catalogs, next_token, matched
|
|
1887
|
+
|
|
1888
|
+
async def create_catalog(self, catalog: Dict, refresh: bool = False) -> None:
|
|
1889
|
+
"""Create a catalog in OpenSearch.
|
|
1890
|
+
|
|
1891
|
+
Args:
|
|
1892
|
+
catalog (Dict): The catalog document to create.
|
|
1893
|
+
refresh (bool): Whether to refresh the index after creation.
|
|
1894
|
+
"""
|
|
1895
|
+
await self.client.index(
|
|
1896
|
+
index=COLLECTIONS_INDEX,
|
|
1897
|
+
id=catalog.get("id"),
|
|
1898
|
+
body=catalog,
|
|
1899
|
+
refresh=refresh,
|
|
1900
|
+
)
|
|
1901
|
+
|
|
1902
|
+
async def find_catalog(self, catalog_id: str) -> Dict:
|
|
1903
|
+
"""Find a catalog in OpenSearch by ID.
|
|
1904
|
+
|
|
1905
|
+
Args:
|
|
1906
|
+
catalog_id (str): The ID of the catalog to find.
|
|
1907
|
+
|
|
1908
|
+
Returns:
|
|
1909
|
+
Dict: The catalog document.
|
|
1910
|
+
|
|
1911
|
+
Raises:
|
|
1912
|
+
NotFoundError: If the catalog is not found.
|
|
1913
|
+
"""
|
|
1914
|
+
try:
|
|
1915
|
+
response = await self.client.get(
|
|
1916
|
+
index=COLLECTIONS_INDEX,
|
|
1917
|
+
id=catalog_id,
|
|
1918
|
+
)
|
|
1919
|
+
# Verify it's a catalog
|
|
1920
|
+
if response["_source"].get("type") != "Catalog":
|
|
1921
|
+
raise NotFoundError(f"Catalog {catalog_id} not found")
|
|
1922
|
+
return response["_source"]
|
|
1923
|
+
except exceptions.NotFoundError:
|
|
1924
|
+
raise NotFoundError(f"Catalog {catalog_id} not found")
|
|
1925
|
+
|
|
1926
|
+
async def delete_catalog(self, catalog_id: str, refresh: bool = False) -> None:
|
|
1927
|
+
"""Delete a catalog from OpenSearch.
|
|
1928
|
+
|
|
1929
|
+
Args:
|
|
1930
|
+
catalog_id (str): The ID of the catalog to delete.
|
|
1931
|
+
refresh (bool): Whether to refresh the index after deletion.
|
|
1932
|
+
"""
|
|
1933
|
+
await self.client.delete(
|
|
1934
|
+
index=COLLECTIONS_INDEX,
|
|
1935
|
+
id=catalog_id,
|
|
1936
|
+
refresh=refresh,
|
|
1937
|
+
)
|
{stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/stac_fastapi/opensearch/version.py
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""library version."""
|
|
2
|
-
__version__ = "6.
|
|
2
|
+
__version__ = "6.8.0"
|
|
File without changes
|
|
File without changes
|
{stac_fastapi_opensearch-6.7.6 → stac_fastapi_opensearch-6.8.0}/stac_fastapi/opensearch/__init__.py
RENAMED
|
File without changes
|