Skip to content

Commit e270f43

Browse files
move transaction clients and models to the extensions module (#846)
* move transaction clients and models to the extensions module * fix
1 parent 423b587 commit e270f43

File tree

9 files changed

+542
-510
lines changed

9 files changed

+542
-510
lines changed

CHANGES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
### Changed
66

7-
* Add Item and Collection `PATCH` endpoints with support for [RFC 6902](https://tools.ietf.org/html/rfc6902) and [RFC 7396](https://tools.ietf.org/html/rfc7386) in the `TransactionExtension`
7+
- Add Item and Collection `PATCH` endpoints with support for [RFC 6902](https://tools.ietf.org/html/rfc6902) and [RFC 7396](https://tools.ietf.org/html/rfc7386) in the `TransactionExtension`
88
- remove support of `cql-json` in Filter extension ([#840](https://github.com/stac-utils/stac-fastapi/pull/840))
9+
- move `transaction` clients and models to `stac_fastapi.extension` sub-module
910

1011
### Fixed
1112

stac_fastapi/api/tests/test_api.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from stac_fastapi.api.app import StacApi
55
from stac_fastapi.api.models import ItemCollectionUri, create_request_model
66
from stac_fastapi.extensions.core import TokenPaginationExtension, TransactionExtension
7+
from stac_fastapi.extensions.core.transaction import BaseTransactionsClient
78
from stac_fastapi.types import config, core
89

910

@@ -418,7 +419,7 @@ def item_collection(self, *args, **kwargs):
418419
...
419420

420421

421-
class DummyTransactionsClient(core.BaseTransactionsClient):
422+
class DummyTransactionsClient(BaseTransactionsClient):
422423
"""Defines a pattern for implementing the STAC transaction extension."""
423424

424425
def create_item(self, *args, **kwargs):
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"""transaction extension module."""
2+
3+
from .client import AsyncBaseTransactionsClient, BaseTransactionsClient
4+
from .transaction import TransactionConformanceClasses, TransactionExtension
5+
6+
__all__ = [
7+
"AsyncBaseTransactionsClient",
8+
"BaseTransactionsClient",
9+
"TransactionExtension",
10+
"TransactionConformanceClasses",
11+
]
Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
"""Transaction clients."""
2+
3+
import abc
4+
from typing import List, Optional, Union
5+
6+
import attr
7+
from stac_pydantic import Collection, Item, ItemCollection
8+
from starlette.responses import Response
9+
10+
from stac_fastapi.types import stac
11+
12+
from .request import PartialCollection, PartialItem, PatchOperation
13+
14+
15+
@attr.s # type:ignore
16+
class BaseTransactionsClient(abc.ABC):
17+
"""Defines a pattern for implementing the STAC API Transaction Extension."""
18+
19+
@abc.abstractmethod
20+
def create_item(
21+
self,
22+
collection_id: str,
23+
item: Union[Item, ItemCollection],
24+
**kwargs,
25+
) -> Optional[Union[stac.Item, Response, None]]:
26+
"""Create a new item.
27+
28+
Called with `POST /collections/{collection_id}/items`.
29+
30+
Args:
31+
item: the item or item collection
32+
collection_id: the id of the collection from the resource path
33+
34+
Returns:
35+
The item that was created or None if item collection.
36+
"""
37+
...
38+
39+
@abc.abstractmethod
40+
def update_item(
41+
self, collection_id: str, item_id: str, item: Item, **kwargs
42+
) -> Optional[Union[stac.Item, Response]]:
43+
"""Perform a complete update on an existing item.
44+
45+
Called with `PUT /collections/{collection_id}/items`. It is expected
46+
that this item already exists. The update should do a diff against the
47+
saved item and perform any necessary updates. Partial updates are not
48+
supported by the transactions extension.
49+
50+
Args:
51+
item: the item (must be complete)
52+
collection_id: the id of the collection from the resource path
53+
54+
Returns:
55+
The updated item.
56+
"""
57+
...
58+
59+
@abc.abstractmethod
60+
def patch_item(
61+
self,
62+
collection_id: str,
63+
item_id: str,
64+
patch: Union[PartialItem, List[PatchOperation]],
65+
**kwargs,
66+
) -> Optional[Union[stac.Item, Response]]:
67+
"""Update an item from a collection.
68+
69+
Called with `PATCH /collections/{collection_id}/items/{item_id}`
70+
71+
example:
72+
# convert merge patch item to list of operations
73+
if isinstance(patch, PartialItem):
74+
patch = patch.operations()
75+
76+
item = backend.patch_item(collection_id, item_id, patch)
77+
78+
return item
79+
80+
Args:
81+
item_id: id of the item.
82+
collection_id: id of the collection.
83+
patch: either the partial item or list of patch operations.
84+
85+
Returns:
86+
The patched item.
87+
"""
88+
...
89+
90+
@abc.abstractmethod
91+
def delete_item(
92+
self, item_id: str, collection_id: str, **kwargs
93+
) -> Optional[Union[stac.Item, Response]]:
94+
"""Delete an item from a collection.
95+
96+
Called with `DELETE /collections/{collection_id}/items/{item_id}`
97+
98+
Args:
99+
item_id: id of the item.
100+
collection_id: id of the collection.
101+
102+
Returns:
103+
The deleted item.
104+
"""
105+
...
106+
107+
@abc.abstractmethod
108+
def create_collection(
109+
self, collection: Collection, **kwargs
110+
) -> Optional[Union[stac.Collection, Response]]:
111+
"""Create a new collection.
112+
113+
Called with `POST /collections`.
114+
115+
Args:
116+
collection: the collection
117+
118+
Returns:
119+
The collection that was created.
120+
"""
121+
...
122+
123+
@abc.abstractmethod
124+
def update_collection(
125+
self, collection_id: str, collection: Collection, **kwargs
126+
) -> Optional[Union[stac.Collection, Response]]:
127+
"""Perform a complete update on an existing collection.
128+
129+
Called with `PUT /collections/{collection_id}`. It is expected that this
130+
collection already exists. The update should do a diff against the saved
131+
collection and perform any necessary updates. Partial updates are not
132+
supported by the transactions extension.
133+
134+
Args:
135+
collection_id: id of the existing collection to be updated
136+
collection: the updated collection (must be complete)
137+
138+
Returns:
139+
The updated collection.
140+
"""
141+
...
142+
143+
@abc.abstractmethod
144+
def patch_collection(
145+
self,
146+
collection_id: str,
147+
patch: Union[PartialCollection, List[PatchOperation]],
148+
**kwargs,
149+
) -> Optional[Union[stac.Collection, Response]]:
150+
"""Update a collection.
151+
152+
Called with `PATCH /collections/{collection_id}`
153+
154+
example:
155+
# convert merge patch item to list of operations
156+
if isinstance(patch, PartialCollection):
157+
patch = patch.operations()
158+
159+
collection = backend.patch_collection(collection_id, patch)
160+
161+
return collection
162+
163+
Args:
164+
collection_id: id of the collection.
165+
patch: either the partial collection or list of patch operations.
166+
167+
Returns:
168+
The patched collection.
169+
"""
170+
...
171+
172+
@abc.abstractmethod
173+
def delete_collection(
174+
self, collection_id: str, **kwargs
175+
) -> Optional[Union[stac.Collection, Response]]:
176+
"""Delete a collection.
177+
178+
Called with `DELETE /collections/{collection_id}`
179+
180+
Args:
181+
collection_id: id of the collection.
182+
183+
Returns:
184+
The deleted collection.
185+
"""
186+
...
187+
188+
189+
@attr.s # type:ignore
190+
class AsyncBaseTransactionsClient(abc.ABC):
191+
"""Defines a pattern for implementing the STAC transaction extension."""
192+
193+
@abc.abstractmethod
194+
async def create_item(
195+
self,
196+
collection_id: str,
197+
item: Union[Item, ItemCollection],
198+
**kwargs,
199+
) -> Optional[Union[stac.Item, Response, None]]:
200+
"""Create a new item.
201+
202+
Called with `POST /collections/{collection_id}/items`.
203+
204+
Args:
205+
item: the item or item collection
206+
collection_id: the id of the collection from the resource path
207+
208+
Returns:
209+
The item that was created or None if item collection.
210+
"""
211+
...
212+
213+
@abc.abstractmethod
214+
async def update_item(
215+
self, collection_id: str, item_id: str, item: Item, **kwargs
216+
) -> Optional[Union[stac.Item, Response]]:
217+
"""Perform a complete update on an existing item.
218+
219+
Called with `PUT /collections/{collection_id}/items`. It is expected
220+
that this item already exists. The update should do a diff against the
221+
saved item and perform any necessary updates. Partial updates are not
222+
supported by the transactions extension.
223+
224+
Args:
225+
item: the item (must be complete)
226+
227+
Returns:
228+
The updated item.
229+
"""
230+
...
231+
232+
@abc.abstractmethod
233+
async def patch_item(
234+
self,
235+
collection_id: str,
236+
item_id: str,
237+
patch: Union[PartialItem, List[PatchOperation]],
238+
**kwargs,
239+
) -> Optional[Union[stac.Item, Response]]:
240+
"""Update an item from a collection.
241+
242+
Called with `PATCH /collections/{collection_id}/items/{item_id}`
243+
244+
example:
245+
# convert merge patch item to list of operations
246+
if isinstance(patch, PartialItem):
247+
patch = patch.operations()
248+
249+
item = backend.patch_item(collection_id, item_id, patch)
250+
251+
return item
252+
253+
Args:
254+
item_id: id of the item.
255+
collection_id: id of the collection.
256+
patch: either the partial item or list of patch operations.
257+
258+
Returns:
259+
The patched item.
260+
"""
261+
...
262+
263+
@abc.abstractmethod
264+
async def delete_item(
265+
self, item_id: str, collection_id: str, **kwargs
266+
) -> Optional[Union[stac.Item, Response]]:
267+
"""Delete an item from a collection.
268+
269+
Called with `DELETE /collections/{collection_id}/items/{item_id}`
270+
271+
Args:
272+
item_id: id of the item.
273+
collection_id: id of the collection.
274+
275+
Returns:
276+
The deleted item.
277+
"""
278+
...
279+
280+
@abc.abstractmethod
281+
async def create_collection(
282+
self, collection: Collection, **kwargs
283+
) -> Optional[Union[stac.Collection, Response]]:
284+
"""Create a new collection.
285+
286+
Called with `POST /collections`.
287+
288+
Args:
289+
collection: the collection
290+
291+
Returns:
292+
The collection that was created.
293+
"""
294+
...
295+
296+
@abc.abstractmethod
297+
async def update_collection(
298+
self, collection_id: str, collection: Collection, **kwargs
299+
) -> Optional[Union[stac.Collection, Response]]:
300+
"""Perform a complete update on an existing collection.
301+
302+
Called with `PUT /collections/{collection_id}`. It is expected that this item
303+
already exists. The update should do a diff against the saved collection and
304+
perform any necessary updates. Partial updates are not supported by the
305+
transactions extension.
306+
307+
Args:
308+
collection_id: id of the existing collection to be updated
309+
collection: the updated collection (must be complete)
310+
311+
Returns:
312+
The updated collection.
313+
"""
314+
...
315+
316+
@abc.abstractmethod
317+
async def patch_collection(
318+
self,
319+
collection_id: str,
320+
patch: Union[PartialCollection, List[PatchOperation]],
321+
**kwargs,
322+
) -> Optional[Union[stac.Collection, Response]]:
323+
"""Update a collection.
324+
325+
Called with `PATCH /collections/{collection_id}`
326+
327+
example:
328+
# convert merge patch item to list of operations
329+
if isinstance(patch, PartialCollection):
330+
patch = patch.operations()
331+
332+
collection = backend.patch_collection(collection_id, patch)
333+
334+
return collection
335+
336+
Args:
337+
collection_id: id of the collection.
338+
patch: either the partial collection or list of patch operations.
339+
340+
Returns:
341+
The patched collection.
342+
"""
343+
...
344+
345+
@abc.abstractmethod
346+
async def delete_collection(
347+
self, collection_id: str, **kwargs
348+
) -> Optional[Union[stac.Collection, Response]]:
349+
"""Delete a collection.
350+
351+
Called with `DELETE /collections/{collection_id}`
352+
353+
Args:
354+
collection_id: id of the collection.
355+
356+
Returns:
357+
The deleted collection.
358+
"""
359+
...

0 commit comments

Comments
 (0)