Skip to content

Commit

Permalink
Merge pull request #703 from streamich/fix-builder-clock
Browse files Browse the repository at this point in the history
Fix API `NodeBuilder` detached clock
  • Loading branch information
streamich authored Sep 17, 2024
2 parents 6fe2faf + 7ce486d commit 51e47aa
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/json-crdt-patch/PatchBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class PatchBuilder {
*
* @param clock Clock to use for generating timestamps.
*/
constructor(public readonly clock: IClock) {
constructor(public clock: IClock) {
this.patch = new Patch();
}

Expand Down
2 changes: 2 additions & 0 deletions src/json-crdt-patch/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export const enum SESSION {
* attributing it to any specific user. For example, when the initial document
* is created, the default patch can be applied on all clients to result in
* the same initial state on all clients.
*
* @todo Rename or alias this to `SCHEMA`.
*/
GLOBAL = 2,

Expand Down
9 changes: 7 additions & 2 deletions src/json-crdt/model/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ export class Model<N extends JsonNode = JsonNode<any>> implements Printable {

/**
* Applies a single patch to the document. All mutations to the model must go
* through this method.
* through this method. (With the only exception of local changes through API,
* which have an alternative path.)
*/
public applyPatch(patch: Patch) {
this.onbeforepatch?.(patch);
Expand Down Expand Up @@ -492,7 +493,11 @@ export class Model<N extends JsonNode = JsonNode<any>> implements Printable {
decoder.decode(blob, <any>this);
this.clock = to.clock.clone();
this.ext = to.ext.clone();
this._api?.flush();
const api = this._api;
if (api) {
api.flush();
api.builder.clock = this.clock;
}
index.forEach(({v: node}) => {
const api = node.api as NodeApi | undefined;
if (!api) return;
Expand Down
15 changes: 15 additions & 0 deletions src/json-crdt/model/__tests__/Model.cloning.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,19 @@ describe('reset()', () => {
doc1.reset(doc2);
expect(str.view()).toBe('hello');
});

test('uses the same clock in Model and NodeBuilder', async () => {
const doc1 = Model.create().setSchema(
schema.obj({
text: schema.str('hell'),
}),
);
const doc2 = doc1.fork();
doc2.s.text.toApi().ins(4, 'o');
expect(doc1.clock).toBe(doc1.api.builder.clock);
expect(doc2.clock).toBe(doc2.api.builder.clock);
doc1.reset(doc2);
expect(doc1.clock).toBe(doc1.api.builder.clock);
expect(doc2.clock).toBe(doc2.api.builder.clock);
});
});
2 changes: 2 additions & 0 deletions src/json-crdt/nodes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export interface JsonNode<View = unknown> extends Identifiable {

/**
* Returns a list of immediate child nodes.
*
* @todo: Use `UndefIterator` interface here.
*/
children(callback: (node: JsonNode) => void): void;

Expand Down

0 comments on commit 51e47aa

Please sign in to comment.