@dxos/echo-pipeline 0.1.57-main.6b5f268 → 0.1.57-main.b6e249b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,10 @@
1
+ import { DocumentModel } from '@dxos/document-model';
1
2
  import { DatabaseProxy, ItemManager } from '@dxos/echo-db';
2
3
  import { PublicKey } from '@dxos/keys';
3
4
  import { ModelFactory } from '@dxos/model-factory';
4
5
  import { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
5
6
  import { EchoSnapshot, SpaceSnapshot } from '@dxos/protocols/proto/dxos/echo/snapshot';
7
+ import { TextModel } from '@dxos/text-model';
6
8
  import { Timeframe } from '@dxos/timeframe';
7
9
  import { ComplexMap } from '@dxos/util';
8
10
  import { DatabaseHost } from '../db-host';
@@ -59,5 +61,6 @@ export declare class DatabaseTestPeer {
59
61
  */
60
62
  private _getHeads;
61
63
  private _processMessages;
64
+ getModel(id: string): DocumentModel | TextModel | undefined;
62
65
  }
63
66
  //# sourceMappingURL=database-test-rig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"database-test-rig.d.ts","sourceRoot":"","sources":["../../../../src/testing/database-test-rig.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAGvF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI1C,qBAAa,mBAAmB;IAC9B,SAAgB,KAAK,0CAA+D;IAE9E,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAM9C;AAQD,qBAAa,gBAAgB;aAoCC,GAAG,EAAE,mBAAmB;IAnCpD,SAAgB,YAAY,eAA4E;IAEjG,KAAK,EAAG,WAAW,CAAC;IACpB,KAAK,EAAG,aAAa,CAAC;IAEtB,IAAI,EAAG,YAAY,CAAC;IACpB,SAAS,EAAG,WAAW,CAAC;IAM/B,SAAgB,GAAG,YAAsB;IAElC,YAAY,EAAE,WAAW,EAAE,CAAM;IAExC,SAAgB,SAAS,6BAAoC;IAC7D,OAAO,CAAC,YAAY,CAAC,CAAQ;IAE7B;;OAEG;IACI,SAAS,SAAM;IAEtB;;OAEG;IACI,SAAS,YAAmB;IAE5B,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC;IAE3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAE1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;gBAEvB,GAAG,EAAE,mBAAmB;IAE9C,IAAI;IAoCV;;;OAGG;IACG,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM;IAe1B;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,EAAE,SAAS;IAUxB;;OAEG;IACG,MAAM;IAOZ;;OAEG;IACH,YAAY,IAAI,aAAa;IAS7B,WAAW,CAAC,YAAY,CAAC,EAAE,YAAY;IAqBvC;;;OAGG;IACH,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,gBAAgB;CAmCzB"}
1
+ {"version":3,"file":"database-test-rig.d.ts","sourceRoot":"","sources":["../../../../src/testing/database-test-rig.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,WAAW,EAA4C,MAAM,eAAe,CAAC;AAGrG,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAEvF,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI1C,qBAAa,mBAAmB;IAC9B,SAAgB,KAAK,0CAA+D;IAE9E,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAM9C;AAQD,qBAAa,gBAAgB;aAoCC,GAAG,EAAE,mBAAmB;IAnCpD,SAAgB,YAAY,eAA4E;IAEjG,KAAK,EAAG,WAAW,CAAC;IACpB,KAAK,EAAG,aAAa,CAAC;IAEtB,IAAI,EAAG,YAAY,CAAC;IACpB,SAAS,EAAG,WAAW,CAAC;IAM/B,SAAgB,GAAG,YAAsB;IAElC,YAAY,EAAE,WAAW,EAAE,CAAM;IAExC,SAAgB,SAAS,6BAAoC;IAC7D,OAAO,CAAC,YAAY,CAAC,CAAQ;IAE7B;;OAEG;IACI,SAAS,SAAM;IAEtB;;OAEG;IACI,SAAS,YAAmB;IAE5B,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC;IAE3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAE1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;gBAEvB,GAAG,EAAE,mBAAmB;IAE9C,IAAI;IAoCV;;;OAGG;IACG,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM;IAe1B;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,EAAE,SAAS;IAUxB;;OAEG;IACG,MAAM;IAOZ;;OAEG;IACH,YAAY,IAAI,aAAa;IAS7B,WAAW,CAAC,YAAY,CAAC,EAAE,YAAY;IAqBvC;;;OAGG;IACH,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,gBAAgB;IAoCxB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,GAAG,SAAS;CA4B5D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/echo-pipeline",
3
- "version": "0.1.57-main.6b5f268",
3
+ "version": "0.1.57-main.b6e249b",
4
4
  "description": "ECHO database.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -20,43 +20,43 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "crc-32": "^1.2.2",
23
- "@dxos/async": "0.1.57-main.6b5f268",
24
- "@dxos/codec-protobuf": "0.1.57-main.6b5f268",
25
- "@dxos/context": "0.1.57-main.6b5f268",
26
- "@dxos/credentials": "0.1.57-main.6b5f268",
27
- "@dxos/crypto": "0.1.57-main.6b5f268",
28
- "@dxos/debug": "0.1.57-main.6b5f268",
29
- "@dxos/document-model": "0.1.57-main.6b5f268",
30
- "@dxos/echo-db": "0.1.57-main.6b5f268",
31
- "@dxos/errors": "0.1.57-main.6b5f268",
32
- "@dxos/feed-store": "0.1.57-main.6b5f268",
33
- "@dxos/hypercore": "0.1.57-main.6b5f268",
34
- "@dxos/invariant": "0.1.57-main.6b5f268",
35
- "@dxos/keyring": "0.1.57-main.6b5f268",
36
- "@dxos/keys": "0.1.57-main.6b5f268",
37
- "@dxos/log": "0.1.57-main.6b5f268",
38
- "@dxos/messaging": "0.1.57-main.6b5f268",
39
- "@dxos/model-factory": "0.1.57-main.6b5f268",
40
- "@dxos/network-manager": "0.1.57-main.6b5f268",
41
- "@dxos/node-std": "0.1.57-main.6b5f268",
42
- "@dxos/protocols": "0.1.57-main.6b5f268",
43
- "@dxos/random-access-storage": "0.1.57-main.6b5f268",
44
- "@dxos/rpc": "0.1.57-main.6b5f268",
45
- "@dxos/teleport": "0.1.57-main.6b5f268",
46
- "@dxos/teleport-extension-gossip": "0.1.57-main.6b5f268",
47
- "@dxos/teleport-extension-object-sync": "0.1.57-main.6b5f268",
48
- "@dxos/teleport-extension-replicator": "0.1.57-main.6b5f268",
49
- "@dxos/timeframe": "0.1.57-main.6b5f268",
50
- "@dxos/tracing": "0.1.57-main.6b5f268",
51
- "@dxos/typings": "0.1.57-main.6b5f268",
52
- "@dxos/util": "0.1.57-main.6b5f268"
23
+ "@dxos/async": "0.1.57-main.b6e249b",
24
+ "@dxos/codec-protobuf": "0.1.57-main.b6e249b",
25
+ "@dxos/context": "0.1.57-main.b6e249b",
26
+ "@dxos/credentials": "0.1.57-main.b6e249b",
27
+ "@dxos/crypto": "0.1.57-main.b6e249b",
28
+ "@dxos/debug": "0.1.57-main.b6e249b",
29
+ "@dxos/document-model": "0.1.57-main.b6e249b",
30
+ "@dxos/echo-db": "0.1.57-main.b6e249b",
31
+ "@dxos/errors": "0.1.57-main.b6e249b",
32
+ "@dxos/feed-store": "0.1.57-main.b6e249b",
33
+ "@dxos/hypercore": "0.1.57-main.b6e249b",
34
+ "@dxos/invariant": "0.1.57-main.b6e249b",
35
+ "@dxos/keyring": "0.1.57-main.b6e249b",
36
+ "@dxos/keys": "0.1.57-main.b6e249b",
37
+ "@dxos/log": "0.1.57-main.b6e249b",
38
+ "@dxos/messaging": "0.1.57-main.b6e249b",
39
+ "@dxos/model-factory": "0.1.57-main.b6e249b",
40
+ "@dxos/network-manager": "0.1.57-main.b6e249b",
41
+ "@dxos/node-std": "0.1.57-main.b6e249b",
42
+ "@dxos/protocols": "0.1.57-main.b6e249b",
43
+ "@dxos/random-access-storage": "0.1.57-main.b6e249b",
44
+ "@dxos/rpc": "0.1.57-main.b6e249b",
45
+ "@dxos/teleport": "0.1.57-main.b6e249b",
46
+ "@dxos/teleport-extension-gossip": "0.1.57-main.b6e249b",
47
+ "@dxos/teleport-extension-object-sync": "0.1.57-main.b6e249b",
48
+ "@dxos/teleport-extension-replicator": "0.1.57-main.b6e249b",
49
+ "@dxos/timeframe": "0.1.57-main.b6e249b",
50
+ "@dxos/tracing": "0.1.57-main.b6e249b",
51
+ "@dxos/typings": "0.1.57-main.b6e249b",
52
+ "@dxos/util": "0.1.57-main.b6e249b"
53
53
  },
54
54
  "devDependencies": {
55
55
  "fast-check": "~3.3.0",
56
56
  "hypercore-protocol": "^8.0.7",
57
57
  "source-map-support": "^0.5.12",
58
58
  "wait-for-expect": "^3.0.2",
59
- "@dxos/text-model": "0.1.57-main.6b5f268"
59
+ "@dxos/text-model": "0.1.57-main.b6e249b"
60
60
  },
61
61
  "publishConfig": {
62
62
  "access": "public"
@@ -4,8 +4,9 @@
4
4
 
5
5
  import { Event, Trigger } from '@dxos/async';
6
6
  import { DocumentModel } from '@dxos/document-model';
7
- import { DatabaseProxy, ItemManager } from '@dxos/echo-db';
7
+ import { DatabaseProxy, ItemManager, createModelMutation, encodeModelMutation } from '@dxos/echo-db';
8
8
  import { WriteOptions, WriteReceipt } from '@dxos/feed-store';
9
+ import { invariant } from '@dxos/invariant';
9
10
  import { PublicKey } from '@dxos/keys';
10
11
  import { ModelFactory } from '@dxos/model-factory';
11
12
  import { FeedMessageBlock, schema } from '@dxos/protocols';
@@ -242,4 +243,33 @@ export class DatabaseTestPeer {
242
243
  }
243
244
  }
244
245
  }
246
+
247
+ getModel(id: string): DocumentModel | TextModel | undefined {
248
+ const item = this.items.getItem(id);
249
+ if (!item) {
250
+ return;
251
+ }
252
+
253
+ invariant(item.modelMeta);
254
+ const ModelConstructor = this.modelFactory.getModel(item.modelMeta.type)?.constructor;
255
+ invariant(ModelConstructor);
256
+
257
+ const model = new ModelConstructor(
258
+ item.modelMeta,
259
+ item.id,
260
+ () => item.state,
261
+ async (mutation) => {
262
+ invariant(item.modelMeta);
263
+ this.proxy.mutate(createModelMutation(id, encodeModelMutation(item.modelMeta, mutation)));
264
+ return {
265
+ feedKey: PublicKey.from('00'),
266
+ seq: 0,
267
+ waitToBeProcessed: () => Promise.resolve(),
268
+ };
269
+ },
270
+ );
271
+ model.initialize();
272
+
273
+ return model;
274
+ }
245
275
  }
