Skip to content

Commit f38c487

Browse files
committed
fix(json-crdt): 🐛 update "arr" element only when new ID is higher
1 parent 7d071f5 commit f38c487

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

src/json-crdt/model/__tests__/Model.array.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,19 @@ describe('Document', () => {
687687
expect(doc.view()).toEqual([1, 0, 3]);
688688
expect(indexSize0 - indexSize1).toBe(7);
689689
});
690+
691+
test('does not update "arr" element, if ID is lower than current', () => {
692+
const doc = Model.create([1, 2, 3]);
693+
const node = doc.root.child();
694+
const secondElementId = node.getId(1)!;
695+
const builder = new PatchBuilder(new ClockVector(1234567, 0));
696+
builder.flush();
697+
const constId = builder.con(0);
698+
builder.updArr(node.id, secondElementId, constId);
699+
const patch = builder.flush();
700+
doc.applyPatch(patch);
701+
expect(doc.view()).toEqual([1, 2, 3]);
702+
});
690703
});
691704
});
692705
});

src/json-crdt/nodes/arr/ArrNode.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {AbstractRga, type Chunk} from '../rga/AbstractRga';
2-
import {type ITimestampStruct, tick} from '../../../json-crdt-patch/clock';
2+
import {compare, type ITimestampStruct, tick} from '../../../json-crdt-patch/clock';
33
import {printBinary} from 'tree-dump/lib/printBinary';
44
import {printTree} from 'tree-dump/lib/printTree';
55
import type {Model} from '../../model';
@@ -115,6 +115,8 @@ export class ArrNode<Element extends JsonNode = JsonNode>
115115
* in the array. The ID is a timestamp the unique slot of the element in the RGA.
116116
* To retrieve the JSON node ID referenced by the slot, use {@link get} method.
117117
*
118+
* @todo Rename to `getRef`.
119+
*
118120
* @param position The position of the element to get.
119121
* @returns ID of the RGA slot.
120122
*/
@@ -133,16 +135,26 @@ export class ArrNode<Element extends JsonNode = JsonNode>
133135
return chunk.data![offset];
134136
}
135137

138+
/**
139+
* Updates an array element in-place. Used by the "upd_arr" operation.
140+
*
141+
* @todo Verify that the new ID is greater than the old ID.
142+
*
143+
* @param ref A reference to the element slot in the array.
144+
* @param val A new value to set in the slot.
145+
* @returns The old value of the slot, if any.
146+
*/
136147
public upd(ref: ITimestampStruct, val: ITimestampStruct): ITimestampStruct | undefined {
137148
const chunk = this.findById(ref);
138149
if (!chunk) return;
139150
const data = chunk.data;
140151
if (!data) return;
141152
const offset = ref.time - chunk.id.time;
142-
const oldVal = data[offset];
153+
const currentVal = data[offset];
154+
if (currentVal && compare(currentVal, val) >= 0) return;
143155
data[offset] = val;
144156
this.onChange();
145-
return oldVal;
157+
return currentVal;
146158
}
147159

148160
// -------------------------------------------------------------- AbstractRga

0 commit comments

Comments
 (0)