feat: add route state and merge patches
This commit is contained in:
parent
5b206635fb
commit
3d3b031332
7 changed files with 306 additions and 63 deletions
|
|
@ -37,11 +37,19 @@ class DeltaMergeTests(SceneApiTestCase):
|
|||
self.put(self.b, changed={"a2": ann("beat")})
|
||||
self.assertEqual(set(self.groups()), {"a1", "a2"})
|
||||
|
||||
def test_same_annotation_is_last_write_wins(self):
|
||||
def test_same_annotation_same_field_is_last_write_wins(self):
|
||||
self.put(self.a, changed={"a1": ann("x", "first")})
|
||||
self.put(self.b, changed={"a1": ann("x", "second")})
|
||||
self.put(self.b, changed={"a1": {"content": "second"}})
|
||||
self.assertEqual(self.groups()["a1"]["content"], "second")
|
||||
|
||||
def test_same_annotation_different_fields_merge(self):
|
||||
self.put(self.a, changed={"a1": ann("x", "first", marks=[{"id": "m0"}])})
|
||||
self.put(self.a, changed={"a1": {"marks": [{"id": "m1"}]}})
|
||||
self.put(self.b, changed={"a1": {"content": "second"}})
|
||||
g = self.groups()["a1"]
|
||||
self.assertEqual(g["content"], "second")
|
||||
self.assertEqual(g["marks"], [{"id": "m1"}])
|
||||
|
||||
def test_stale_client_neither_resurrects_nor_wipes(self):
|
||||
# bob only ever knew a2; his delta must not erase alice's a1
|
||||
self.put(self.a, changed={"a1": ann("x")})
|
||||
|
|
|
|||
|
|
@ -135,16 +135,20 @@ def scene(request, pk):
|
|||
if (resp := _auth(request)):
|
||||
return resp
|
||||
p = _editable(request, pk)
|
||||
# A delta, not the whole scene: {changed: {gid: annotation}, deleted: [gid]}.
|
||||
# Merging per-id means two users editing different annotations both land
|
||||
# (no clobber); same-annotation edits are last-write-wins by arrival.
|
||||
# A delta, not the whole scene. `changed` values may be whole new
|
||||
# annotations or field patches for existing annotations. Merging per
|
||||
# field lets same-annotation edits to different fields both land.
|
||||
data = json.loads(request.body or "{}")
|
||||
changed = data.get("changed") or {}
|
||||
deleted = data.get("deleted") or []
|
||||
summary = None
|
||||
if changed or deleted:
|
||||
groups = dict((p.scene or {}).get("groups", {}))
|
||||
groups.update(changed)
|
||||
for gid, patch in changed.items():
|
||||
if isinstance(patch, dict) and isinstance(groups.get(gid), dict):
|
||||
groups[gid] = {**groups[gid], **patch}
|
||||
else:
|
||||
groups[gid] = patch
|
||||
for gid in deleted:
|
||||
groups.pop(gid, None)
|
||||
merged = dict(p.scene or {}, groups=groups)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue