-
-
Notifications
You must be signed in to change notification settings - Fork 20
Description
Hello,
After computing an RFC 6902 JSON Patch, it appears that operations on the contents of vec nodes cannot be applied to a JSON CRDT model, resulting in a thrown error.
Here is a minimum reproducible example script:
import { Model } from "json-joy/lib/json-crdt";
import { JsonPatch } from "json-joy/lib/json-crdt/json-patch";
import { JsonPatchDiff } from "json-joy/lib/json-patch-diff/JsonPatchDiff";
import { s } from "json-joy/lib/json-crdt-patch";
const schema = s.obj({ vector: s.vec() });
const model1 = Model.create(schema).fork(1);
model1.api.vec(["vector"]).push(s.con("a"));
model1.api.vec(["vector"]).push(s.con("b"));
model1.api.vec(["vector"]).push(s.con("c"));
const model2 = Model.create(schema).fork(2);
model2.api.vec(["vector"]).push(s.con("x"));
model2.api.vec(["vector"]).push(s.con("y"));
model2.api.vec(["vector"]).push(s.con("z"));
model1.api.flush();
const differ = new JsonPatchDiff();
const patch = differ.diff(
"",
model1.api.getSnapshot(),
model2.api.getSnapshot(),
);
const patcher = new JsonPatch(model1);
console.log(patch);
patcher.apply(patch);Output:
[
{ op: 'str_ins', path: '/vector/2', pos: 1, str: 'z' },
{ op: 'str_del', path: '/vector/2', pos: 0, len: 1, str: 'c' },
{ op: 'str_ins', path: '/vector/1', pos: 1, str: 'y' },
{ op: 'str_del', path: '/vector/1', pos: 0, len: 1, str: 'b' },
{ op: 'str_ins', path: '/vector/0', pos: 1, str: 'x' },
{ op: 'str_del', path: '/vector/0', pos: 0, len: 1, str: 'a' }
]
<redacted>/node_modules/.pnpm/[email protected][email protected][email protected][email protected][email protected][email protected]/node_modules/json-joy/lib/json-crdt/json-patch/JsonPatch.js:157
throw new Error('NOT_FOUND');
^
Error: NOT_FOUND
at JsonPatch.strIns (<redacted>/node_modules/.pnpm/[email protected][email protected][email protected][email protected][email protected][email protected]/node_modules/json-joy/src/json-crdt/json-patch/JsonPatch.ts:150:43)
at JsonPatch.applyOp (<redacted>/node_modules/.pnpm/[email protected][email protected][email protected][email protected][email protected][email protected]/node_modules/json-joy/src/json-crdt/json-patch/JsonPatch.ts:46:14)
at <anonymous> (<redacted>/node_modules/.pnpm/[email protected][email protected][email protected][email protected][email protected][email protected]/node_modules/json-joy/src/json-crdt/json-patch/JsonPatch.ts:20:45)
at ModelApi.transaction (<redacted>/node_modules/.pnpm/[email protected][email protected][email protected][email protected][email protected][email protected]/node_modules/json-joy/src/json-crdt/model/api/nodes.ts:990:9)
at JsonPatch.apply (<redacted>/node_modules/.pnpm/[email protected][email protected][email protected][email protected][email protected][email protected]/node_modules/json-joy/src/json-crdt/json-patch/JsonPatch.ts:19:20)
at <anonymous> (<redacted>/src/snapshot-test/vectorPatchMinRepro.ts:30:9)
at ModuleJob.run (node:internal/modules/esm/module_job:274:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:644:26)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:117:5)
Node.js v22.16.0
Is this a bug, or a technical limitation due to the limited set of operations supported by vec nodes?
For context, we are trying to implement 'snapshot' or 'time-travel' functionality. The idea is that a database would persist an object representing a previous state of the CRDT model. A replica could load this object and compute a JSON Patch comparing the current model.view with the previous state, then apply the JSON Patch to the model to achieve the desired state (producing a patch that can be consumed by other replicas). Is there a more straightforward way we could achieve this?