@@ -4,10 +4,13 @@
4
4
 
5
5
  import expect from 'expect';
6
6
 
7
+ import { sleep } from '@dxos/async';
7
8
  import { DocumentModel, MutationBuilder, OrderedArray } from '@dxos/document-model';
8
- import { Item, createModelMutation, encodeModelMutation, genesisMutation } from '@dxos/echo-db';
9
+ import { BATCH_COMMIT_AFTER, Item, createModelMutation, encodeModelMutation, genesisMutation } from '@dxos/echo-db';
10
+ import { invariant } from '@dxos/invariant';
9
11
  import { PublicKey } from '@dxos/keys';
10
12
  import { describe, test } from '@dxos/test';
13
+ import { Doc, TextModel } from '@dxos/text-model';
11
14
  import { Timeframe } from '@dxos/timeframe';
12
15
 
13
16
  import { DatabaseTestBuilder } from '../testing/database-test-rig';
@@ -19,11 +22,13 @@ describe('database (unit)', () => {
19
22
 
20
23
  const id = PublicKey.random().toHex();
21
24
  peer.proxy.mutate(genesisMutation(id, DocumentModel.meta.type));
25
+ peer.proxy.commitBatch();
22
26
  peer.proxy.mutate(
23
27
  createModelMutation(id, encodeModelMutation(DocumentModel.meta, new MutationBuilder().set('test', 42).build())),
24
28
  );
25
-
29
+ peer.proxy.commitBatch();
26
30
  await peer.confirm();
31
+
27
32
  expect(peer.confirmed).toEqual(1);
28
33
  expect(peer.timeframe).toEqual(new Timeframe([[peer.key, 1]]));
29
34
 
@@ -43,10 +48,13 @@ describe('database (unit)', () => {
43
48
 
44
49
  const id = PublicKey.random().toHex();
45
50
  peer.proxy.mutate(genesisMutation(id, DocumentModel.meta.type));
51
+ peer.proxy.commitBatch();
52
+
46
53
  peer.proxy.mutate(
47
54
  createModelMutation(id, encodeModelMutation(DocumentModel.meta, new MutationBuilder().set('test', 42).build())),
48
55
  );
49
56
 
57
+ peer.proxy.commitBatch();
50
58
  await peer.confirm();
51
59
  expect(peer.confirmed).toEqual(1);
52
60
  expect(peer.timeframe).toEqual(new Timeframe([[peer.key, 1]]));
@@ -72,6 +80,7 @@ describe('database (unit)', () => {
72
80
  peer1.proxy.mutate(
73
81
  createModelMutation(id, encodeModelMutation(DocumentModel.meta, new MutationBuilder().set('test', 42).build())),
74
82
  );
83
+ peer1.proxy.commitBatch();
75
84
  await peer1.confirm();
76
85
 
77
86
  peer2.replicate(peer1.timeframe);
@@ -159,15 +168,123 @@ describe('database (unit)', () => {
159
168
  });
160
169
  });
161
170
 
171
+ describe('TextModel', () => {
172
+ test('insert', async () => {
173
+ const rig = new DatabaseTestBuilder();
174
+ const peer1 = await rig.createPeer();
175
+ const peer2 = await rig.createPeer();
176
+
177
+ const mutations = [];
178
+ const doc = new Doc();
179
+ doc.on('update', (update) => {
180
+ mutations.push(update);
181
+ });
182
+
183
+ const id = PublicKey.random().toHex();
184
+ peer1.proxy.mutate(genesisMutation(id, TextModel.meta.type));
185
+ const model = peer1.getModel(id);
186
+ invariant(model instanceof TextModel);
187
+ model.insert('Hello World!', 0);
188
+
189
+ peer1.proxy.commitBatch();
190
+ await peer1.confirm();
191
+ await peer1.proxy.flush();
192
+
193
+ peer2.replicate(peer1.timeframe);
194
+ const replicatedItem = peer2.items.entities.get(id);
195
+ expect(replicatedItem).toBeDefined();
196
+ const replicatedModel = peer2.getModel(id)! as TextModel;
197
+ expect(replicatedModel.textContent).toBe('Hello World!');
198
+
199
+ replicatedModel.insert(' DXOS', 5);
200
+
201
+ peer2.proxy.commitBatch();
202
+ await peer2.confirm();
203
+ await peer2.proxy.flush();
204
+
205
+ peer1.replicate(peer2.timeframe);
206
+ expect(model.textContent).toBe('Hello DXOS World!');
207
+ });
208
+ });
209
+
210
+ describe('Mutations merging', () => {
211
+ test('merge EchoObject-s for one item', async () => {
212
+ const rig = new DatabaseTestBuilder();
213
+ const peer1 = await rig.createPeer();
214
+ const peer2 = await rig.createPeer();
215
+
216
+ const mutations = [];
217
+ const doc = new Doc();
218
+ doc.on('update', (update) => {
219
+ mutations.push(update);
220
+ });
221
+
222
+ const id = PublicKey.random().toHex();
223
+ const begin = peer1.proxy.beginBatch();
224
+ expect(begin).toBeTruthy();
225
+ peer1.proxy.mutate(genesisMutation(id, TextModel.meta.type));
226
+ const model = peer1.getModel(id);
227
+ invariant(model instanceof TextModel);
228
+ model.insert('Hello', 0);
229
+ model.insert(' World!', 5);
230
+
231
+ peer1.proxy.commitBatch();
232
+ await peer1.confirm();
233
+
234
+ // Mutations got merged.
235
+ expect(peer1.feedMessages.length).toEqual(1);
236
+
237
+ peer2.replicate(peer1.timeframe);
238
+
239
+ const replicatedItem = peer2.items.entities.get(id);
240
+ expect(replicatedItem).toBeDefined();
241
+ const replicatedModel = peer2.getModel(id)! as TextModel;
242
+ expect(replicatedModel.textContent).toBe('Hello World!');
243
+
244
+ replicatedModel.insert(' DXOS', 5);
245
+ peer2.proxy.commitBatch();
246
+ await peer2.confirm();
247
+
248
+ peer1.replicate(peer2.timeframe);
249
+ expect(model.textContent).toBe('Hello DXOS World!');
250
+ });
251
+
252
+ test('consecutive mutations are batched', async () => {
253
+ const rig = new DatabaseTestBuilder();
254
+ const peer = await rig.createPeer();
255
+
256
+ const id = PublicKey.random().toHex();
257
+ peer.proxy.mutate(genesisMutation(id, TextModel.meta.type));
258
+ const model = peer.getModel(id);
259
+ invariant(model instanceof TextModel);
260
+ model.insert('Hello', 0);
261
+ model.insert(' World!', 5);
262
+ // Wait for batch commit.
263
+ await sleep(BATCH_COMMIT_AFTER + 10);
264
+
265
+ // Mutations got merged.
266
+ expect(peer.feedMessages.length).toEqual(1);
267
+
268
+ model.insert(' DXOS', 5);
269
+ // New batch is still not committed.
270
+ expect(peer.feedMessages.length).toEqual(1);
271
+ await sleep(BATCH_COMMIT_AFTER + 10);
272
+ // New batch is committed.
273
+ expect(peer.feedMessages.length).toEqual(2);
274
+ });
275
+ });
276
+
162
277
  it('epoch correctly resets items', async () => {
163
278
  const builder = new DatabaseTestBuilder();
164
279
  const peer = await builder.createPeer();
165
280
 
166
281
  const id = PublicKey.random().toHex();
167
282
  peer.proxy.mutate(genesisMutation(id, DocumentModel.meta.type));
283
+ peer.proxy.commitBatch();
168
284
  peer.proxy.mutate(
169
285
  createModelMutation(id, encodeModelMutation(DocumentModel.meta, new MutationBuilder().set('test', 42).build())),
170
286
  );
287
+ peer.proxy.commitBatch();
171
288
 
172
289
  await peer.confirm();
173
290
  expect(peer.confirmed).toEqual(1);
@@ -58,6 +58,7 @@ describe('database', () => {
58
58
  const result = database.backend.mutate(genesisMutation(PublicKey.random().toHex(), DocumentModel.meta.type));
59
59
  expect(result.objectsUpdated.length).toEqual(1);
60
60
  expect(database.itemManager.entities.has(result.objectsUpdated[0].id));
61
+ database.backend.commitBatch();
61
62
 
62
63
  await result.batch.waitToBeProcessed();
63
64
  expect(database.itemManager.entities.has(result.objectsUpdated[0].id));
@@ -72,6 +73,7 @@ describe('database', () => {
72
73
  createModelMutation(id, encodeModelMutation(DocumentModel.meta, new MutationBuilder().set('test', 42).build())),
73
74
  );
74
75
  expect(database.itemManager.getItem(id)!.state.data.test).toEqual(42);
76
+ database.backend.commitBatch();
75
77
 
76
78
  await result.batch.waitToBeProcessed();
77
79
  expect(database.itemManager.getItem(id)!.state.data.test).toEqual(42);