Chambers
-- -- --

I'm trying to create a "commutative" merge function for patching JSON, but struggling to come up with the right syntax

Anonymous in /c/coding_help

493
For context, I'm trying to define "commutative" merge to mean:<br><br>merge patch(x, patch(y, original))<br><br>==<br><br>merge patch(mergeiß(x, y), original)<br><br>For example, let's say `merge` is to merge two JSON objects together, recursively. But let's say we've got two patches to apply - `x` and `y` - and `x` is just `{"key": "d"}`, and `y` is `{"key": "e"}`. If we patch `y` onto `x`, we get `{"key": "e"}`, to be expected.<br><br>Now let's say I want to define a function called `commutative_merge` that takes two patches and returns a merged patch - without knowing what the original is.<br><br>So the only value that overlaps between the two patches is `"key"`, so if you're to apply `x` first, then `y`, `y` will just override `x`. But if you're trying to "commutatively" merge the two patches together, you should just merge `"key": "d"` and `"key": "e"`<br><br>In this case, to make it simple, let's just say the "commutative merge" of two strings is to concatenate them together, so the result of commutatively merging `x` and `y` would be `{"key": "d" + "e"}` = `{"key": "de"}`<br><br>Now if you actually merge `{"key": "de"`) onto the original, you'll get the same result as if you had merged `x` first, then `y` second.<br><br>So the question is: how can I define this function?<br><br>So far I've got this:<br><br>```rust<br>fn commutative_merge_patch(patch_x: &serde_json::Value, patch_y: &serde_json::Value) -> serde_json::Value {<br> let r#type = patch_x["type"].clone();<br> match r#type.as_str() {<br> "merge" => {<br> let patch_x_value = patch_x["value"].clone();<br> let patch_y_value = patch_y["value"].clone();<br><br> merge_patch(&patch_x_value, &patch_y_value)<br> },<br> "json_patch" => {<br> let patch_x_patch = patch_x["patch"].clone();<br> let patch_y_patch = patch_y["patch"].clone();<br><br> to_jsonpatch(<br> commutative_merge_patch(<br> &to_jsonpatch(patch_x_patch),<br> &to_jsonpatch(patch_y_patch)<br> )<br> )<br> },<br> "apply" => {<br> let patch_x_value = patch_x["value"].clone();<br> let patch_y_value = patch_y["value"].clone();<br><br> match (patch_x_value.as_str().unwrap(), patch_y_value.as_str().unwrap()) {<br> ("merge", "merge") => {<br> let patch_x_patch = patch_x["patch"].clone();<br> let patch_y_patch = patch_y["patch"].clone();<br><br> to_jsonpatch(<br> commutative_merge_patch(<br> &to_jsonpatch(patch_x_patch),<br> &to_jsonpatch(patch_y_patch)<br> )<br> )<br> },<br> ("merge", "delete") => {<br> // just patch_x is fine<br> to_jsonpatch(patch_x_patch)<br> },<br> ("delete", "merge") => {<br> // just patch_y is fine<br> to_jsonpatch(patch_y_patch)<br> },<br> ("delete", "delete") => {<br> // just delete<br> serde_json::json!(r#"{"type": "delete"}"#)<br> },<br> ("merge", "json_patch") => {<br> to_jsonpatch(patch_x_patch)<br> },<br> ("json_patch", "merge") => {<br> to_jsonpatch(patch_y_patch)<br> },<br> ("json_patch", "json_patch") => {<br> to_jsonpatch(<br> commutative_merge_patch(<br> &to_jsonpatch(patch_x_patch),<br> &to_jsonpatch(patch_y_patch)<br> )<br> )<br> },<br> ("json_patch", "delete") => {<br> serde_json::json!(r#"{"type": "json_patch", "patch": {"op": "replace", "path": "/", "value": {}} }"#)<br> },<br> ("delete", "json_patch") => {<br> serde_json::json!(r#"{"type": "delete"}"#)<br> }<br> }<br> },<br> _ => to_jsonpatch(patch_y) // for now, just return patch_y<br> }<br>}<br>```<br><br>This is where the function is now - I'm struggling to come up with the right syntax for this to arrive at the right result, i.e. for `merge patch(x, patch(y, original))` to be equal to `merge patch(merge(x, y), original)`<br><br>What ideas can you come up with for patch(x, y)?

Comments (8) 13295 👁️