stac-fastapi-core 5.0.0a0__py3-none-any.whl → 6.0.0__py3-none-any.whl
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/core/base_database_logic.py +59 -1
- stac_fastapi/core/core.py +121 -2
- stac_fastapi/core/extensions/filter.py +11 -0
- stac_fastapi/core/route_dependencies.py +6 -6
- stac_fastapi/core/utilities.py +1 -0
- stac_fastapi/core/version.py +1 -1
- {stac_fastapi_core-5.0.0a0.dist-info → stac_fastapi_core-6.0.0.dist-info}/METADATA +5 -5
- {stac_fastapi_core-5.0.0a0.dist-info → stac_fastapi_core-6.0.0.dist-info}/RECORD +10 -10
- {stac_fastapi_core-5.0.0a0.dist-info → stac_fastapi_core-6.0.0.dist-info}/WHEEL +0 -0
- {stac_fastapi_core-5.0.0a0.dist-info → stac_fastapi_core-6.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Base database logic."""
|
|
2
2
|
|
|
3
3
|
import abc
|
|
4
|
-
from typing import Any, Dict, Iterable, Optional
|
|
4
|
+
from typing import Any, Dict, Iterable, List, Optional
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class BaseDatabaseLogic(abc.ABC):
|
|
@@ -29,6 +29,30 @@ class BaseDatabaseLogic(abc.ABC):
|
|
|
29
29
|
"""Create an item in the database."""
|
|
30
30
|
pass
|
|
31
31
|
|
|
32
|
+
@abc.abstractmethod
|
|
33
|
+
async def merge_patch_item(
|
|
34
|
+
self,
|
|
35
|
+
collection_id: str,
|
|
36
|
+
item_id: str,
|
|
37
|
+
item: Dict,
|
|
38
|
+
base_url: str,
|
|
39
|
+
refresh: bool = True,
|
|
40
|
+
) -> Dict:
|
|
41
|
+
"""Patch a item in the database follows RF7396."""
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
@abc.abstractmethod
|
|
45
|
+
async def json_patch_item(
|
|
46
|
+
self,
|
|
47
|
+
collection_id: str,
|
|
48
|
+
item_id: str,
|
|
49
|
+
operations: List,
|
|
50
|
+
base_url: str,
|
|
51
|
+
refresh: bool = True,
|
|
52
|
+
) -> Dict:
|
|
53
|
+
"""Patch a item in the database follows RF6902."""
|
|
54
|
+
pass
|
|
55
|
+
|
|
32
56
|
@abc.abstractmethod
|
|
33
57
|
async def delete_item(
|
|
34
58
|
self, item_id: str, collection_id: str, refresh: bool = False
|
|
@@ -36,11 +60,45 @@ class BaseDatabaseLogic(abc.ABC):
|
|
|
36
60
|
"""Delete an item from the database."""
|
|
37
61
|
pass
|
|
38
62
|
|
|
63
|
+
@abc.abstractmethod
|
|
64
|
+
async def get_items_mapping(self, collection_id: str) -> Dict[str, Dict[str, Any]]:
|
|
65
|
+
"""Get the mapping for the items in the collection."""
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
@abc.abstractmethod
|
|
69
|
+
async def get_items_unique_values(
|
|
70
|
+
self, collection_id: str, field_names: Iterable[str], *, limit: int = ...
|
|
71
|
+
) -> Dict[str, List[str]]:
|
|
72
|
+
"""Get the unique values for the given fields in the collection."""
|
|
73
|
+
pass
|
|
74
|
+
|
|
39
75
|
@abc.abstractmethod
|
|
40
76
|
async def create_collection(self, collection: Dict, refresh: bool = False) -> None:
|
|
41
77
|
"""Create a collection in the database."""
|
|
42
78
|
pass
|
|
43
79
|
|
|
80
|
+
@abc.abstractmethod
|
|
81
|
+
async def merge_patch_collection(
|
|
82
|
+
self,
|
|
83
|
+
collection_id: str,
|
|
84
|
+
collection: Dict,
|
|
85
|
+
base_url: str,
|
|
86
|
+
refresh: bool = True,
|
|
87
|
+
) -> Dict:
|
|
88
|
+
"""Patch a collection in the database follows RF7396."""
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
@abc.abstractmethod
|
|
92
|
+
async def json_patch_collection(
|
|
93
|
+
self,
|
|
94
|
+
collection_id: str,
|
|
95
|
+
operations: List,
|
|
96
|
+
base_url: str,
|
|
97
|
+
refresh: bool = True,
|
|
98
|
+
) -> Dict:
|
|
99
|
+
"""Patch a collection in the database follows RF6902."""
|
|
100
|
+
pass
|
|
101
|
+
|
|
44
102
|
@abc.abstractmethod
|
|
45
103
|
async def find_collection(self, collection_id: str) -> Dict:
|
|
46
104
|
"""Find a collection in the database."""
|
stac_fastapi/core/core.py
CHANGED
|
@@ -11,7 +11,7 @@ import attr
|
|
|
11
11
|
import orjson
|
|
12
12
|
from fastapi import HTTPException, Request
|
|
13
13
|
from overrides import overrides
|
|
14
|
-
from pydantic import ValidationError
|
|
14
|
+
from pydantic import TypeAdapter, ValidationError
|
|
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 import Collection, Item, ItemCollection
|
|
@@ -26,6 +26,12 @@ from stac_fastapi.core.models.links import PagingLinks
|
|
|
26
26
|
from stac_fastapi.core.serializers import CollectionSerializer, ItemSerializer
|
|
27
27
|
from stac_fastapi.core.session import Session
|
|
28
28
|
from stac_fastapi.core.utilities import filter_fields
|
|
29
|
+
from stac_fastapi.extensions.core.transaction import AsyncBaseTransactionsClient
|
|
30
|
+
from stac_fastapi.extensions.core.transaction.request import (
|
|
31
|
+
PartialCollection,
|
|
32
|
+
PartialItem,
|
|
33
|
+
PatchOperation,
|
|
34
|
+
)
|
|
29
35
|
from stac_fastapi.extensions.third_party.bulk_transactions import (
|
|
30
36
|
BaseBulkTransactionsClient,
|
|
31
37
|
BulkTransactionMethod,
|
|
@@ -33,13 +39,16 @@ from stac_fastapi.extensions.third_party.bulk_transactions import (
|
|
|
33
39
|
)
|
|
34
40
|
from stac_fastapi.types import stac as stac_types
|
|
35
41
|
from stac_fastapi.types.conformance import BASE_CONFORMANCE_CLASSES
|
|
36
|
-
from stac_fastapi.types.core import AsyncBaseCoreClient
|
|
42
|
+
from stac_fastapi.types.core import AsyncBaseCoreClient
|
|
37
43
|
from stac_fastapi.types.extension import ApiExtension
|
|
38
44
|
from stac_fastapi.types.requests import get_base_url
|
|
39
45
|
from stac_fastapi.types.search import BaseSearchPostRequest
|
|
40
46
|
|
|
41
47
|
logger = logging.getLogger(__name__)
|
|
42
48
|
|
|
49
|
+
partialItemValidator = TypeAdapter(PartialItem)
|
|
50
|
+
partialCollectionValidator = TypeAdapter(PartialCollection)
|
|
51
|
+
|
|
43
52
|
|
|
44
53
|
@attr.s
|
|
45
54
|
class CoreClient(AsyncBaseCoreClient):
|
|
@@ -680,6 +689,63 @@ class TransactionsClient(AsyncBaseTransactionsClient):
|
|
|
680
689
|
|
|
681
690
|
return ItemSerializer.db_to_stac(item, base_url)
|
|
682
691
|
|
|
692
|
+
@overrides
|
|
693
|
+
async def patch_item(
|
|
694
|
+
self,
|
|
695
|
+
collection_id: str,
|
|
696
|
+
item_id: str,
|
|
697
|
+
patch: Union[PartialItem, List[PatchOperation]],
|
|
698
|
+
**kwargs,
|
|
699
|
+
):
|
|
700
|
+
"""Patch an item in the collection.
|
|
701
|
+
|
|
702
|
+
Args:
|
|
703
|
+
collection_id (str): The ID of the collection the item belongs to.
|
|
704
|
+
item_id (str): The ID of the item to be updated.
|
|
705
|
+
patch (Union[PartialItem, List[PatchOperation]]): The item data or operations.
|
|
706
|
+
kwargs: Other optional arguments, including the request object.
|
|
707
|
+
|
|
708
|
+
Returns:
|
|
709
|
+
stac_types.Item: The updated item object.
|
|
710
|
+
|
|
711
|
+
Raises:
|
|
712
|
+
NotFound: If the specified collection is not found in the database.
|
|
713
|
+
|
|
714
|
+
"""
|
|
715
|
+
base_url = str(kwargs["request"].base_url)
|
|
716
|
+
|
|
717
|
+
content_type = kwargs["request"].headers.get("content-type")
|
|
718
|
+
|
|
719
|
+
item = None
|
|
720
|
+
if isinstance(patch, list) and content_type == "application/json-patch+json":
|
|
721
|
+
item = await self.database.json_patch_item(
|
|
722
|
+
collection_id=collection_id,
|
|
723
|
+
item_id=item_id,
|
|
724
|
+
operations=patch,
|
|
725
|
+
base_url=base_url,
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
if isinstance(patch, dict):
|
|
729
|
+
patch = partialItemValidator.validate_python(patch)
|
|
730
|
+
|
|
731
|
+
if isinstance(patch, PartialItem) and content_type in [
|
|
732
|
+
"application/merge-patch+json",
|
|
733
|
+
"application/json",
|
|
734
|
+
]:
|
|
735
|
+
item = await self.database.merge_patch_item(
|
|
736
|
+
collection_id=collection_id,
|
|
737
|
+
item_id=item_id,
|
|
738
|
+
item=patch,
|
|
739
|
+
base_url=base_url,
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
if item:
|
|
743
|
+
return ItemSerializer.db_to_stac(item, base_url=base_url)
|
|
744
|
+
|
|
745
|
+
raise NotImplementedError(
|
|
746
|
+
f"Content-Type: {content_type} and body: {patch} combination not implemented"
|
|
747
|
+
)
|
|
748
|
+
|
|
683
749
|
@overrides
|
|
684
750
|
async def delete_item(self, item_id: str, collection_id: str, **kwargs) -> None:
|
|
685
751
|
"""Delete an item from a collection.
|
|
@@ -761,6 +827,59 @@ class TransactionsClient(AsyncBaseTransactionsClient):
|
|
|
761
827
|
extensions=[type(ext).__name__ for ext in self.database.extensions],
|
|
762
828
|
)
|
|
763
829
|
|
|
830
|
+
@overrides
|
|
831
|
+
async def patch_collection(
|
|
832
|
+
self,
|
|
833
|
+
collection_id: str,
|
|
834
|
+
patch: Union[PartialCollection, List[PatchOperation]],
|
|
835
|
+
**kwargs,
|
|
836
|
+
):
|
|
837
|
+
"""Update a collection.
|
|
838
|
+
|
|
839
|
+
Called with `PATCH /collections/{collection_id}`
|
|
840
|
+
|
|
841
|
+
Args:
|
|
842
|
+
collection_id: id of the collection.
|
|
843
|
+
patch: either the partial collection or list of patch operations.
|
|
844
|
+
|
|
845
|
+
Returns:
|
|
846
|
+
The patched collection.
|
|
847
|
+
"""
|
|
848
|
+
base_url = str(kwargs["request"].base_url)
|
|
849
|
+
content_type = kwargs["request"].headers.get("content-type")
|
|
850
|
+
|
|
851
|
+
collection = None
|
|
852
|
+
if isinstance(patch, list) and content_type == "application/json-patch+json":
|
|
853
|
+
collection = await self.database.json_patch_collection(
|
|
854
|
+
collection_id=collection_id,
|
|
855
|
+
operations=patch,
|
|
856
|
+
base_url=base_url,
|
|
857
|
+
)
|
|
858
|
+
|
|
859
|
+
if isinstance(patch, dict):
|
|
860
|
+
patch = partialCollectionValidator.validate_python(patch)
|
|
861
|
+
|
|
862
|
+
if isinstance(patch, PartialCollection) and content_type in [
|
|
863
|
+
"application/merge-patch+json",
|
|
864
|
+
"application/json",
|
|
865
|
+
]:
|
|
866
|
+
collection = await self.database.merge_patch_collection(
|
|
867
|
+
collection_id=collection_id,
|
|
868
|
+
collection=patch,
|
|
869
|
+
base_url=base_url,
|
|
870
|
+
)
|
|
871
|
+
|
|
872
|
+
if collection:
|
|
873
|
+
return CollectionSerializer.db_to_stac(
|
|
874
|
+
collection,
|
|
875
|
+
kwargs["request"],
|
|
876
|
+
extensions=[type(ext).__name__ for ext in self.database.extensions],
|
|
877
|
+
)
|
|
878
|
+
|
|
879
|
+
raise NotImplementedError(
|
|
880
|
+
f"Content-Type: {content_type} and body: {patch} combination not implemented"
|
|
881
|
+
)
|
|
882
|
+
|
|
764
883
|
@overrides
|
|
765
884
|
async def delete_collection(self, collection_id: str, **kwargs) -> None:
|
|
766
885
|
"""
|
|
@@ -60,6 +60,17 @@ DEFAULT_QUERYABLES: Dict[str, Dict[str, Any]] = {
|
|
|
60
60
|
"maximum": 100,
|
|
61
61
|
},
|
|
62
62
|
}
|
|
63
|
+
"""Queryables that are present in all collections."""
|
|
64
|
+
|
|
65
|
+
OPTIONAL_QUERYABLES: Dict[str, Dict[str, Any]] = {
|
|
66
|
+
"platform": {
|
|
67
|
+
"$enum": True,
|
|
68
|
+
"description": "Satellite platform identifier",
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
"""Queryables that are present in some collections."""
|
|
72
|
+
|
|
73
|
+
ALL_QUERYABLES: Dict[str, Dict[str, Any]] = DEFAULT_QUERYABLES | OPTIONAL_QUERYABLES
|
|
63
74
|
|
|
64
75
|
|
|
65
76
|
class LogicalOp(str, Enum):
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import importlib
|
|
4
4
|
import inspect
|
|
5
|
-
import json
|
|
6
5
|
import logging
|
|
7
6
|
import os
|
|
8
7
|
from typing import List
|
|
9
8
|
|
|
9
|
+
import orjson
|
|
10
10
|
from fastapi import Depends
|
|
11
11
|
from jsonschema import validate
|
|
12
12
|
|
|
@@ -84,14 +84,14 @@ route_dependencies_schema = {
|
|
|
84
84
|
|
|
85
85
|
def get_route_dependencies_conf(route_dependencies_env: str) -> list:
|
|
86
86
|
"""Get Route dependencies configuration from file or environment variable."""
|
|
87
|
-
if os.path.
|
|
88
|
-
with open(route_dependencies_env,
|
|
89
|
-
route_dependencies_conf =
|
|
87
|
+
if os.path.isfile(route_dependencies_env):
|
|
88
|
+
with open(route_dependencies_env, "rb") as f:
|
|
89
|
+
route_dependencies_conf = orjson.loads(f.read())
|
|
90
90
|
|
|
91
91
|
else:
|
|
92
92
|
try:
|
|
93
|
-
route_dependencies_conf =
|
|
94
|
-
except
|
|
93
|
+
route_dependencies_conf = orjson.loads(route_dependencies_env)
|
|
94
|
+
except orjson.JSONDecodeError as exception:
|
|
95
95
|
_LOGGER.error("Invalid JSON format for route dependencies. %s", exception)
|
|
96
96
|
raise
|
|
97
97
|
|
stac_fastapi/core/utilities.py
CHANGED
stac_fastapi/core/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""library version."""
|
|
2
|
-
__version__ = "
|
|
2
|
+
__version__ = "6.0.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: stac-fastapi-core
|
|
3
|
-
Version:
|
|
3
|
+
Version: 6.0.0
|
|
4
4
|
Summary: Core library for the Elasticsearch and Opensearch stac-fastapi backends.
|
|
5
5
|
Home-page: https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch
|
|
6
6
|
License: MIT
|
|
@@ -18,10 +18,10 @@ Description-Content-Type: text/markdown
|
|
|
18
18
|
Requires-Dist: fastapi~=0.109.0
|
|
19
19
|
Requires-Dist: attrs>=23.2.0
|
|
20
20
|
Requires-Dist: pydantic<3.0.0,>=2.4.1
|
|
21
|
-
Requires-Dist: stac-pydantic~=3.
|
|
22
|
-
Requires-Dist: stac-fastapi.
|
|
23
|
-
Requires-Dist: stac-fastapi.
|
|
24
|
-
Requires-Dist: stac-fastapi.
|
|
21
|
+
Requires-Dist: stac-pydantic~=3.3.0
|
|
22
|
+
Requires-Dist: stac-fastapi.types==6.0.0
|
|
23
|
+
Requires-Dist: stac-fastapi.api==6.0.0
|
|
24
|
+
Requires-Dist: stac-fastapi.extensions==6.0.0
|
|
25
25
|
Requires-Dist: orjson~=3.9.0
|
|
26
26
|
Requires-Dist: overrides~=7.4.0
|
|
27
27
|
Requires-Dist: geojson-pydantic~=1.0.0
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
stac_fastapi/core/__init__.py,sha256=8izV3IWRGdXmDOK1hIPQAanbWs9EI04PJCGgqG1ZGIs,20
|
|
2
|
-
stac_fastapi/core/base_database_logic.py,sha256=
|
|
2
|
+
stac_fastapi/core/base_database_logic.py,sha256=AcvS38fWUk44BHD1vJfQENKHx1LDQdvRjMqcSQBFqw4,3189
|
|
3
3
|
stac_fastapi/core/base_settings.py,sha256=R3_Sx7n5XpGMs3zAwFJD7y008WvGU_uI2xkaabm82Kg,239
|
|
4
4
|
stac_fastapi/core/basic_auth.py,sha256=RhFv3RVSHF6OaqnaaU2DO4ncJ_S5nB1q8UNpnVJJsrk,2155
|
|
5
|
-
stac_fastapi/core/core.py,sha256=
|
|
5
|
+
stac_fastapi/core/core.py,sha256=Unfg3c7UX_AxH_FdJSKfHzIggWhENUR2PAlf7XKbgew,35974
|
|
6
6
|
stac_fastapi/core/datetime_utils.py,sha256=oueonjfuKdsB8IF_Ow-brK_X1bXs8_GLuVZOZr_L4ws,2527
|
|
7
7
|
stac_fastapi/core/rate_limit.py,sha256=Gu8dAaJReGsj1L91U6m2tflU6RahpXDRs2-AYSKoybA,1318
|
|
8
|
-
stac_fastapi/core/route_dependencies.py,sha256=
|
|
8
|
+
stac_fastapi/core/route_dependencies.py,sha256=hdtuMkv-zY1vg0YxiCz1aKP0SbBcORqDGEKDGgEazW8,5482
|
|
9
9
|
stac_fastapi/core/serializers.py,sha256=pJjpwA6BOHjCXBCmwVTH7MOmTjY9NXF1-i_E0yB60Zg,6228
|
|
10
10
|
stac_fastapi/core/session.py,sha256=Qr080UU_7qKtIv0qZAuOV7oNUQUzT5Yn00h-m_aoCvY,473
|
|
11
|
-
stac_fastapi/core/utilities.py,sha256=
|
|
12
|
-
stac_fastapi/core/version.py,sha256=
|
|
11
|
+
stac_fastapi/core/utilities.py,sha256=xXWO5oJCNDi7_C5jPYlHZD0B-DL-FN66eEUBUSW-cXw,7296
|
|
12
|
+
stac_fastapi/core/version.py,sha256=Fo5UFEQVxJZ3nywa3IY-enu5UQBE0X45nrQaRBe8c9o,45
|
|
13
13
|
stac_fastapi/core/extensions/__init__.py,sha256=2MCo0UoInkgItIM8id-rbeygzn_qUOvTGfr8jFXZjHQ,167
|
|
14
14
|
stac_fastapi/core/extensions/aggregation.py,sha256=v1hUHqlYuMqfQ554g3cTp16pUyRYucQxPERbHPAFtf8,1878
|
|
15
15
|
stac_fastapi/core/extensions/fields.py,sha256=NCT5XHvfaf297eDPNaIFsIzvJnbbUTpScqF0otdx0NA,1066
|
|
16
|
-
stac_fastapi/core/extensions/filter.py,sha256=
|
|
16
|
+
stac_fastapi/core/extensions/filter.py,sha256=mQKQYKJk4lkKZs9C3rkNR6ICTuKedokWiRBIXii20jc,3599
|
|
17
17
|
stac_fastapi/core/extensions/query.py,sha256=Xmo8pfZEZKPudZEjjozv3R0wLOP0ayjC9E67sBOXqWY,1803
|
|
18
18
|
stac_fastapi/core/models/__init__.py,sha256=g-D1DiGfmC9Bg27DW9JzkN6fAvscv75wyhyiZ6NzvIk,48
|
|
19
19
|
stac_fastapi/core/models/links.py,sha256=3jk4t2wA3RGTq9_BbzFsMKvMbgDBajQy4vKZFSHt7E8,6666
|
|
20
20
|
stac_fastapi/core/models/search.py,sha256=7SgAUyzHGXBXSqB4G6cwq9FMwoAS00momb7jvBkjyow,27
|
|
21
|
-
stac_fastapi_core-
|
|
22
|
-
stac_fastapi_core-
|
|
23
|
-
stac_fastapi_core-
|
|
24
|
-
stac_fastapi_core-
|
|
21
|
+
stac_fastapi_core-6.0.0.dist-info/METADATA,sha256=yP22yFDPXvFZQh_zzAltsue6u7GGsiaClwrbxeMuZU4,31593
|
|
22
|
+
stac_fastapi_core-6.0.0.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
23
|
+
stac_fastapi_core-6.0.0.dist-info/top_level.txt,sha256=vqn-D9-HsRPTTxy0Vk_KkDmTiMES4owwBQ3ydSZYb2s,13
|
|
24
|
+
stac_fastapi_core-6.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|