stac-fastapi-opensearch 6.9.0__tar.gz → 6.10.1__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.9.0 → stac_fastapi_opensearch-6.10.1}/.gitignore +11 -0
- {stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/PKG-INFO +5 -5
- {stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/pyproject.toml +4 -4
- {stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/stac_fastapi/opensearch/app.py +2 -2
- {stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/stac_fastapi/opensearch/database_logic.py +136 -69
- {stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/stac_fastapi/opensearch/version.py +1 -1
- {stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/README.md +0 -0
- {stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/pytest.ini +0 -0
- {stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/stac_fastapi/opensearch/__init__.py +0 -0
- {stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/stac_fastapi/opensearch/config.py +0 -0
|
@@ -141,3 +141,14 @@ venv
|
|
|
141
141
|
/docs/src/api/*
|
|
142
142
|
|
|
143
143
|
.DS_Store
|
|
144
|
+
|
|
145
|
+
# Helm
|
|
146
|
+
*.tgz
|
|
147
|
+
charts/*/charts/
|
|
148
|
+
charts/*/requirements.lock
|
|
149
|
+
charts/*/Chart.lock
|
|
150
|
+
helm-chart/stac-fastapi/charts/
|
|
151
|
+
helm-chart/stac-fastapi/Chart.lock
|
|
152
|
+
helm-chart/stac-fastapi/*.tgz
|
|
153
|
+
helm-chart/test-results/
|
|
154
|
+
helm-chart/tmp/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stac_fastapi_opensearch
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.10.1
|
|
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.10.1
|
|
20
|
+
Requires-Dist: stac-fastapi-core==6.10.1
|
|
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.10.1; 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.10.1; 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
|
|
@@ -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.10.1",
|
|
32
|
+
"sfeos-helpers==6.10.1",
|
|
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.10.1",
|
|
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.10.1",
|
|
61
61
|
]
|
|
62
62
|
server = [
|
|
63
63
|
"uvicorn[standard]~=0.23.0",
|
{stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/stac_fastapi/opensearch/app.py
RENAMED
|
@@ -214,7 +214,7 @@ if ENABLE_CATALOGS_ROUTE:
|
|
|
214
214
|
),
|
|
215
215
|
settings=settings,
|
|
216
216
|
conformance_classes=[
|
|
217
|
-
"https://api.stacspec.org/v1.0.0-beta.1/catalogs
|
|
217
|
+
"https://api.stacspec.org/v1.0.0-beta.1/multi-tenant-catalogs",
|
|
218
218
|
],
|
|
219
219
|
)
|
|
220
220
|
extensions.append(catalogs_extension)
|
|
@@ -243,7 +243,7 @@ items_get_request_model = create_request_model(
|
|
|
243
243
|
app_config = {
|
|
244
244
|
"title": os.getenv("STAC_FASTAPI_TITLE", "stac-fastapi-opensearch"),
|
|
245
245
|
"description": os.getenv("STAC_FASTAPI_DESCRIPTION", "stac-fastapi-opensearch"),
|
|
246
|
-
"api_version": os.getenv("STAC_FASTAPI_VERSION", "6.
|
|
246
|
+
"api_version": os.getenv("STAC_FASTAPI_VERSION", "6.10.1"),
|
|
247
247
|
"settings": settings,
|
|
248
248
|
"extensions": extensions,
|
|
249
249
|
"client": CoreClient(
|
|
@@ -29,11 +29,14 @@ from stac_fastapi.opensearch.config import (
|
|
|
29
29
|
)
|
|
30
30
|
from stac_fastapi.opensearch.config import OpensearchSettings as SyncSearchSettings
|
|
31
31
|
from stac_fastapi.sfeos_helpers.database import (
|
|
32
|
+
ItemAlreadyExistsError,
|
|
32
33
|
add_bbox_shape_to_collection,
|
|
33
34
|
apply_collections_bbox_filter_shared,
|
|
34
35
|
apply_collections_datetime_filter_shared,
|
|
35
36
|
apply_free_text_filter_shared,
|
|
36
37
|
apply_intersects_filter_shared,
|
|
38
|
+
check_item_exists_in_alias,
|
|
39
|
+
check_item_exists_in_alias_sync,
|
|
37
40
|
create_index_templates_shared,
|
|
38
41
|
delete_item_index_shared,
|
|
39
42
|
get_queryables_mapping_shared,
|
|
@@ -49,6 +52,7 @@ from stac_fastapi.sfeos_helpers.database.query import (
|
|
|
49
52
|
add_collections_to_body,
|
|
50
53
|
)
|
|
51
54
|
from stac_fastapi.sfeos_helpers.database.utils import (
|
|
55
|
+
add_hidden_filter,
|
|
52
56
|
merge_to_operations,
|
|
53
57
|
operations_to_script,
|
|
54
58
|
)
|
|
@@ -64,6 +68,7 @@ from stac_fastapi.sfeos_helpers.mappings import (
|
|
|
64
68
|
from stac_fastapi.sfeos_helpers.search_engine import (
|
|
65
69
|
BaseIndexInserter,
|
|
66
70
|
BaseIndexSelector,
|
|
71
|
+
DatetimeIndexInserter,
|
|
67
72
|
IndexInsertionFactory,
|
|
68
73
|
IndexSelectorFactory,
|
|
69
74
|
)
|
|
@@ -406,12 +411,22 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
406
411
|
Notes:
|
|
407
412
|
The Item is retrieved from the Opensearch database using the `client.get` method,
|
|
408
413
|
with the index for the Collection as the target index and the combined `mk_item_id` as the document id.
|
|
414
|
+
Item is hidden if hide_item_path is configured via env var.
|
|
409
415
|
"""
|
|
410
416
|
try:
|
|
417
|
+
base_query = {"term": {"_id": mk_item_id(item_id, collection_id)}}
|
|
418
|
+
|
|
419
|
+
HIDE_ITEM_PATH = os.getenv("HIDE_ITEM_PATH", None)
|
|
420
|
+
|
|
421
|
+
if HIDE_ITEM_PATH:
|
|
422
|
+
query = add_hidden_filter(base_query, HIDE_ITEM_PATH)
|
|
423
|
+
else:
|
|
424
|
+
query = base_query
|
|
425
|
+
|
|
411
426
|
response = await self.client.search(
|
|
412
427
|
index=index_alias_by_collection_id(collection_id),
|
|
413
428
|
body={
|
|
414
|
-
"query":
|
|
429
|
+
"query": query,
|
|
415
430
|
"size": 1,
|
|
416
431
|
},
|
|
417
432
|
)
|
|
@@ -811,7 +826,7 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
811
826
|
token: Optional[str],
|
|
812
827
|
sort: Optional[Dict[str, Dict[str, str]]],
|
|
813
828
|
collection_ids: Optional[List[str]],
|
|
814
|
-
datetime_search:
|
|
829
|
+
datetime_search: str,
|
|
815
830
|
ignore_unavailable: bool = True,
|
|
816
831
|
) -> Tuple[Iterable[Dict[str, Any]], Optional[int], Optional[str]]:
|
|
817
832
|
"""Execute a search query with limit and other optional parameters.
|
|
@@ -822,7 +837,7 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
822
837
|
token (Optional[str]): The token used to return the next set of results.
|
|
823
838
|
sort (Optional[Dict[str, Dict[str, str]]]): Specifies how the results should be sorted.
|
|
824
839
|
collection_ids (Optional[List[str]]): The collection ids to search.
|
|
825
|
-
datetime_search (
|
|
840
|
+
datetime_search (str): Datetime used for index selection.
|
|
826
841
|
ignore_unavailable (bool, optional): Whether to ignore unavailable collections. Defaults to True.
|
|
827
842
|
|
|
828
843
|
Returns:
|
|
@@ -846,7 +861,11 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
846
861
|
index_param = ITEM_INDICES
|
|
847
862
|
query = add_collections_to_body(collection_ids, query)
|
|
848
863
|
|
|
849
|
-
|
|
864
|
+
HIDE_ITEM_PATH = os.getenv("HIDE_ITEM_PATH", None)
|
|
865
|
+
|
|
866
|
+
if HIDE_ITEM_PATH:
|
|
867
|
+
search_body["query"] = add_hidden_filter(query, HIDE_ITEM_PATH)
|
|
868
|
+
elif query:
|
|
850
869
|
search_body["query"] = query
|
|
851
870
|
|
|
852
871
|
search_after = None
|
|
@@ -871,11 +890,17 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
871
890
|
)
|
|
872
891
|
)
|
|
873
892
|
|
|
893
|
+
# Ensure hidden item is not counted
|
|
894
|
+
count_query = search.to_dict(count=True)
|
|
895
|
+
if HIDE_ITEM_PATH:
|
|
896
|
+
q = count_query.get("query")
|
|
897
|
+
count_query["query"] = add_hidden_filter(q, HIDE_ITEM_PATH)
|
|
898
|
+
|
|
874
899
|
count_task = asyncio.create_task(
|
|
875
900
|
self.client.count(
|
|
876
901
|
index=index_param,
|
|
877
902
|
ignore_unavailable=ignore_unavailable,
|
|
878
|
-
body=
|
|
903
|
+
body=count_query,
|
|
879
904
|
)
|
|
880
905
|
)
|
|
881
906
|
|
|
@@ -918,7 +943,7 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
918
943
|
geometry_geohash_grid_precision: int,
|
|
919
944
|
geometry_geotile_grid_precision: int,
|
|
920
945
|
datetime_frequency_interval: str,
|
|
921
|
-
datetime_search,
|
|
946
|
+
datetime_search: str,
|
|
922
947
|
ignore_unavailable: Optional[bool] = True,
|
|
923
948
|
):
|
|
924
949
|
"""Return aggregations of STAC Items."""
|
|
@@ -978,6 +1003,44 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
978
1003
|
if not await self.client.exists(index=COLLECTIONS_INDEX, id=collection_id):
|
|
979
1004
|
raise NotFoundError(f"Collection {collection_id} does not exist")
|
|
980
1005
|
|
|
1006
|
+
async def _check_item_exists_in_collection(
|
|
1007
|
+
self, collection_id: str, item_id: str
|
|
1008
|
+
) -> bool:
|
|
1009
|
+
"""Check if an item exists across all indexes for a collection.
|
|
1010
|
+
|
|
1011
|
+
Args:
|
|
1012
|
+
collection_id (str): The collection identifier.
|
|
1013
|
+
item_id (str): The item identifier.
|
|
1014
|
+
|
|
1015
|
+
Returns:
|
|
1016
|
+
bool: True if the item exists in any index, False otherwise.
|
|
1017
|
+
"""
|
|
1018
|
+
alias = index_alias_by_collection_id(collection_id)
|
|
1019
|
+
doc_id = mk_item_id(item_id, collection_id)
|
|
1020
|
+
try:
|
|
1021
|
+
return await check_item_exists_in_alias(self.client, alias, doc_id)
|
|
1022
|
+
except Exception:
|
|
1023
|
+
return False
|
|
1024
|
+
|
|
1025
|
+
def _check_item_exists_in_collection_sync(
|
|
1026
|
+
self, collection_id: str, item_id: str
|
|
1027
|
+
) -> bool:
|
|
1028
|
+
"""Check if an item exists across all indexes for a collection (sync version).
|
|
1029
|
+
|
|
1030
|
+
Args:
|
|
1031
|
+
collection_id (str): The collection identifier.
|
|
1032
|
+
item_id (str): The item identifier.
|
|
1033
|
+
|
|
1034
|
+
Returns:
|
|
1035
|
+
bool: True if the item exists in any index, False otherwise.
|
|
1036
|
+
"""
|
|
1037
|
+
alias = index_alias_by_collection_id(collection_id)
|
|
1038
|
+
doc_id = mk_item_id(item_id, collection_id)
|
|
1039
|
+
try:
|
|
1040
|
+
return check_item_exists_in_alias_sync(self.sync_client, alias, doc_id)
|
|
1041
|
+
except Exception:
|
|
1042
|
+
return False
|
|
1043
|
+
|
|
981
1044
|
async def async_prep_create_item(
|
|
982
1045
|
self, item: Item, base_url: str, exist_ok: bool = False
|
|
983
1046
|
) -> Item:
|
|
@@ -993,31 +1056,21 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
993
1056
|
Item: The prepped item.
|
|
994
1057
|
|
|
995
1058
|
Raises:
|
|
996
|
-
|
|
1059
|
+
ItemAlreadyExistsError: If the item already exists in the database.
|
|
997
1060
|
|
|
998
1061
|
"""
|
|
999
1062
|
await self.check_collection_exists(collection_id=item["collection"])
|
|
1000
|
-
alias = index_alias_by_collection_id(item["collection"])
|
|
1001
|
-
doc_id = mk_item_id(item["id"], item["collection"])
|
|
1002
|
-
|
|
1003
|
-
if not exist_ok:
|
|
1004
|
-
alias_exists = await self.client.indices.exists_alias(name=alias)
|
|
1005
1063
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
for index in indices:
|
|
1011
|
-
if await self.client.exists(index=index, id=doc_id):
|
|
1012
|
-
raise ConflictError(
|
|
1013
|
-
f"Item {item['id']} in collection {item['collection']} already exists"
|
|
1014
|
-
)
|
|
1064
|
+
if not exist_ok and await self._check_item_exists_in_collection(
|
|
1065
|
+
item["collection"], item["id"]
|
|
1066
|
+
):
|
|
1067
|
+
raise ItemAlreadyExistsError(item["id"], item["collection"])
|
|
1015
1068
|
|
|
1016
1069
|
return self.item_serializer.stac_to_db(item, base_url)
|
|
1017
1070
|
|
|
1018
1071
|
async def bulk_async_prep_create_item(
|
|
1019
1072
|
self, item: Item, base_url: str, exist_ok: bool = False
|
|
1020
|
-
) -> Item:
|
|
1073
|
+
) -> Optional[Item]:
|
|
1021
1074
|
"""
|
|
1022
1075
|
Prepare an item for insertion into the database.
|
|
1023
1076
|
|
|
@@ -1045,20 +1098,19 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1045
1098
|
# Check if the collection exists
|
|
1046
1099
|
await self.check_collection_exists(collection_id=item["collection"])
|
|
1047
1100
|
|
|
1048
|
-
# Check if the item already exists in the database
|
|
1049
|
-
if not exist_ok and await self.
|
|
1050
|
-
|
|
1051
|
-
id=mk_item_id(item["id"], item["collection"]),
|
|
1101
|
+
# Check if the item already exists in the database (across all datetime indexes)
|
|
1102
|
+
if not exist_ok and await self._check_item_exists_in_collection(
|
|
1103
|
+
item["collection"], item["id"]
|
|
1052
1104
|
):
|
|
1053
|
-
error_message = (
|
|
1054
|
-
f"Item {item['id']} in collection {item['collection']} already exists."
|
|
1055
|
-
)
|
|
1056
1105
|
if self.async_settings.raise_on_bulk_error:
|
|
1057
|
-
raise
|
|
1106
|
+
raise ItemAlreadyExistsError(item["id"], item["collection"])
|
|
1058
1107
|
else:
|
|
1059
1108
|
logger.warning(
|
|
1060
|
-
f"{
|
|
1109
|
+
f"Item {item['id']} in collection {item['collection']} already exists. "
|
|
1110
|
+
"Skipping as `RAISE_ON_BULK_ERROR` is set to false."
|
|
1061
1111
|
)
|
|
1112
|
+
return None
|
|
1113
|
+
|
|
1062
1114
|
# Serialize the item into a database-compatible format
|
|
1063
1115
|
prepped_item = self.item_serializer.stac_to_db(item, base_url)
|
|
1064
1116
|
logger.debug(f"Item {item['id']} prepared successfully.")
|
|
@@ -1066,7 +1118,7 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1066
1118
|
|
|
1067
1119
|
def bulk_sync_prep_create_item(
|
|
1068
1120
|
self, item: Item, base_url: str, exist_ok: bool = False
|
|
1069
|
-
) -> Item:
|
|
1121
|
+
) -> Optional[Item]:
|
|
1070
1122
|
"""
|
|
1071
1123
|
Prepare an item for insertion into the database.
|
|
1072
1124
|
|
|
@@ -1095,20 +1147,18 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1095
1147
|
if not self.sync_client.exists(index=COLLECTIONS_INDEX, id=item["collection"]):
|
|
1096
1148
|
raise NotFoundError(f"Collection {item['collection']} does not exist")
|
|
1097
1149
|
|
|
1098
|
-
# Check if the item already exists in the database
|
|
1099
|
-
if not exist_ok and self.
|
|
1100
|
-
|
|
1101
|
-
id=mk_item_id(item["id"], item["collection"]),
|
|
1150
|
+
# Check if the item already exists in the database (across all datetime indexes)
|
|
1151
|
+
if not exist_ok and self._check_item_exists_in_collection_sync(
|
|
1152
|
+
item["collection"], item["id"]
|
|
1102
1153
|
):
|
|
1103
|
-
error_message = (
|
|
1104
|
-
f"Item {item['id']} in collection {item['collection']} already exists."
|
|
1105
|
-
)
|
|
1106
1154
|
if self.sync_settings.raise_on_bulk_error:
|
|
1107
|
-
raise
|
|
1155
|
+
raise ItemAlreadyExistsError(item["id"], item["collection"])
|
|
1108
1156
|
else:
|
|
1109
1157
|
logger.warning(
|
|
1110
|
-
f"{
|
|
1158
|
+
f"Item {item['id']} in collection {item['collection']} already exists. "
|
|
1159
|
+
"Skipping as `RAISE_ON_BULK_ERROR` is set to false."
|
|
1111
1160
|
)
|
|
1161
|
+
return None
|
|
1112
1162
|
|
|
1113
1163
|
# Serialize the item into a database-compatible format
|
|
1114
1164
|
prepped_item = self.item_serializer.stac_to_db(item, base_url)
|
|
@@ -1152,6 +1202,31 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1152
1202
|
f"Creating item {item_id} in collection {collection_id} with refresh={refresh}"
|
|
1153
1203
|
)
|
|
1154
1204
|
|
|
1205
|
+
if exist_ok and isinstance(self.async_index_inserter, DatetimeIndexInserter):
|
|
1206
|
+
existing_item = await self.get_one_item(collection_id, item_id)
|
|
1207
|
+
primary_datetime_name = self.async_index_inserter.primary_datetime_name
|
|
1208
|
+
|
|
1209
|
+
existing_primary_datetime = existing_item.get("properties", {}).get(
|
|
1210
|
+
primary_datetime_name
|
|
1211
|
+
)
|
|
1212
|
+
new_primary_datetime = item.get("properties", {}).get(primary_datetime_name)
|
|
1213
|
+
|
|
1214
|
+
if existing_primary_datetime != new_primary_datetime:
|
|
1215
|
+
self.async_index_inserter.validate_datetime_field_update(
|
|
1216
|
+
f"properties/{primary_datetime_name}"
|
|
1217
|
+
)
|
|
1218
|
+
|
|
1219
|
+
if primary_datetime_name == "start_datetime":
|
|
1220
|
+
existing_end_datetime = existing_item.get("properties", {}).get(
|
|
1221
|
+
"end_datetime"
|
|
1222
|
+
)
|
|
1223
|
+
new_end_datetime = item.get("properties", {}).get("end_datetime")
|
|
1224
|
+
|
|
1225
|
+
if existing_end_datetime != new_end_datetime:
|
|
1226
|
+
self.async_index_inserter.validate_datetime_field_update(
|
|
1227
|
+
"properties/end_datetime"
|
|
1228
|
+
)
|
|
1229
|
+
|
|
1155
1230
|
item = await self.async_prep_create_item(
|
|
1156
1231
|
item=item, base_url=base_url, exist_ok=exist_ok
|
|
1157
1232
|
)
|
|
@@ -1219,6 +1294,10 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1219
1294
|
Returns:
|
|
1220
1295
|
patched item.
|
|
1221
1296
|
"""
|
|
1297
|
+
for operation in operations:
|
|
1298
|
+
if operation.op in ["add", "replace", "remove"]:
|
|
1299
|
+
self.async_index_inserter.validate_datetime_field_update(operation.path)
|
|
1300
|
+
|
|
1222
1301
|
new_item_id = None
|
|
1223
1302
|
new_collection_id = None
|
|
1224
1303
|
script_operations = []
|
|
@@ -1238,8 +1317,6 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1238
1317
|
else:
|
|
1239
1318
|
script_operations.append(operation)
|
|
1240
1319
|
|
|
1241
|
-
script = operations_to_script(script_operations, create_nest=create_nest)
|
|
1242
|
-
|
|
1243
1320
|
try:
|
|
1244
1321
|
search_response = await self.client.search(
|
|
1245
1322
|
index=index_alias_by_collection_id(collection_id),
|
|
@@ -1252,13 +1329,18 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1252
1329
|
raise NotFoundError(
|
|
1253
1330
|
f"Item {item_id} does not exist inside Collection {collection_id}"
|
|
1254
1331
|
)
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1332
|
+
|
|
1333
|
+
if script_operations:
|
|
1334
|
+
script = operations_to_script(
|
|
1335
|
+
script_operations, create_nest=create_nest
|
|
1336
|
+
)
|
|
1337
|
+
document_index = search_response["hits"]["hits"][0]["_index"]
|
|
1338
|
+
await self.client.update(
|
|
1339
|
+
index=document_index,
|
|
1340
|
+
id=mk_item_id(item_id, collection_id),
|
|
1341
|
+
body={"script": script},
|
|
1342
|
+
refresh=True,
|
|
1343
|
+
)
|
|
1262
1344
|
except exceptions.NotFoundError:
|
|
1263
1345
|
raise NotFoundError(
|
|
1264
1346
|
f"Item {item_id} does not exist inside Collection {collection_id}"
|
|
@@ -1271,24 +1353,9 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1271
1353
|
item = await self.get_one_item(collection_id, item_id)
|
|
1272
1354
|
|
|
1273
1355
|
if new_collection_id:
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
"source": {
|
|
1278
|
-
"index": f"{ITEMS_INDEX_PREFIX}{collection_id}",
|
|
1279
|
-
"query": {"term": {"id": {"value": item_id}}},
|
|
1280
|
-
},
|
|
1281
|
-
"script": {
|
|
1282
|
-
"lang": "painless",
|
|
1283
|
-
"source": (
|
|
1284
|
-
f"""ctx._id = ctx._id.replace('{collection_id}', '{new_collection_id}');"""
|
|
1285
|
-
f"""ctx._source.collection = '{new_collection_id}';"""
|
|
1286
|
-
),
|
|
1287
|
-
},
|
|
1288
|
-
},
|
|
1289
|
-
wait_for_completion=True,
|
|
1290
|
-
refresh=True,
|
|
1291
|
-
)
|
|
1356
|
+
item["collection"] = new_collection_id
|
|
1357
|
+
item = await self.async_prep_create_item(item=item, base_url=base_url)
|
|
1358
|
+
await self.create_item(item=item, refresh=True)
|
|
1292
1359
|
|
|
1293
1360
|
await self.delete_item(
|
|
1294
1361
|
item_id=item_id,
|
|
@@ -1296,7 +1363,6 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1296
1363
|
refresh=refresh,
|
|
1297
1364
|
)
|
|
1298
1365
|
|
|
1299
|
-
item["collection"] = new_collection_id
|
|
1300
1366
|
collection_id = new_collection_id
|
|
1301
1367
|
|
|
1302
1368
|
if new_item_id:
|
|
@@ -1657,6 +1723,7 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1657
1723
|
)
|
|
1658
1724
|
# Delete the item index for the collection
|
|
1659
1725
|
await delete_item_index(collection_id)
|
|
1726
|
+
await self.async_index_inserter.refresh_cache()
|
|
1660
1727
|
|
|
1661
1728
|
async def bulk_async(
|
|
1662
1729
|
self,
|
{stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/stac_fastapi/opensearch/version.py
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""library version."""
|
|
2
|
-
__version__ = "6.
|
|
2
|
+
__version__ = "6.10.1"
|
|
File without changes
|
|
File without changes
|
{stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/stac_fastapi/opensearch/__init__.py
RENAMED
|
File without changes
|
{stac_fastapi_opensearch-6.9.0 → stac_fastapi_opensearch-6.10.1}/stac_fastapi/opensearch/config.py
RENAMED
|
File without changes
|