Skip to content

Commit f4b9b89

Browse files
committed
Make equivalent changes to sqlalchemy backend
1 parent 3bb68e2 commit f4b9b89

File tree

8 files changed

+196
-52
lines changed

8 files changed

+196
-52
lines changed

scripts/ingest_joplin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ def post_or_put(url: str, data: dict):
1919
"""Post or put data to url."""
2020
r = requests.post(url, json=data)
2121
if r.status_code == 409:
22+
new_url = url if data["type"] == "Collection" else url + f"/{data['id']}"
2223
# Exists, so update
23-
r = requests.put(url, json=data)
24+
r = requests.put(new_url, json=data)
2425
# Unchanged may throw a 404
2526
if not r.status_code == 404:
2627
r.raise_for_status()

stac_fastapi/pgstac/stac_fastapi/pgstac/transactions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ async def create_item(
2727
self, collection_id: str, item: stac_types.Item, **kwargs
2828
) -> Optional[Union[stac_types.Item, Response]]:
2929
"""Create item."""
30-
item_collection_id = item.get("collection")
31-
if item_collection_id is not None and collection_id != item_collection_id:
30+
body_collection_id = item.get("collection")
31+
if body_collection_id is not None and collection_id != body_collection_id:
3232
raise HTTPException(
3333
status_code=409,
34-
detail=f"Collection ID from path parameter ({collection_id}) does not match Collection ID from Item ({item_collection_id})",
34+
detail=f"Collection ID from path parameter ({collection_id}) does not match Collection ID from Item ({body_collection_id})",
3535
)
3636
item["collection"] = collection_id
3737
request = kwargs["request"]

stac_fastapi/sqlalchemy/stac_fastapi/sqlalchemy/transactions.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import Optional, Type, Union
55

66
import attr
7+
from fastapi import HTTPException
78
from starlette.responses import Response
89

910
from stac_fastapi.extensions.third_party.bulk_transactions import (
@@ -35,19 +36,29 @@ class TransactionsClient(BaseTransactionsClient):
3536
)
3637

3738
def create_item(
38-
self, model: Union[stac_types.Item, stac_types.ItemCollection], **kwargs
39+
self,
40+
collection_id: str,
41+
item: Union[stac_types.Item, stac_types.ItemCollection],
42+
**kwargs,
3943
) -> Optional[stac_types.Item]:
4044
"""Create item."""
4145
base_url = str(kwargs["request"].base_url)
4246

4347
# If a feature collection is posted
44-
if model["type"] == "FeatureCollection":
48+
if item["type"] == "FeatureCollection":
4549
bulk_client = BulkTransactionsClient(session=self.session)
46-
bulk_client.bulk_item_insert(items=model["features"])
50+
bulk_client.bulk_item_insert(items=item["features"])
4751
return None
4852

