Skip to content

Commit ef707b4

Browse files
Replace a moving feature with PUT /collections/{cid}/items/{fid}
PUT on a feature replaces its temporal geometry and properties from the posted Feature: the feature is deleted (the foreign-key cascade removes its temporal geometries, properties and values) and re-inserted under the same id in one transaction, reusing the create path and the extent trigger. do_PUT routes the items path to the new handler before the collection PUT.
1 parent f75d933 commit ef707b4

2 files changed

Lines changed: 55 additions & 1 deletion

File tree

resource/moving_feature/Replace.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# PUT /collections/{collectionId}/items/{mFeatureId}
2+
# Replace a moving feature: its temporal geometry and properties are replaced by
3+
# the posted Feature. The feature is deleted (the FK cascade removes its temporal
4+
# geometries / properties / values) and re-inserted under the same id, in one
5+
# transaction, so the replace reuses the create path and the extent trigger.
6+
import json
7+
8+
from utils import send_json_response
9+
from resource.moving_features.Create import insert_feature
10+
11+
12+
def put_single_moving_feature(self, collection_id, feature_id, connection, cursor):
13+
try:
14+
content_length = int(self.headers.get("Content-Length", 0))
15+
body = json.loads(self.rfile.read(content_length).decode("utf-8")) if content_length else {}
16+
17+
cursor.execute("SELECT id FROM collections WHERE id = %s", (collection_id,))
18+
if cursor.fetchone() is None:
19+
self.handle_error(404, f"Collection '{collection_id}' not found")
20+
return
21+
22+
cursor.execute(
23+
"SELECT id FROM moving_features WHERE id = %s AND collection_id = %s",
24+
(feature_id, collection_id),
25+
)
26+
if cursor.fetchone() is None:
27+
self.handle_error(404, f"Feature '{feature_id}' not found in collection '{collection_id}'")
28+
return
29+
30+
# Full replace: drop the feature (cascades to its temporal geometries,
31+
# properties and values) and re-insert it under the path id.
32+
cursor.execute(
33+
"DELETE FROM moving_features WHERE id = %s AND collection_id = %s",
34+
(feature_id, collection_id),
35+
)
36+
body["id"] = feature_id
37+
if body.get("type") is None:
38+
body["type"] = "Feature"
39+
insert_feature(self, body, collection_id, connection, cursor)
40+
connection.commit()
41+
42+
send_json_response(self, 200, {"message": "replaced", "id": feature_id})
43+
44+
except Exception as e:
45+
connection.rollback()
46+
self.handle_error(400, f"Replace failed: {str(e)}")

server.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from resource.moving_features.Retrieve import get_collection_items
1616
from resource.moving_feature.Retrieve import get_movement_single_moving_feature
1717
from resource.moving_feature.Delete import delete_single_moving_feature
18+
from resource.moving_feature.Replace import put_single_moving_feature
1819
from resource.temporal_geom_seq.Retrieve import get_tgsequence
1920
from resource.temporal_geom_seq.Create import post_tgsequence
2021
from resource.bulk.Create import post_bulk
@@ -242,8 +243,12 @@ def do_DELETE(self):
242243

243244

244245
def do_PUT(self):
246+
# PUT /collections/{collectionId}/items/{mFeatureId} — replace a feature
247+
if self.path.startswith('/collections/') and '/items/' in self.path and len(self.path.split('/')) == 5:
248+
parts = self.path.split('/')
249+
self.put_single_moving_feature(parts[2], parts[4], connection, cursor)
245250
#===================================================PUT collection========================================
246-
if self.path.startswith('/collections/'):
251+
elif self.path.startswith('/collections/'):
247252
collection_id = self.path.split('/')[-1]
248253
self.put_collection(collection_id, connection, cursor)
249254

@@ -370,6 +375,9 @@ def get_movement_single_moving_feature(self, collectionId, mFeatureId, connectio
370375
def delete_single_moving_feature(self, collectionId, mFeature_id, connection, cursor):
371376
delete_single_moving_feature(self, collectionId, mFeature_id, connection, cursor)
372377

378+
def put_single_moving_feature(self, collectionId, mFeature_id, connection, cursor):
379+
put_single_moving_feature(self, collectionId, mFeature_id, connection, cursor)
380+
373381

374382
## Resource Temporal Geometry Sequence
375383
#Get

0 commit comments

Comments
 (0)