async def patch(self, body: Iterable[dict[str, Any]]): """ Insert and/or modify multiple rows in a single transaction. Patch body is an iterable of JSON Merge Patch documents; each document must contain the primary key of the row to patch. """ async with table.database.transaction(): for doc in body: pk = doc.get(table.pk) if pk is None: raise ValidationError("missing primary key") row = row_resource_type(pk_codec.decode(pk)) try: old = await row._read() try: new = json_merge_patch(value=old, type=table.schema, patch=doc) except DecodeError as de: raise BadRequestError from de await row._validate(new) await row._update(old, new) except NotFoundError: new = dc_codec.decode(doc) await row._validate(new) await row._insert(new)
async def patch(self, body: dict[str, Any]): """Modify row. Patch body is a JSON Merge Patch document.""" async with table.database.transaction(): old = await self._read() try: new = json_merge_patch(value=old, type=table.schema, patch=body) except DecodeError as de: raise BadRequestError from de await self._validate(new) await self._update(old, new)
def test_merge_patch_rfc_7386_test_cases(): assert json_merge_patch(value={"a": "b"}, patch={"a": "c"}) == {"a": "c"} assert json_merge_patch(value={"a": "b"}, patch={"b": "c"}) == {"a": "b", "b": "c"} assert json_merge_patch(value={"a": "b"}, patch={"a": None}) == {} assert json_merge_patch(value={"a": "b", "b": "c"}, patch={"a": None}) == {"b": "c"} assert json_merge_patch(value={"a": ["b"]}, patch={"a": "c"}) == {"a": "c"} assert json_merge_patch(value={"a": "c"}, patch={"a": ["b"]}) == {"a": ["b"]} assert json_merge_patch(value={"a": {"b": "c"}}, patch={"a": {"b": "d", "c": None}}) == { "a": {"b": "d"} } assert json_merge_patch(value={"a": [{"b": "c"}]}, patch={"a": [1]}) == {"a": [1]} assert json_merge_patch(value=["a", "b"], patch=["c", "d"]) == ["c", "d"] assert json_merge_patch(value={"a": "b"}, patch=["c"]) == ["c"] assert json_merge_patch(value={"a": "foo"}, patch=None) == None assert json_merge_patch(value={"a": "foo"}, patch="bar") == "bar" assert json_merge_patch(value={"e": None}, patch={"a": 1}) == {"e": None, "a": 1} assert json_merge_patch(value=[1, 2], patch={"a": "b", "c": None}) == {"a": "b"} assert json_merge_patch(value={}, patch={"a": {"bb": {"ccc": None}}}) == {"a": {"bb": {}}}
def test_merge_patch_dc_nested_delete(): DC2 = make_dataclass("DC2", (("b", Optional[str]),)) DC1 = make_dataclass("DC1", (("a", DC2),)) assert json_merge_patch(type=DC1, value=DC1(a=DC2(b="c")), patch={"a": {"b": None}}) == DC1( a=DC2(b=None) )
def test_merge_patch_dc_nested_add(): DC2 = make_dataclass("DC2", (("b", str),)) DC1 = make_dataclass("DC1", (("a", DC2),)) assert json_merge_patch( type=DC1, value=DC1(a=DC2(b="c")), patch={"a": {"b": "d", "c": None}} ) == DC1(a=DC2(b="d"))
def test_merge_patch_dc_flat_delete(): DC = make_dataclass("DC", (("a", str), ("b", Optional[str], field(default=None)))) assert json_merge_patch(type=DC, value=DC(a="b", b="c"), patch={"b": None}) == DC( a="b", b=None )
def test_merge_patch_dc_flat(): DC = make_dataclass("DC", (("a", str),)) assert json_merge_patch(type=DC, value=DC(a="b"), patch={"a": "c"}) == DC(a="c")