4953
# Otherwise a single item has been posted
50-
data = self.item_serializer.stac_to_db(model)
54+
body_collection_id = item.get("collection")
55+
if body_collection_id is not None and collection_id != body_collection_id:
56+
raise HTTPException(
57+
status_code=409,
58+
detail=f"Collection ID from path parameter ({collection_id}) does not match Collection ID from Item ({body_collection_id})",
59+
)
60+
item["collection"] = collection_id
61+
data = self.item_serializer.stac_to_db(item)
5162
with self.session.writer.context_session() as session:
5263
session.add(data)
5364
return self.item_serializer.db_to_stac(data, base_url)
@@ -63,9 +74,22 @@ def create_collection(
6374
return self.collection_serializer.db_to_stac(data, base_url=base_url)
6475

6576
def update_item(
66-
self, item: stac_types.Item, **kwargs
77+
self, collection_id: str, item_id: str, item: stac_types.Item, **kwargs
6778
) -> Optional[Union[stac_types.Item, Response]]:
6879
"""Update item."""
80+
body_collection_id = item.get("collection")
81+
if body_collection_id is not None and collection_id != body_collection_id:
82+
raise HTTPException(
83+
status_code=409,
84+
detail=f"Collection ID from path parameter ({collection_id}) does not match Collection ID from Item ({body_collection_id})",
85+
)
86+
item["collection"] = collection_id
87+
body_item_id = item["id"]
88+
if body_item_id != item_id:
89+
raise HTTPException(
90+
status_code=409,
91+
detail=f"Item ID from path parameter ({item_id}) does not match Item ID from Item ({body_item_id})",
92+
)
6993
base_url = str(kwargs["request"].base_url)
7094
with self.session.reader.context_session() as session:
7195
query = session.query(self.item_table).filter(

stac_fastapi/sqlalchemy/tests/api/test_api.py

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"POST /collections",
2020
"POST /collections/{collection_id}/items",
2121
"PUT /collections",
22-
"PUT /collections/{collection_id}/items",
22+
"PUT /collections/{collection_id}/items/{item_id}",
2323
]
2424

2525

@@ -66,7 +66,9 @@ def test_app_transaction_extension(app_client, load_test_data):
6666

6767
def test_app_search_response(load_test_data, app_client, postgres_transactions):
6868
item = load_test_data("test_item.json")
69-
postgres_transactions.create_item(item, request=MockStarletteRequest)
69+
postgres_transactions.create_item(
70+
item["collection"], item, request=MockStarletteRequest
71+
)
7072

7173
resp = app_client.get("/search", params={"collections": ["test-collection"]})
7274
assert resp.status_code == 200
@@ -82,7 +84,9 @@ def test_app_search_response_multipolygon(
8284
load_test_data, app_client, postgres_transactions
8385
):
8486
item = load_test_data("test_item_multipolygon.json")
85-
postgres_transactions.create_item(item, request=MockStarletteRequest)
87+
postgres_transactions.create_item(
88+
item["collection"], item, request=MockStarletteRequest
89+
)
8690

8791
resp = app_client.get("/search", params={"collections": ["test-collection"]})
8892
assert resp.status_code == 200
@@ -96,7 +100,9 @@ def test_app_search_response_geometry_null(
96100
load_test_data, app_client, postgres_transactions
97101
):
98102
item = load_test_data("test_item_geometry_null.json")
99-
postgres_transactions.create_item(item, request=MockStarletteRequest)
103+
postgres_transactions.create_item(
104+
item["collection"], item, request=MockStarletteRequest
105+
)
100106

101107
resp = app_client.get("/search", params={"collections": ["test-collection"]})
102108
assert resp.status_code == 200
@@ -109,7 +115,9 @@ def test_app_search_response_geometry_null(
109115

110116
def test_app_context_extension(load_test_data, app_client, postgres_transactions):
111117
item = load_test_data("test_item.json")
112-
postgres_transactions.create_item(item, request=MockStarletteRequest)
118+
postgres_transactions.create_item(
119+
item["collection"], item, request=MockStarletteRequest
120+
)
113121

114122
resp = app_client.get("/search", params={"collections": ["test-collection"]})
115123
assert resp.status_code == 200
@@ -120,7 +128,9 @@ def test_app_context_extension(load_test_data, app_client, postgres_transactions
120128

121129
def test_app_fields_extension(load_test_data, app_client, postgres_transactions):
122130
item = load_test_data("test_item.json")
123-
postgres_transactions.create_item(item, request=MockStarletteRequest)
131+
postgres_transactions.create_item(
132+
item["collection"], item, request=MockStarletteRequest
133+
)
124134

125135
resp = app_client.get("/search", params={"collections": ["test-collection"]})
126136
assert resp.status_code == 200
@@ -130,7 +140,9 @@ def test_app_fields_extension(load_test_data, app_client, postgres_transactions)
130140

131141
def test_app_query_extension_gt(load_test_data, app_client, postgres_transactions):
132142
test_item = load_test_data("test_item.json")
133-
postgres_transactions.create_item(test_item, request=MockStarletteRequest)
143+
postgres_transactions.create_item(
144+
test_item["collection"], test_item, request=MockStarletteRequest
145+
)
134146

135147
params = {"query": {"proj:epsg": {"gt": test_item["properties"]["proj:epsg"]}}}
136148
resp = app_client.post("/search", json=params)
@@ -141,7 +153,9 @@ def test_app_query_extension_gt(load_test_data, app_client, postgres_transaction
141153

142154
def test_app_query_extension_gte(load_test_data, app_client, postgres_transactions):
143155
test_item = load_test_data("test_item.json")
144-
postgres_transactions.create_item(test_item, request=MockStarletteRequest)
156+
postgres_transactions.create_item(
157+
test_item["collection"], test_item, request=MockStarletteRequest
158+
)
145159

146160
params = {"query": {"proj:epsg": {"gte": test_item["properties"]["proj:epsg"]}}}
147161
resp = app_client.post("/search", json=params)
@@ -160,7 +174,9 @@ def test_app_query_extension_limit_lt0(
160174
load_test_data, app_client, postgres_transactions
161175
):
162176
item = load_test_data("test_item.json")
163-
postgres_transactions.create_item(item, request=MockStarletteRequest)
177+
postgres_transactions.create_item(
178+
item["collection"], item, request=MockStarletteRequest
179+
)
164180

165181
params = {"limit": -1}
166182
resp = app_client.post("/search", json=params)
@@ -171,7 +187,9 @@ def test_app_query_extension_limit_gt10000(
171187
load_test_data, app_client, postgres_transactions
172188
):
173189
item = load_test_data("test_item.json")
174-
postgres_transactions.create_item(item, request=MockStarletteRequest)
190+
postgres_transactions.create_item(
191+
item["collection"], item, request=MockStarletteRequest
192+
)
175193

176194
params = {"limit": 10001}
177195
resp = app_client.post("/search", json=params)
@@ -182,7 +200,9 @@ def test_app_query_extension_limit_10000(
182200
load_test_data, app_client, postgres_transactions
183201
):
184202
item = load_test_data("test_item.json")
185-
postgres_transactions.create_item(item, request=MockStarletteRequest)
203+
postgres_transactions.create_item(
204+
item["collection"], item, request=MockStarletteRequest
205+
)
186206

187207
params = {"limit": 10000}
188208
resp = app_client.post("/search", json=params)
@@ -194,15 +214,19 @@ def test_app_sort_extension(load_test_data, app_client, postgres_transactions):
194214
item_date = datetime.strptime(
195215
first_item["properties"]["datetime"], "%Y-%m-%dT%H:%M:%SZ"
196216
)
197-
postgres_transactions.create_item(first_item, request=MockStarletteRequest)
217+
postgres_transactions.create_item(
218+
first_item["collection"], first_item, request=MockStarletteRequest
219+
)
198220

199221
second_item = load_test_data("test_item.json")
200222
second_item["id"] = "another-item"
201223
another_item_date = item_date - timedelta(days=1)
202224
second_item["properties"]["datetime"] = another_item_date.strftime(
203225
"%Y-%m-%dT%H:%M:%SZ"
204226
)
205-
postgres_transactions.create_item(second_item, request=MockStarletteRequest)
227+
postgres_transactions.create_item(
228+
second_item["collection"], second_item, request=MockStarletteRequest
229+
)
206230

207231
params = {
208232
"collections": [first_item["collection"]],
@@ -217,7 +241,9 @@ def test_app_sort_extension(load_test_data, app_client, postgres_transactions):
217241

218242
def test_search_invalid_date(load_test_data, app_client, postgres_transactions):
219243
item = load_test_data("test_item.json")
220-
postgres_transactions.create_item(item, request=MockStarletteRequest)
244+
postgres_transactions.create_item(
245+
item["collection"], item, request=MockStarletteRequest
246+
)
221247

222248
params = {
223249
"datetime": "2020-XX-01/2020-10-30",
@@ -230,7 +256,9 @@ def test_search_invalid_date(load_test_data, app_client, postgres_transactions):
230256

231257
def test_search_point_intersects(load_test_data, app_client, postgres_transactions):
232258
item = load_test_data("test_item.json")
233-
postgres_transactions.create_item(item, request=MockStarletteRequest)
259+
postgres_transactions.create_item(
260+
item["collection"], item, request=MockStarletteRequest
261+
)
234262

235263
point = [150.04, -33.14]
236264
intersects = {"type": "Point", "coordinates": point}
@@ -247,7 +275,9 @@ def test_search_point_intersects(load_test_data, app_client, postgres_transactio
247275

248276
def test_datetime_non_interval(load_test_data, app_client, postgres_transactions):
249277
item = load_test_data("test_item.json")
250-
postgres_transactions.create_item(item, request=MockStarletteRequest)
278+
postgres_transactions.create_item(
279+
item["collection"], item, request=MockStarletteRequest
280+
)
251281
alternate_formats = [
252282
"2020-02-12T12:30:22+00:00",
253283
"2020-02-12T12:30:22.00Z",
@@ -269,7 +299,9 @@ def test_datetime_non_interval(load_test_data, app_client, postgres_transactions
269299

270300
def test_bbox_3d(load_test_data, app_client, postgres_transactions):
271301
item = load_test_data("test_item.json")
272-
postgres_transactions.create_item(item, request=MockStarletteRequest)
302+
postgres_transactions.create_item(
303+
item["collection"], item, request=MockStarletteRequest
304+
)
273305

274306
australia_bbox = [106.343365, -47.199523, 0.1, 168.218365, -19.437288, 0.1]
275307
params = {
@@ -286,7 +318,9 @@ def test_search_line_string_intersects(
286318
load_test_data, app_client, postgres_transactions
287319
):
288320
item = load_test_data("test_item.json")
289-
postgres_transactions.create_item(item, request=MockStarletteRequest)
321+
postgres_transactions.create_item(
322+
item["collection"], item, request=MockStarletteRequest
323+
)
290324

291325
line = [[150.04, -33.14], [150.22, -33.89]]
292326
intersects = {"type": "LineString", "coordinates": line}
@@ -305,7 +339,9 @@ def test_app_fields_extension_return_all_properties(
305339
load_test_data, app_client, postgres_transactions
306340
):
307341
item = load_test_data("test_item.json")
308-
postgres_transactions.create_item(item, request=MockStarletteRequest)
342+
postgres_transactions.create_item(
343+
item["collection"], item, request=MockStarletteRequest
344+
)
309345

310346
resp = app_client.get(
311347
"/search", params={"collections": ["test-collection"], "fields": "properties"}

0 commit comments

Comments
 (0)