Skip to content

Commit 5121fab

Browse files
authored
Merge pull request #605 from streamich/global-schema
JSON CRDT: use global session ID for default value
2 parents f3d2298 + cc7ba8d commit 5121fab

File tree

5 files changed

+85
-33
lines changed

5 files changed

+85
-33
lines changed

src/json-crdt-extensions/peritext/util/__tests__/ChunkSlice.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {Model} from '../../../../json-crdt/model';
33
import {ChunkSlice} from '../ChunkSlice';
44

55
const setup = () => {
6-
const model = Model.withLogicalClock().setSchema(s.str('Hello world'));
6+
const model = Model.withLogicalClock().setSchema(s.str('Hello world'), false);
77
const node = model.root.node();
88
const chunk = node.first()!;
99
return {

src/json-crdt-patch/clock/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export interface ITimestampStruct {
88
* Session ID (or actor ID, site ID, process ID, etc.), a random identifier
99
* randomly assigned to each editing session.
1010
*/
11-
readonly sid: number;
11+
sid: number;
1212

1313
/**
1414
* Logical time (or sequence number, tick, etc.), a monotonically increasing

src/json-crdt/model/Model.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,10 +396,24 @@ export class Model<N extends JsonNode = JsonNode<any>> implements Printable {
396396
* the document is empty.
397397
*
398398
* @param schema The schema to set for this model.
399+
* @param sid Session ID to use for setting the default value of the document.
400+
* Defaults to `SESSION.GLOBAL` (2), which is the default session ID
401+
* for all operations operations that are not attributed to a specific
402+
* session.
399403
* @returns Strictly typed model.
400404
*/
401-
public setSchema<S extends NodeBuilder>(schema: S): Model<SchemaToJsonNode<S>> {
402-
if (this.clock.time < 2) this.api.root(schema);
405+
public setSchema<S extends NodeBuilder>(schema: S, useGlobalSession: boolean = true): Model<SchemaToJsonNode<S>> {
406+
const c = this.clock;
407+
const isNewDocument = c.time === 1;
408+
if (isNewDocument) {
409+
const oldSid = c.sid;
410+
if (useGlobalSession) c.sid = SESSION.GLOBAL;
411+
this.api.root(schema);
412+
if (useGlobalSession) {
413+
c.sid = oldSid;
414+
c.observe(new clock.Timestamp(SESSION.GLOBAL, c.time - 1), 1);
415+
}
416+
}
403417
return <any>this;
404418
}
405419

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

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {nodes, s} from '../../../json-crdt-patch';
2+
import {SESSION} from '../../../json-crdt-patch/constants';
3+
import {Model} from '../Model';
4+
5+
test('can set object schema', () => {
6+
const model = Model.withLogicalClock().setSchema(
7+
s.obj({
8+
str: s.str('asdf'),
9+
con: s.con(123),
10+
}),
11+
);
12+
expect(model.s.str.toApi().view()).toBe('asdf');
13+
expect(model.s.con.toApi().view()).toBe(123);
14+
});
15+
16+
test('can set map schema', () => {
17+
const model = Model.withLogicalClock().setSchema(
18+
s.map<nodes.str | nodes.con<number>>({
19+
str: s.str('asdf'),
20+
con1: s.con(123),
21+
}),
22+
);
23+
expect(model.s.str.toApi().view()).toBe('asdf');
24+
expect(model.s.con1.toApi().view()).toBe(123);
25+
expect(model.view().str).toBe('asdf');
26+
expect(model.view().con1).toBe(123);
27+
expect(model.view().anyKeyAllowed).toBe(undefined);
28+
});
29+
30+
test('uses global session ID by default', () => {
31+
const model = Model.withLogicalClock().setSchema(
32+
s.obj({
33+
id: s.str<string>('asdf'),
34+
num: s.con(123),
35+
}),
36+
);
37+
expect(model.api.r.get().node.id.sid).toBe(SESSION.GLOBAL);
38+
expect(model.api.r.get().get('id').node.id.sid).toBe(SESSION.GLOBAL);
39+
expect(model.api.r.get().get('num').node.id.sid).toBe(SESSION.GLOBAL);
40+
});
41+
42+
test('allows to specify custom session ID', () => {
43+
const schema = s.obj({
44+
id: s.str<string>('asdf'),
45+
num: s.con(123),
46+
});
47+
const model = Model.withLogicalClock().setSchema(schema, false);
48+
expect(model.api.r.get().node.id.sid).toBe(model.clock.sid);
49+
expect(model.api.r.get().get('id').node.id.sid).toBe(model.clock.sid);
50+
expect(model.api.r.get().get('num').node.id.sid).toBe(model.clock.sid);
51+
});
52+
53+
test('resets session ID to user specified', () => {
54+
const model = Model.withLogicalClock().setSchema(
55+
s.obj({
56+
id: s.str<string>('asdf'),
57+
num: s.con(123),
58+
}),
59+
);
60+
expect(model.view().num).toBe(123);
61+
expect(model.api.r.get().get('num').node.id.sid).toBe(SESSION.GLOBAL);
62+
model.api.r.get().set({
63+
num: 456,
64+
});
65+
expect(model.view().num).toBe(456);
66+
expect(model.api.r.get().get('num').node.id.sid).not.toBe(SESSION.GLOBAL);
67+
});

0 commit comments

Comments
 (0)