Skip to content

Commit d6d564d

Browse files
committed
feat(json-crdt): 🎸 implement "arr" node undo
1 parent c33a0a5 commit d6d564d

File tree

2 files changed

+40
-7
lines changed

2 files changed

+40
-7
lines changed

src/json-crdt/log/Log.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
Timespan,
1818
compare,
1919
} from '../../json-crdt-patch';
20-
import {BinNode, ObjNode, StrNode, ValNode, VecNode} from '../nodes';
20+
import {ArrNode, BinNode, ObjNode, StrNode, ValNode, VecNode} from '../nodes';
2121
import type {FanOutUnsubscribe} from 'thingies/lib/fanout';
2222
import type {Printable} from 'tree-dump/lib/types';
2323
import type {JsonNode} from '../nodes/types';
@@ -195,7 +195,7 @@ export class Log<N extends JsonNode = JsonNode<any>> implements Printable {
195195
continue;
196196
}
197197
const model = getModel();
198-
// TODO: Do not overwrite already deleted values? Or needed for concurrency?
198+
// TODO: Do not overwrite already deleted values? Or needed for concurrency? Orphaned nodes.
199199
if (op instanceof InsValOp) {
200200
const val = model.index.get(op.obj);
201201
if (val instanceof ValNode) {
@@ -247,6 +247,28 @@ export class Log<N extends JsonNode = JsonNode<any>> implements Printable {
247247
}
248248
const blob = listToUint8(buffers);
249249
builder.insBin(op.obj, after, blob);
250+
} else if (rga instanceof ArrNode) {
251+
const copies: ITimestampStruct[] = [];
252+
for (const span of op.what) {
253+
const ids2 = rga.spanView(span);
254+
for (const ids of ids2) {
255+
for (const id of ids) {
256+
const node = model.index.get(id);
257+
if (node) {
258+
const schema = toSchema(node);
259+
const newId = schema.build(builder);
260+
copies.push(newId);
261+
}
262+
}
263+
}
264+
}
265+
let after = op.obj;
266+
const firstDelSpan = op.what[0];
267+
if (firstDelSpan) {
268+
const after2 = rga.prevId(firstDelSpan);
269+
if (after2) after = after2;
270+
}
271+
builder.insArr(op.obj, after, copies);
250272
}
251273
}
252274
}

src/json-crdt/log/__tests__/Log.spec.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,17 @@ describe('.undo()', () => {
200200
log.end.applyPatch(undo);
201201
expect(log.end.view()).toEqual({bin: new Uint8Array([])});
202202
});
203+
204+
test('can undo blob delete', () => {
205+
const {log} = setup({bin: new Uint8Array([1, 2, 3])});
206+
log.end.api.flush();
207+
log.end.api.bin(['bin']).del(1, 1);
208+
const patch = log.end.api.flush();
209+
const undo = log.undo(patch);
210+
expect(log.end.view()).toEqual({bin: new Uint8Array([1, 3])});
211+
log.end.applyPatch(undo);
212+
expect(log.end.view()).toEqual({bin: new Uint8Array([1, 2, 3])});
213+
});
203214
});
204215

205216
describe('arr', () => {
@@ -224,15 +235,15 @@ describe('.undo()', () => {
224235
expect(log.end.view()).toEqual({arr: []});
225236
});
226237

227-
test('can undo blob delete', () => {
228-
const {log} = setup({bin: new Uint8Array([1, 2, 3])});
238+
test('can undo "arr" delete', () => {
239+
const {log} = setup({arr: [{a: 1}, {a: 2}, {a: 3}]});
229240
log.end.api.flush();
230-
log.end.api.bin(['bin']).del(1, 1);
241+
log.end.api.arr(['arr']).del(1, 1);
231242
const patch = log.end.api.flush();
232243
const undo = log.undo(patch);
233-
expect(log.end.view()).toEqual({bin: new Uint8Array([1, 3])});
244+
expect(log.end.view()).toEqual({arr: [{a: 1}, {a: 3}]});
234245
log.end.applyPatch(undo);
235-
expect(log.end.view()).toEqual({bin: new Uint8Array([1, 2, 3])});
246+
expect(log.end.view()).toEqual({arr: [{a: 1}, {a: 2}, {a: 3}]});
236247
});
237248
});
238249
});

0 commit comments

Comments
 (0)