Structural JSON diff/patch for MoonBit — compute and apply PatchOp sequences between Json trees
let new_remote = @recollect.apply_to_value(old_remote, patches)
catch { _ => old_remote }
// old_remote is still untouchedDo not keep your app state inside a mutable wrapper and patch it in place. Replace the whole value with the newly returned one, otherwise structural equality-based update logic may stop working correctly.
import {
"tiye/recollect" @recollect,
}let before : Json = {
"todos": [{ "id": "t-1", "title": "A", "done": false }],
}
let after : Json = {
"todos": [
{ "id": "t-1", "title": "A", "done": true },
{ "id": "t-2", "title": "B", "done": false },
],
}
let patches = @recollect.diff_json(before, after)
let rebuilt = @recollect.apply_patches(before, patches)
// rebuilt == afterstruct Todo {
id : String
title : String
done : Bool
} derive(FromJson, ToJson)
struct AppState {
todos : Array[Todo]
} derive(FromJson, ToJson)
let before = AppState::{ todos: [{ id: "t-1", title: "A", done: false }] }
let after = AppState::{ todos: [
{ id: "t-1", title: "A", done: true },
{ id: "t-2", title: "B", done: false },
] }
let patches = @recollect.diff_value(before, after)
let rebuilt : AppState = @recollect.apply_to_value(before, patches)
catch { _ => before }
// rebuilt == aftermoon check
moon testpub(all) enum PatchOp {
Set(Array[PathSegment], Json)
Remove(Array[PathSegment])
Insert(Array[PathSegment], Int, Json)
Delete(Array[PathSegment], Int)
Move(Array[PathSegment], Int, Int)
} derive(Eq, ToJson, Debug, FromJson)| Variant | Meaning |
|---|---|
| Set | Overwrite a value at path (creates intermediate nodes if absent) |
| Remove | Delete the field or array element addressed by path |
| Insert | Splice a new element into the array at path before index |
| Delete | Remove the element at index from the array at path |
| Move | Re-order an element within the array at path |
let new_json = apply_patches(old_json, diff_json(old_json, new_json))
assert_eq(new_json, new_json)fn[T : ToJson + FromJson] apply_to_value(value : T, patches : Array[PatchOp]) -> T raise JsonDecodeErrorlet new_remote = @recollect.apply_to_value(old_remote, patches)
catch { err => ... }let patches = diff_json(
{ "count": 1 },
{ "count": 2, "label": "hi" },
)
// patches: [Set(path=[Field("count")], value=2),
// Set(path=[Field("label")], value="hi")]struct Counter { value : Int } derive(ToJson)
let patches = diff_value({ value: 1 }, { value: 2 })Install
Download zipStructural JSON diff/patch for MoonBit — compute and apply PatchOp sequences between Json trees