stac-fastapi-elasticsearch 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_elasticsearch-6.9.0 → stac_fastapi_elasticsearch-6.10.1}/.gitignore +11 -0
- {stac_fastapi_elasticsearch-6.9.0 → stac_fastapi_elasticsearch-6.10.1}/PKG-INFO +5 -5
- {stac_fastapi_elasticsearch-6.9.0 → stac_fastapi_elasticsearch-6.10.1}/pyproject.toml +4 -4
- {stac_fastapi_elasticsearch-6.9.0 → stac_fastapi_elasticsearch-6.10.1}/stac_fastapi/elasticsearch/app.py +2 -2
- {stac_fastapi_elasticsearch-6.9.0 → stac_fastapi_elasticsearch-6.10.1}/stac_fastapi/elasticsearch/database_logic.py +135 -71
- {stac_fastapi_elasticsearch-6.9.0 → stac_fastapi_elasticsearch-6.10.1}/stac_fastapi/elasticsearch/version.py +1 -1
- {stac_fastapi_elasticsearch-6.9.0 → stac_fastapi_elasticsearch-6.10.1}/README.md +0 -0
- {stac_fastapi_elasticsearch-6.9.0 → stac_fastapi_elasticsearch-6.10.1}/pytest.ini +0 -0
- {stac_fastapi_elasticsearch-6.9.0 → stac_fastapi_elasticsearch-6.10.1}/stac_fastapi/elasticsearch/__init__.py +0 -0
- {stac_fastapi_elasticsearch-6.9.0 → stac_fastapi_elasticsearch-6.10.1}/stac_fastapi/elasticsearch/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_elasticsearch
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.10.1
|
|
4
4
|
Summary: An implementation of STAC API based on the FastAPI framework with Elasticsearch.
|
|
5
5
|
Project-URL: Homepage, https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch
|
|
6
6
|
License: MIT
|
|
@@ -15,8 +15,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.14
|
|
16
16
|
Requires-Python: >=3.11
|
|
17
17
|
Requires-Dist: elasticsearch[async]~=8.19.1
|
|
18
|
-
Requires-Dist: sfeos-helpers==6.
|
|
19
|
-
Requires-Dist: stac-fastapi-core==6.
|
|
18
|
+
Requires-Dist: sfeos-helpers==6.10.1
|
|
19
|
+
Requires-Dist: stac-fastapi-core==6.10.1
|
|
20
20
|
Requires-Dist: starlette<0.36.0,>=0.35.0
|
|
21
21
|
Requires-Dist: uvicorn~=0.23.0
|
|
22
22
|
Provides-Extra: dev
|
|
@@ -28,7 +28,7 @@ Requires-Dist: pytest-cov~=4.0.0; extra == 'dev'
|
|
|
28
28
|
Requires-Dist: pytest~=8.0; extra == 'dev'
|
|
29
29
|
Requires-Dist: redis~=6.4.0; extra == 'dev'
|
|
30
30
|
Requires-Dist: retry~=0.9.2; extra == 'dev'
|
|
31
|
-
Requires-Dist: stac-fastapi-core[redis]==6.
|
|
31
|
+
Requires-Dist: stac-fastapi-core[redis]==6.10.1; extra == 'dev'
|
|
32
32
|
Provides-Extra: docs
|
|
33
33
|
Requires-Dist: mkdocs-material~=9.0.0; extra == 'docs'
|
|
34
34
|
Requires-Dist: mkdocs~=1.4.0; extra == 'docs'
|
|
@@ -36,7 +36,7 @@ Requires-Dist: pdocs~=1.2.0; extra == 'docs'
|
|
|
36
36
|
Requires-Dist: redis~=6.4.0; extra == 'docs'
|
|
37
37
|
Requires-Dist: retry~=0.9.2; extra == 'docs'
|
|
38
38
|
Provides-Extra: redis
|
|
39
|
-
Requires-Dist: stac-fastapi-core[redis]==6.
|
|
39
|
+
Requires-Dist: stac-fastapi-core[redis]==6.10.1; extra == 'redis'
|
|
40
40
|
Provides-Extra: server
|
|
41
41
|
Requires-Dist: uvicorn[standard]~=0.23.0; extra == 'server'
|
|
42
42
|
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
|
"elasticsearch[async]~=8.19.1",
|
|
34
34
|
"uvicorn~=0.23.0",
|
|
35
35
|
"starlette>=0.35.0,<0.36.0",
|
|
@@ -48,7 +48,7 @@ dev = [
|
|
|
48
48
|
"httpx>=0.24.0,<0.28.0",
|
|
49
49
|
"redis~=6.4.0",
|
|
50
50
|
"retry~=0.9.2",
|
|
51
|
-
"stac-fastapi-core[redis]==6.
|
|
51
|
+
"stac-fastapi-core[redis]==6.10.1",
|
|
52
52
|
]
|
|
53
53
|
docs = [
|
|
54
54
|
"mkdocs~=1.4.0",
|
|
@@ -58,7 +58,7 @@ docs = [
|
|
|
58
58
|
"retry~=0.9.2",
|
|
59
59
|
]
|
|
60
60
|
redis = [
|
|
61
|
-
"stac-fastapi-core[redis]==6.
|
|
61
|
+
"stac-fastapi-core[redis]==6.10.1",
|
|
62
62
|
]
|
|
63
63
|
server = [
|
|
64
64
|
"uvicorn[standard]~=0.23.0",
|
|
@@ -215,7 +215,7 @@ if ENABLE_CATALOGS_ROUTE:
|
|
|
215
215
|
),
|
|
216
216
|
settings=settings,
|
|
217
217
|
conformance_classes=[
|
|
218
|
-
"https://api.stacspec.org/v1.0.0-beta.1/catalogs
|
|
218
|
+
"https://api.stacspec.org/v1.0.0-beta.1/multi-tenant-catalogs",
|
|
219
219
|
],
|
|
220
220
|
)
|
|
221
221
|
extensions.append(catalogs_extension)
|
|
@@ -244,7 +244,7 @@ items_get_request_model = create_request_model(
|
|
|
244
244
|
app_config = {
|
|
245
245
|
"title": os.getenv("STAC_FASTAPI_TITLE", "stac-fastapi-elasticsearch"),
|
|
246
246
|
"description": os.getenv("STAC_FASTAPI_DESCRIPTION", "stac-fastapi-elasticsearch"),
|
|
247
|
-
"api_version": os.getenv("STAC_FASTAPI_VERSION", "6.
|
|
247
|
+
"api_version": os.getenv("STAC_FASTAPI_VERSION", "6.10.1"),
|
|
248
248
|
"settings": settings,
|
|
249
249
|
"extensions": extensions,
|
|
250
250
|
"client": CoreClient(
|
|
@@ -33,11 +33,14 @@ from stac_fastapi.extensions.core.transaction.request import (
|
|
|
33
33
|
PatchOperation,
|
|
34
34
|
)
|
|
35
35
|
from stac_fastapi.sfeos_helpers.database import (
|
|
36
|
+
ItemAlreadyExistsError,
|
|
36
37
|
add_bbox_shape_to_collection,
|
|
37
38
|
apply_collections_bbox_filter_shared,
|
|
38
39
|
apply_collections_datetime_filter_shared,
|
|
39
40
|
apply_free_text_filter_shared,
|
|
40
41
|
apply_intersects_filter_shared,
|
|
42
|
+
check_item_exists_in_alias,
|
|
43
|
+
check_item_exists_in_alias_sync,
|
|
41
44
|
create_index_templates_shared,
|
|
42
45
|
delete_item_index_shared,
|
|
43
46
|
get_queryables_mapping_shared,
|
|
@@ -53,6 +56,7 @@ from stac_fastapi.sfeos_helpers.database.query import (
|
|
|
53
56
|
add_collections_to_body,
|
|
54
57
|
)
|
|
55
58
|
from stac_fastapi.sfeos_helpers.database.utils import (
|
|
59
|
+
add_hidden_filter,
|
|
56
60
|
merge_to_operations,
|
|
57
61
|
operations_to_script,
|
|
58
62
|
)
|
|
@@ -67,6 +71,7 @@ from stac_fastapi.sfeos_helpers.mappings import (
|
|
|
67
71
|
from stac_fastapi.sfeos_helpers.search_engine import (
|
|
68
72
|
BaseIndexInserter,
|
|
69
73
|
BaseIndexSelector,
|
|
74
|
+
DatetimeIndexInserter,
|
|
70
75
|
IndexInsertionFactory,
|
|
71
76
|
IndexSelectorFactory,
|
|
72
77
|
)
|
|
@@ -406,12 +411,22 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
406
411
|
Notes:
|
|
407
412
|
The Item is retrieved from the Elasticsearch 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
|
)
|
|
@@ -656,7 +671,7 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
656
671
|
),
|
|
657
672
|
],
|
|
658
673
|
)
|
|
659
|
-
|
|
674
|
+
return search.query(filter_query), datetime_search
|
|
660
675
|
|
|
661
676
|
@staticmethod
|
|
662
677
|
def apply_bbox_filter(search: Search, bbox: List):
|
|
@@ -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:
|
|
@@ -854,6 +869,10 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
854
869
|
|
|
855
870
|
size_limit = min(limit + 1, max_result_window)
|
|
856
871
|
|
|
872
|
+
HIDE_ITEM_PATH = os.getenv("HIDE_ITEM_PATH", None)
|
|
873
|
+
if HIDE_ITEM_PATH:
|
|
874
|
+
query = add_hidden_filter(query, HIDE_ITEM_PATH)
|
|
875
|
+
|
|
857
876
|
search_task = asyncio.create_task(
|
|
858
877
|
self.client.search(
|
|
859
878
|
index=index_param,
|
|
@@ -865,11 +884,17 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
865
884
|
)
|
|
866
885
|
)
|
|
867
886
|
|
|
887
|
+
# Apply hidden filter to count query as well
|
|
888
|
+
count_query = search.to_dict(count=True)
|
|
889
|
+
if HIDE_ITEM_PATH:
|
|
890
|
+
q = count_query.get("query")
|
|
891
|
+
count_query["query"] = add_hidden_filter(q, HIDE_ITEM_PATH)
|
|
892
|
+
|
|
868
893
|
count_task = asyncio.create_task(
|
|
869
894
|
self.client.count(
|
|
870
895
|
index=index_param,
|
|
871
896
|
ignore_unavailable=ignore_unavailable,
|
|
872
|
-
body=
|
|
897
|
+
body=count_query,
|
|
873
898
|
)
|
|
874
899
|
)
|
|
875
900
|
|
|
@@ -912,7 +937,7 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
912
937
|
geometry_geohash_grid_precision: int,
|
|
913
938
|
geometry_geotile_grid_precision: int,
|
|
914
939
|
datetime_frequency_interval: str,
|
|
915
|
-
datetime_search,
|
|
940
|
+
datetime_search: str,
|
|
916
941
|
ignore_unavailable: Optional[bool] = True,
|
|
917
942
|
):
|
|
918
943
|
"""Return aggregations of STAC Items."""
|
|
@@ -974,6 +999,44 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
974
999
|
if not await self.client.exists(index=COLLECTIONS_INDEX, id=collection_id):
|
|
975
1000
|
raise NotFoundError(f"Collection {collection_id} does not exist")
|
|
976
1001
|
|
|
1002
|
+
async def _check_item_exists_in_collection(
|
|
1003
|
+
self, collection_id: str, item_id: str
|
|
1004
|
+
) -> bool:
|
|
1005
|
+
"""Check if an item exists across all indexes for a collection.
|
|
1006
|
+
|
|
1007
|
+
Args:
|
|
1008
|
+
collection_id (str): The collection identifier.
|
|
1009
|
+
item_id (str): The item identifier.
|
|
1010
|
+
|
|
1011
|
+
Returns:
|
|
1012
|
+
bool: True if the item exists in any index, False otherwise.
|
|
1013
|
+
"""
|
|
1014
|
+
alias = index_alias_by_collection_id(collection_id)
|
|
1015
|
+
doc_id = mk_item_id(item_id, collection_id)
|
|
1016
|
+
try:
|
|
1017
|
+
return await check_item_exists_in_alias(self.client, alias, doc_id)
|
|
1018
|
+
except Exception:
|
|
1019
|
+
return False
|
|
1020
|
+
|
|
1021
|
+
def _check_item_exists_in_collection_sync(
|
|
1022
|
+
self, collection_id: str, item_id: str
|
|
1023
|
+
) -> bool:
|
|
1024
|
+
"""Check if an item exists across all indexes for a collection (sync version).
|
|
1025
|
+
|
|
1026
|
+
Args:
|
|
1027
|
+
collection_id (str): The collection identifier.
|
|
1028
|
+
item_id (str): The item identifier.
|
|
1029
|
+
|
|
1030
|
+
Returns:
|
|
1031
|
+
bool: True if the item exists in any index, False otherwise.
|
|
1032
|
+
"""
|
|
1033
|
+
alias = index_alias_by_collection_id(collection_id)
|
|
1034
|
+
doc_id = mk_item_id(item_id, collection_id)
|
|
1035
|
+
try:
|
|
1036
|
+
return check_item_exists_in_alias_sync(self.sync_client, alias, doc_id)
|
|
1037
|
+
except Exception:
|
|
1038
|
+
return False
|
|
1039
|
+
|
|
977
1040
|
async def async_prep_create_item(
|
|
978
1041
|
self, item: Item, base_url: str, exist_ok: bool = False
|
|
979
1042
|
) -> Item:
|
|
@@ -989,31 +1052,21 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
989
1052
|
Item: The prepped item.
|
|
990
1053
|
|
|
991
1054
|
Raises:
|
|
992
|
-
|
|
1055
|
+
ItemAlreadyExistsError: If the item already exists in the database.
|
|
993
1056
|
|
|
994
1057
|
"""
|
|
995
1058
|
await self.check_collection_exists(collection_id=item["collection"])
|
|
996
|
-
alias = index_alias_by_collection_id(item["collection"])
|
|
997
|
-
doc_id = mk_item_id(item["id"], item["collection"])
|
|
998
|
-
|
|
999
|
-
if not exist_ok:
|
|
1000
|
-
alias_exists = await self.client.indices.exists_alias(name=alias)
|
|
1001
1059
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
for index in indices:
|
|
1007
|
-
if await self.client.exists(index=index, id=doc_id):
|
|
1008
|
-
raise ConflictError(
|
|
1009
|
-
f"Item {item['id']} in collection {item['collection']} already exists"
|
|
1010
|
-
)
|
|
1060
|
+
if not exist_ok and await self._check_item_exists_in_collection(
|
|
1061
|
+
item["collection"], item["id"]
|
|
1062
|
+
):
|
|
1063
|
+
raise ItemAlreadyExistsError(item["id"], item["collection"])
|
|
1011
1064
|
|
|
1012
1065
|
return self.item_serializer.stac_to_db(item, base_url)
|
|
1013
1066
|
|
|
1014
1067
|
async def bulk_async_prep_create_item(
|
|
1015
1068
|
self, item: Item, base_url: str, exist_ok: bool = False
|
|
1016
|
-
) -> Item:
|
|
1069
|
+
) -> Optional[Item]:
|
|
1017
1070
|
"""
|
|
1018
1071
|
Prepare an item for insertion into the database.
|
|
1019
1072
|
|
|
@@ -1041,20 +1094,18 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1041
1094
|
# Check if the collection exists
|
|
1042
1095
|
await self.check_collection_exists(collection_id=item["collection"])
|
|
1043
1096
|
|
|
1044
|
-
# Check if the item already exists in the database
|
|
1045
|
-
if not exist_ok and await self.
|
|
1046
|
-
|
|
1047
|
-
id=mk_item_id(item["id"], item["collection"]),
|
|
1097
|
+
# Check if the item already exists in the database (across all datetime indexes)
|
|
1098
|
+
if not exist_ok and await self._check_item_exists_in_collection(
|
|
1099
|
+
item["collection"], item["id"]
|
|
1048
1100
|
):
|
|
1049
|
-
error_message = (
|
|
1050
|
-
f"Item {item['id']} in collection {item['collection']} already exists."
|
|
1051
|
-
)
|
|
1052
1101
|
if self.async_settings.raise_on_bulk_error:
|
|
1053
|
-
raise
|
|
1102
|
+
raise ItemAlreadyExistsError(item["id"], item["collection"])
|
|
1054
1103
|
else:
|
|
1055
1104
|
logger.warning(
|
|
1056
|
-
f"{
|
|
1105
|
+
f"Item {item['id']} in collection {item['collection']} already exists. "
|
|
1106
|
+
"Skipping as `RAISE_ON_BULK_ERROR` is set to false."
|
|
1057
1107
|
)
|
|
1108
|
+
return None
|
|
1058
1109
|
|
|
1059
1110
|
# Serialize the item into a database-compatible format
|
|
1060
1111
|
prepped_item = self.item_serializer.stac_to_db(item, base_url)
|
|
@@ -1063,7 +1114,7 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1063
1114
|
|
|
1064
1115
|
def bulk_sync_prep_create_item(
|
|
1065
1116
|
self, item: Item, base_url: str, exist_ok: bool = False
|
|
1066
|
-
) -> Item:
|
|
1117
|
+
) -> Optional[Item]:
|
|
1067
1118
|
"""
|
|
1068
1119
|
Prepare an item for insertion into the database.
|
|
1069
1120
|
|
|
@@ -1092,20 +1143,18 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1092
1143
|
if not self.sync_client.exists(index=COLLECTIONS_INDEX, id=item["collection"]):
|
|
1093
1144
|
raise NotFoundError(f"Collection {item['collection']} does not exist")
|
|
1094
1145
|
|
|
1095
|
-
# Check if the item already exists in the database
|
|
1096
|
-
if not exist_ok and self.
|
|
1097
|
-
|
|
1098
|
-
id=mk_item_id(item["id"], item["collection"]),
|
|
1146
|
+
# Check if the item already exists in the database (across all datetime indexes)
|
|
1147
|
+
if not exist_ok and self._check_item_exists_in_collection_sync(
|
|
1148
|
+
item["collection"], item["id"]
|
|
1099
1149
|
):
|
|
1100
|
-
error_message = (
|
|
1101
|
-
f"Item {item['id']} in collection {item['collection']} already exists."
|
|
1102
|
-
)
|
|
1103
1150
|
if self.sync_settings.raise_on_bulk_error:
|
|
1104
|
-
raise
|
|
1151
|
+
raise ItemAlreadyExistsError(item["id"], item["collection"])
|
|
1105
1152
|
else:
|
|
1106
1153
|
logger.warning(
|
|
1107
|
-
f"{
|
|
1154
|
+
f"Item {item['id']} in collection {item['collection']} already exists. "
|
|
1155
|
+
"Skipping as `RAISE_ON_BULK_ERROR` is set to false."
|
|
1108
1156
|
)
|
|
1157
|
+
return None
|
|
1109
1158
|
|
|
1110
1159
|
# Serialize the item into a database-compatible format
|
|
1111
1160
|
prepped_item = self.item_serializer.stac_to_db(item, base_url)
|
|
@@ -1150,6 +1199,31 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1150
1199
|
f"Creating item {item_id} in collection {collection_id} with refresh={refresh}"
|
|
1151
1200
|
)
|
|
1152
1201
|
|
|
1202
|
+
if exist_ok and isinstance(self.async_index_inserter, DatetimeIndexInserter):
|
|
1203
|
+
existing_item = await self.get_one_item(collection_id, item_id)
|
|
1204
|
+
primary_datetime_name = self.async_index_inserter.primary_datetime_name
|
|
1205
|
+
|
|
1206
|
+
existing_primary_datetime = existing_item.get("properties", {}).get(
|
|
1207
|
+
primary_datetime_name
|
|
1208
|
+
)
|
|
1209
|
+
new_primary_datetime = item.get("properties", {}).get(primary_datetime_name)
|
|
1210
|
+
|
|
1211
|
+
if existing_primary_datetime != new_primary_datetime:
|
|
1212
|
+
self.async_index_inserter.validate_datetime_field_update(
|
|
1213
|
+
f"properties/{primary_datetime_name}"
|
|
1214
|
+
)
|
|
1215
|
+
|
|
1216
|
+
if primary_datetime_name == "start_datetime":
|
|
1217
|
+
existing_end_datetime = existing_item.get("properties", {}).get(
|
|
1218
|
+
"end_datetime"
|
|
1219
|
+
)
|
|
1220
|
+
new_end_datetime = item.get("properties", {}).get("end_datetime")
|
|
1221
|
+
|
|
1222
|
+
if existing_end_datetime != new_end_datetime:
|
|
1223
|
+
self.async_index_inserter.validate_datetime_field_update(
|
|
1224
|
+
"properties/end_datetime"
|
|
1225
|
+
)
|
|
1226
|
+
|
|
1153
1227
|
# Prepare the item for insertion
|
|
1154
1228
|
item = await self.async_prep_create_item(
|
|
1155
1229
|
item=item, base_url=base_url, exist_ok=exist_ok
|
|
@@ -1218,6 +1292,10 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1218
1292
|
Returns:
|
|
1219
1293
|
patched item.
|
|
1220
1294
|
"""
|
|
1295
|
+
for operation in operations:
|
|
1296
|
+
if operation.op in ["add", "replace", "remove"]:
|
|
1297
|
+
self.async_index_inserter.validate_datetime_field_update(operation.path)
|
|
1298
|
+
|
|
1221
1299
|
new_item_id = None
|
|
1222
1300
|
new_collection_id = None
|
|
1223
1301
|
script_operations = []
|
|
@@ -1238,8 +1316,6 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1238
1316
|
else:
|
|
1239
1317
|
script_operations.append(operation)
|
|
1240
1318
|
|
|
1241
|
-
script = operations_to_script(script_operations, create_nest=create_nest)
|
|
1242
|
-
|
|
1243
1319
|
try:
|
|
1244
1320
|
search_response = await self.client.search(
|
|
1245
1321
|
index=index_alias_by_collection_id(collection_id),
|
|
@@ -1252,13 +1328,18 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1252
1328
|
raise NotFoundError(
|
|
1253
1329
|
f"Item {item_id} does not exist inside Collection {collection_id}"
|
|
1254
1330
|
)
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1331
|
+
|
|
1332
|
+
if script_operations:
|
|
1333
|
+
script = operations_to_script(
|
|
1334
|
+
script_operations, create_nest=create_nest
|
|
1335
|
+
)
|
|
1336
|
+
document_index = search_response["hits"]["hits"][0]["_index"]
|
|
1337
|
+
await self.client.update(
|
|
1338
|
+
index=document_index,
|
|
1339
|
+
id=mk_item_id(item_id, collection_id),
|
|
1340
|
+
script=script,
|
|
1341
|
+
refresh=True,
|
|
1342
|
+
)
|
|
1262
1343
|
except ESNotFoundError:
|
|
1263
1344
|
raise NotFoundError(
|
|
1264
1345
|
f"Item {item_id} does not exist inside Collection {collection_id}"
|
|
@@ -1271,26 +1352,9 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1271
1352
|
item = await self.get_one_item(collection_id, item_id)
|
|
1272
1353
|
|
|
1273
1354
|
if new_collection_id:
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
"index": f"{ITEMS_INDEX_PREFIX}{new_collection_id}"
|
|
1278
|
-
}, # # noqa
|
|
1279
|
-
"source": {
|
|
1280
|
-
"index": f"{ITEMS_INDEX_PREFIX}{collection_id}",
|
|
1281
|
-
"query": {"term": {"id": {"value": item_id}}},
|
|
1282
|
-
},
|
|
1283
|
-
"script": {
|
|
1284
|
-
"lang": "painless",
|
|
1285
|
-
"source": (
|
|
1286
|
-
f"""ctx._id = ctx._id.replace('{collection_id}', '{new_collection_id}');""" # noqa
|
|
1287
|
-
f"""ctx._source.collection = '{new_collection_id}';""" # noqa
|
|
1288
|
-
),
|
|
1289
|
-
},
|
|
1290
|
-
},
|
|
1291
|
-
wait_for_completion=True,
|
|
1292
|
-
refresh=True,
|
|
1293
|
-
)
|
|
1355
|
+
item["collection"] = new_collection_id
|
|
1356
|
+
item = await self.async_prep_create_item(item=item, base_url=base_url)
|
|
1357
|
+
await self.create_item(item=item, refresh=True)
|
|
1294
1358
|
|
|
1295
1359
|
await self.delete_item(
|
|
1296
1360
|
item_id=item_id,
|
|
@@ -1298,7 +1362,6 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1298
1362
|
refresh=refresh,
|
|
1299
1363
|
)
|
|
1300
1364
|
|
|
1301
|
-
item["collection"] = new_collection_id
|
|
1302
1365
|
collection_id = new_collection_id
|
|
1303
1366
|
|
|
1304
1367
|
if new_item_id:
|
|
@@ -1684,6 +1747,7 @@ class DatabaseLogic(BaseDatabaseLogic):
|
|
|
1684
1747
|
index=COLLECTIONS_INDEX, id=collection_id, refresh=refresh
|
|
1685
1748
|
)
|
|
1686
1749
|
await delete_item_index(collection_id)
|
|
1750
|
+
await self.async_index_inserter.refresh_cache()
|
|
1687
1751
|
|
|
1688
1752
|
async def bulk_async(
|
|
1689
1753
|
self,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""library version."""
|
|
2
|
-
__version__ = "6.
|
|
2
|
+
__version__ = "6.10.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|