@arcote.tech/arc 0.0.13 → 0.0.14
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.
- package/dist/collection/collection-change.d.ts +1 -0
- package/dist/collection/collection.d.ts +35 -26
- package/dist/collection/db.d.ts +11 -12
- package/dist/collection/index.d.ts +1 -1
- package/dist/collection/queries/abstract-collection-query.d.ts +11 -14
- package/dist/collection/queries/abstract-many-items.d.ts +22 -13
- package/dist/collection/queries/all-items.d.ts +4 -3
- package/dist/collection/queries/indexed.d.ts +8 -8
- package/dist/collection/queries/one-item.d.ts +14 -6
- package/dist/collection/queries/util.d.ts +3 -6
- package/dist/collection/query-builders/abstract-many-items.d.ts +6 -6
- package/dist/collection/query-builders/all-items.d.ts +1 -0
- package/dist/collection/query-builders/indexed.d.ts +1 -0
- package/dist/collection/query-builders/one-item.d.ts +1 -0
- package/dist/context/commands.d.ts +3 -1
- package/dist/context/context.d.ts +13 -23
- package/dist/context/element.d.ts +7 -5
- package/dist/context/index.d.ts +4 -0
- package/dist/context/query-builders.d.ts +5 -2
- package/dist/context/query.d.ts +6 -2
- package/dist/data-storage/DataStorage.d.ts +11 -0
- package/dist/data-storage/ForkStoreState.d.ts +32 -0
- package/dist/data-storage/StoreState.d.ts +24 -0
- package/dist/data-storage/data-storage-forked.d.ts +16 -0
- package/dist/data-storage/data-storage-master.d.ts +20 -0
- package/dist/data-storage/data-storage.d.ts +2 -0
- package/dist/data-storage/data-storage.interface.d.ts +37 -0
- package/dist/data-storage/index.d.ts +7 -0
- package/dist/data-storage/master-store-state.d.ts +17 -0
- package/dist/data-storage/store-state-fork.d.ts +15 -0
- package/dist/data-storage/store-state-master.d.ts +14 -0
- package/dist/data-storage/store-state.abstract.d.ts +22 -0
- package/dist/data-storage/store-state.d.ts +24 -0
- package/dist/db/index.d.ts +2 -0
- package/dist/db/interface.d.ts +17 -0
- package/dist/elements/abstract-primitive.d.ts +1 -0
- package/dist/elements/abstract.d.ts +1 -0
- package/dist/elements/array.d.ts +1 -0
- package/dist/elements/boolean.d.ts +1 -0
- package/dist/elements/branded.d.ts +1 -0
- package/dist/elements/date.d.ts +1 -0
- package/dist/elements/default.d.ts +1 -0
- package/dist/elements/element.d.ts +1 -0
- package/dist/elements/id.d.ts +1 -0
- package/dist/elements/index.d.ts +1 -0
- package/dist/elements/number.d.ts +1 -0
- package/dist/elements/object.d.ts +1 -0
- package/dist/elements/optional.d.ts +1 -0
- package/dist/elements/string-enum.d.ts +1 -0
- package/dist/elements/string.d.ts +1 -0
- package/dist/elements/tests/object.test.d.ts +2 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +429 -396
- package/dist/model/model.d.ts +18 -19
- package/dist/rtc/client.d.ts +2 -1
- package/dist/rtc/deserializeChanges.d.ts +1 -0
- package/dist/rtc/index.d.ts +1 -0
- package/dist/rtc/messages.d.ts +6 -5
- package/dist/rtc/rtc.d.ts +6 -0
- package/dist/state/db.d.ts +14 -0
- package/dist/state/index.d.ts +3 -0
- package/dist/state/query-builder.d.ts +8 -0
- package/dist/state/query.d.ts +22 -0
- package/dist/state/state-change.d.ts +13 -0
- package/dist/state/state.d.ts +28 -0
- package/dist/state/util.d.ts +2 -0
- package/dist/utils.d.ts +17 -14
- package/package.json +2 -2
- package/dist/collection/in-memory-db-proxy.d.ts +0 -10
- package/dist/elements/instanceOf.d.ts +0 -19
- package/dist/elements/or.d.ts +0 -11
- package/dist/elements/recurent.d.ts +0 -20
- package/dist/model/index.d.ts +0 -4
- package/dist/model/query-builder.d.ts +0 -3
- package/dist/model/rtc.d.ts +0 -6
- package/dist/model/submodel.d.ts +0 -23
package/dist/index.js
CHANGED
|
@@ -1,48 +1,34 @@
|
|
|
1
|
-
// collection/collection.ts
|
|
2
|
-
import { apply } from "mutative";
|
|
3
|
-
|
|
4
1
|
// collection/queries/abstract-collection-query.ts
|
|
5
|
-
import { BehaviorSubject, debounceTime, Subject } from "rxjs";
|
|
6
|
-
|
|
7
2
|
class ArcCollectionQuery {
|
|
8
3
|
collection;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
subscriptions = [];
|
|
4
|
+
lastResult;
|
|
5
|
+
listener;
|
|
12
6
|
constructor(collection) {
|
|
13
7
|
this.collection = collection;
|
|
14
8
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const result = await this.fetch(transaction);
|
|
23
|
-
this.resultQueue$ = new BehaviorSubject(result);
|
|
24
|
-
const subscriptionDebounce = this.resultQueue$.pipe(debounceTime(50)).subscribe(this.result$);
|
|
25
|
-
this.subscriptions.push(subscriptionDebounce);
|
|
9
|
+
async run(dataStorage, listener) {
|
|
10
|
+
const store = dataStorage.getStore(this.collection.name);
|
|
11
|
+
const result = await this.fetch(store);
|
|
12
|
+
this.lastResult = result;
|
|
13
|
+
if (listener)
|
|
14
|
+
this.listener = listener;
|
|
15
|
+
return result;
|
|
26
16
|
}
|
|
27
|
-
changeHandler(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
this.nextResult(
|
|
17
|
+
changeHandler(changes) {
|
|
18
|
+
for (const change of changes) {
|
|
19
|
+
const response = this.onChange(change);
|
|
20
|
+
if (response !== false)
|
|
21
|
+
this.lastResult = response;
|
|
22
|
+
}
|
|
23
|
+
if (this.lastResult)
|
|
24
|
+
this.nextResult(this.lastResult);
|
|
35
25
|
}
|
|
36
26
|
unsubscribe() {
|
|
37
|
-
|
|
27
|
+
console.log("unsubscribe");
|
|
38
28
|
}
|
|
39
29
|
nextResult(result) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
this.resultQueue$.next(result);
|
|
43
|
-
}
|
|
44
|
-
isUnsubscribed() {
|
|
45
|
-
return this.subscriptions.every((sub) => sub.closed);
|
|
30
|
+
this.lastResult = result;
|
|
31
|
+
this.listener?.(result);
|
|
46
32
|
}
|
|
47
33
|
}
|
|
48
34
|
|
|
@@ -72,17 +58,17 @@ class ArcManyItemsQuery extends ArcCollectionQuery {
|
|
|
72
58
|
this.sortFn = sortFn;
|
|
73
59
|
}
|
|
74
60
|
onChange(change) {
|
|
75
|
-
const lastResult = this.
|
|
76
|
-
const lastResultAsArray = lastResult
|
|
77
|
-
const index = lastResultAsArray.findIndex((e) => e._id === (change.type === "delete" ? change.id : change.
|
|
61
|
+
const lastResult = this.lastResult;
|
|
62
|
+
const lastResultAsArray = lastResult?.toArray() || [];
|
|
63
|
+
const index = lastResultAsArray.findIndex((e) => e._id === (change.type === "delete" ? change.id : change.id));
|
|
78
64
|
const isInLastResult = index !== -1;
|
|
79
|
-
const shouldBeInTheResult = change.type !== "delete" && this.checkItem(change.
|
|
65
|
+
const shouldBeInTheResult = change.type !== "delete" && this.checkItem(change.item);
|
|
80
66
|
if (isInLastResult && shouldBeInTheResult)
|
|
81
|
-
return this.createResult(lastResultAsArray.toSpliced(index, 1, change.
|
|
67
|
+
return this.createResult(lastResultAsArray.toSpliced(index, 1, change.item));
|
|
82
68
|
else if (isInLastResult && (change.type === "delete" || !shouldBeInTheResult))
|
|
83
69
|
return this.createResult(lastResultAsArray.toSpliced(index, 1));
|
|
84
70
|
else if (!isInLastResult && shouldBeInTheResult)
|
|
85
|
-
return this.createResult(lastResultAsArray.concat(change.
|
|
71
|
+
return this.createResult(lastResultAsArray.concat(change.item));
|
|
86
72
|
return false;
|
|
87
73
|
}
|
|
88
74
|
createResult(result) {
|
|
@@ -104,8 +90,9 @@ class ArcManyItemsQuery extends ArcCollectionQuery {
|
|
|
104
90
|
|
|
105
91
|
// collection/queries/all-items.ts
|
|
106
92
|
class ArcAllItemsQuery extends ArcManyItemsQuery {
|
|
107
|
-
async fetch(
|
|
108
|
-
|
|
93
|
+
async fetch(store) {
|
|
94
|
+
const results = await store.findAll(this.changeHandler.bind(this));
|
|
95
|
+
return this.createFiltredResult(results);
|
|
109
96
|
}
|
|
110
97
|
}
|
|
111
98
|
|
|
@@ -179,8 +166,9 @@ class ArcIndexedItemsQuery extends ArcManyItemsQuery {
|
|
|
179
166
|
return false;
|
|
180
167
|
return true;
|
|
181
168
|
}
|
|
182
|
-
async fetch(
|
|
183
|
-
|
|
169
|
+
async fetch(store) {
|
|
170
|
+
const results = await store.findByIndex(this.index, this.data, this.changeHandler.bind(this));
|
|
171
|
+
return this.createFiltredResult(results);
|
|
184
172
|
}
|
|
185
173
|
}
|
|
186
174
|
|
|
@@ -210,16 +198,15 @@ class ArcOneItemQuery extends ArcCollectionQuery {
|
|
|
210
198
|
this.id = id;
|
|
211
199
|
}
|
|
212
200
|
onChange(change) {
|
|
213
|
-
if (change.type === "delete"
|
|
201
|
+
if (change.type === "delete")
|
|
214
202
|
return;
|
|
215
|
-
if (change.type === "set"
|
|
216
|
-
return change.
|
|
203
|
+
if (change.type === "set")
|
|
204
|
+
return change.item;
|
|
217
205
|
return false;
|
|
218
206
|
}
|
|
219
|
-
fetch(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return transaction.findById(this.collection, this.id);
|
|
207
|
+
async fetch(store) {
|
|
208
|
+
const result = await store.findById(this.id, this.changeHandler.bind(this));
|
|
209
|
+
return result;
|
|
223
210
|
}
|
|
224
211
|
}
|
|
225
212
|
|
|
@@ -271,61 +258,44 @@ class ArcCollection {
|
|
|
271
258
|
one: (id) => new ArcOneItemQueryBuilder(this, id)
|
|
272
259
|
};
|
|
273
260
|
}
|
|
274
|
-
commandContext(
|
|
261
|
+
commandContext(dataStorage) {
|
|
262
|
+
const store = dataStorage.getStore(this.name);
|
|
275
263
|
return {
|
|
276
|
-
add: (data) => {
|
|
264
|
+
add: async (data) => {
|
|
277
265
|
const id = this.id.generate();
|
|
278
266
|
const parsed = this.schema.parse(data);
|
|
279
267
|
const body = {
|
|
280
268
|
_id: id,
|
|
281
269
|
...parsed
|
|
282
270
|
};
|
|
283
|
-
|
|
271
|
+
await store.set(body);
|
|
284
272
|
return { id };
|
|
285
273
|
},
|
|
286
|
-
remove: (id) => {
|
|
287
|
-
|
|
274
|
+
remove: async (id) => {
|
|
275
|
+
await store.remove(id);
|
|
288
276
|
return { success: true };
|
|
289
277
|
},
|
|
290
|
-
set: (id, data) => {
|
|
278
|
+
set: async (id, data) => {
|
|
291
279
|
const parsed = this.schema.parse(data);
|
|
292
280
|
const body = {
|
|
293
281
|
_id: id,
|
|
294
282
|
...parsed
|
|
295
283
|
};
|
|
296
|
-
|
|
284
|
+
await store.set(body);
|
|
297
285
|
return { success: true };
|
|
298
286
|
},
|
|
287
|
+
all: async () => {
|
|
288
|
+
return store.findAll();
|
|
289
|
+
},
|
|
299
290
|
one: async (id) => {
|
|
300
|
-
|
|
301
|
-
|
|
291
|
+
return store.findById(id);
|
|
292
|
+
},
|
|
293
|
+
modify: async (id, data) => {
|
|
294
|
+
const deserialized = this.schema.deserialize(data);
|
|
295
|
+
await store.modify(id, deserialized);
|
|
302
296
|
}
|
|
303
297
|
};
|
|
304
298
|
}
|
|
305
|
-
async applyChange(transaction, change, events) {
|
|
306
|
-
switch (change.type) {
|
|
307
|
-
case "set":
|
|
308
|
-
await transaction.set(this, change.body);
|
|
309
|
-
events.push(change);
|
|
310
|
-
break;
|
|
311
|
-
case "delete":
|
|
312
|
-
await transaction.remove(this, change.id);
|
|
313
|
-
events.push(change);
|
|
314
|
-
break;
|
|
315
|
-
case "mutate":
|
|
316
|
-
const existingObject = await transaction.findById(this, change.id);
|
|
317
|
-
if (existingObject) {
|
|
318
|
-
const updatedObject = apply(existingObject, change.patches);
|
|
319
|
-
await transaction.set(this, updatedObject);
|
|
320
|
-
events.push({
|
|
321
|
-
type: "set",
|
|
322
|
-
collection: change.collection,
|
|
323
|
-
body: updatedObject
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
break;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
299
|
indexBy(indexes) {
|
|
330
300
|
return new ArcIndexedCollection(this.name, this.id, this.schema, this.options, indexes);
|
|
331
301
|
}
|
|
@@ -337,6 +307,20 @@ class ArcIndexedCollection extends ArcCollection {
|
|
|
337
307
|
super(name, id, schema, options);
|
|
338
308
|
this.indexes = indexes;
|
|
339
309
|
}
|
|
310
|
+
commandContext(dataStorage) {
|
|
311
|
+
const superContext = super.commandContext(dataStorage);
|
|
312
|
+
return new Proxy(superContext, {
|
|
313
|
+
get: (target, name) => {
|
|
314
|
+
if (name in target) {
|
|
315
|
+
return target[name];
|
|
316
|
+
}
|
|
317
|
+
if (!(name in this.indexes)) {
|
|
318
|
+
throw new Error(`Index "${name}" not found in collection "${this.name}"`);
|
|
319
|
+
}
|
|
320
|
+
return (data) => dataStorage.getStore(this.name, this.deserialize.bind(this)).findByIndex(name, data);
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
}
|
|
340
324
|
queryBuilder() {
|
|
341
325
|
const superQueryBuilder = super.queryBuilder();
|
|
342
326
|
return new Proxy({}, {
|
|
@@ -352,22 +336,25 @@ class ArcIndexedCollection extends ArcCollection {
|
|
|
352
336
|
}
|
|
353
337
|
}
|
|
354
338
|
// context/context.ts
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
return new ArcContext(collections);
|
|
339
|
+
function context(elements, commands, version) {
|
|
340
|
+
return new ArcContext(elements, commands, version);
|
|
358
341
|
}
|
|
359
342
|
|
|
360
343
|
class ArcContext {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
344
|
+
elements;
|
|
345
|
+
commands;
|
|
346
|
+
version;
|
|
347
|
+
elementsMap;
|
|
348
|
+
constructor(elements, commands, version) {
|
|
349
|
+
this.elements = elements;
|
|
350
|
+
this.commands = commands;
|
|
351
|
+
this.version = version;
|
|
352
|
+
this.elementsMap = Object.fromEntries(elements.map((collection3) => [collection3.name, collection3]));
|
|
366
353
|
}
|
|
367
354
|
queryBuilder() {
|
|
368
355
|
return new Proxy({}, {
|
|
369
356
|
get: (target, name) => {
|
|
370
|
-
const collection3 = this.
|
|
357
|
+
const collection3 = this.elementsMap[name];
|
|
371
358
|
if (!collection3) {
|
|
372
359
|
throw new Error(`Collection "${name}" not found`);
|
|
373
360
|
}
|
|
@@ -375,57 +362,308 @@ class ArcContext {
|
|
|
375
362
|
}
|
|
376
363
|
});
|
|
377
364
|
}
|
|
378
|
-
commandContext(
|
|
379
|
-
|
|
380
|
-
const collectionDrafts = [];
|
|
381
|
-
function getDraft(collection3, base) {
|
|
382
|
-
const [draft, finalize2] = create(base, { enablePatches: true });
|
|
383
|
-
collectionDrafts.push({
|
|
384
|
-
collection: collection3,
|
|
385
|
-
finalize: finalize2
|
|
386
|
-
});
|
|
387
|
-
return draft;
|
|
388
|
-
}
|
|
389
|
-
const contextProxy = new Proxy({}, {
|
|
365
|
+
commandContext(dataStorage) {
|
|
366
|
+
return new Proxy({}, {
|
|
390
367
|
get: (target, name) => {
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
throw new Error(`Collection "${name}" not found`);
|
|
394
|
-
}
|
|
395
|
-
return collection3.commandContext(transaction, changes, getDraft);
|
|
368
|
+
const element = this.elementsMap[name];
|
|
369
|
+
return element.commandContext(dataStorage);
|
|
396
370
|
}
|
|
397
371
|
});
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// data-storage/store-state.abstract.ts
|
|
375
|
+
class StoreState {
|
|
376
|
+
storeName;
|
|
377
|
+
dataStorage;
|
|
378
|
+
deserialize;
|
|
379
|
+
listeners = new Set;
|
|
380
|
+
constructor(storeName, dataStorage, deserialize) {
|
|
381
|
+
this.storeName = storeName;
|
|
382
|
+
this.dataStorage = dataStorage;
|
|
383
|
+
this.deserialize = deserialize;
|
|
384
|
+
}
|
|
385
|
+
fork() {
|
|
386
|
+
return new ForkedStoreState(this.storeName, this.dataStorage, this, this.deserialize);
|
|
387
|
+
}
|
|
388
|
+
async set(item) {
|
|
389
|
+
const change = {
|
|
390
|
+
type: "set",
|
|
391
|
+
data: item
|
|
392
|
+
};
|
|
393
|
+
await this.applyChanges([change]);
|
|
394
|
+
}
|
|
395
|
+
async remove(id) {
|
|
396
|
+
const change = {
|
|
397
|
+
type: "delete",
|
|
398
|
+
id
|
|
399
|
+
};
|
|
400
|
+
await this.applyChanges([change]);
|
|
401
|
+
}
|
|
402
|
+
async modify(id, data) {
|
|
403
|
+
const change = {
|
|
404
|
+
type: "modify",
|
|
405
|
+
id,
|
|
406
|
+
data
|
|
407
|
+
};
|
|
408
|
+
await this.applyChanges([change]);
|
|
409
|
+
}
|
|
410
|
+
unsubscribe(listener) {
|
|
411
|
+
this.listeners.delete(listener);
|
|
412
|
+
}
|
|
413
|
+
notifyListeners(events) {
|
|
414
|
+
for (const listener of this.listeners) {
|
|
415
|
+
listener.callback(events);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// data-storage/store-state-fork.ts
|
|
421
|
+
class ForkedStoreState extends StoreState {
|
|
422
|
+
master;
|
|
423
|
+
changedItems = new Map;
|
|
424
|
+
changes = [];
|
|
425
|
+
constructor(storeName, dataStorage, master, deserialize) {
|
|
426
|
+
super(storeName, dataStorage, deserialize);
|
|
427
|
+
this.master = master;
|
|
428
|
+
}
|
|
429
|
+
async applyChanges(changes) {
|
|
430
|
+
const events = [];
|
|
431
|
+
for (const change of changes) {
|
|
432
|
+
switch (change.type) {
|
|
433
|
+
case "set":
|
|
434
|
+
const item = this.deserialize ? this.deserialize(change.data) : change.data;
|
|
435
|
+
this.changedItems.set(change.data._id, item);
|
|
436
|
+
events.push({
|
|
437
|
+
type: "set",
|
|
438
|
+
item: change.data,
|
|
439
|
+
id: change.data._id
|
|
440
|
+
});
|
|
441
|
+
break;
|
|
442
|
+
case "delete":
|
|
443
|
+
this.changedItems.set(change.id, null);
|
|
444
|
+
events.push({
|
|
445
|
+
type: "delete",
|
|
446
|
+
item: null,
|
|
447
|
+
id: change.id
|
|
448
|
+
});
|
|
449
|
+
break;
|
|
450
|
+
case "modify":
|
|
451
|
+
{
|
|
452
|
+
const existing = await this.findById(change.id);
|
|
453
|
+
const updated = existing ? { ...existing, ...change.data } : change.data;
|
|
454
|
+
const item2 = this.deserialize ? this.deserialize(updated) : updated;
|
|
455
|
+
this.changedItems.set(change.id, item2);
|
|
456
|
+
events.push({
|
|
457
|
+
type: "set",
|
|
458
|
+
item: item2,
|
|
459
|
+
id: change.id
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
break;
|
|
407
463
|
}
|
|
408
|
-
|
|
464
|
+
this.changes.push(change);
|
|
465
|
+
}
|
|
466
|
+
if (events.length > 0) {
|
|
467
|
+
this.notifyListeners(events);
|
|
409
468
|
}
|
|
410
|
-
return { context: contextProxy, finalize };
|
|
411
469
|
}
|
|
412
|
-
async
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
470
|
+
async findById(id, listener) {
|
|
471
|
+
if (listener)
|
|
472
|
+
this.listeners.add({ callback: listener, id });
|
|
473
|
+
if (this.changedItems.has(id))
|
|
474
|
+
return this.changedItems.get(id);
|
|
475
|
+
return await this.master.findById(id);
|
|
476
|
+
}
|
|
477
|
+
async findByIndex(index, data, listener) {
|
|
478
|
+
if (listener)
|
|
479
|
+
this.listeners.add({ callback: listener });
|
|
480
|
+
const parentResult = await this.master.findByIndex(index, data);
|
|
481
|
+
return parentResult.map((item) => {
|
|
482
|
+
const id = item._id;
|
|
483
|
+
if (this.changedItems.has(id))
|
|
484
|
+
return this.changedItems.get(id);
|
|
485
|
+
return item;
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
async findAll(listener) {
|
|
489
|
+
if (listener)
|
|
490
|
+
this.listeners.add({ callback: listener });
|
|
491
|
+
const parentResult = await this.master.findAll();
|
|
492
|
+
return parentResult.map((item) => {
|
|
493
|
+
const id = item._id;
|
|
494
|
+
if (this.changedItems.has(id))
|
|
495
|
+
return this.changedItems.get(id);
|
|
496
|
+
return item;
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// data-storage/data-storage-forked.ts
|
|
502
|
+
class ForkedDataStorage {
|
|
503
|
+
master;
|
|
504
|
+
stores = new Map;
|
|
505
|
+
constructor(master) {
|
|
506
|
+
this.master = master;
|
|
507
|
+
}
|
|
508
|
+
getReadTransaction() {
|
|
509
|
+
return this.master.getReadTransaction();
|
|
510
|
+
}
|
|
511
|
+
getReadWriteTransaction() {
|
|
512
|
+
return this.master.getReadWriteTransaction();
|
|
513
|
+
}
|
|
514
|
+
getStore(storeName, deserialize) {
|
|
515
|
+
if (this.stores.has(storeName))
|
|
516
|
+
return this.stores.get(storeName);
|
|
517
|
+
const masterStorage = this.master.getStore(storeName, deserialize);
|
|
518
|
+
const storage = new ForkedStoreState(storeName, this, masterStorage, deserialize);
|
|
519
|
+
this.stores.set(storeName, storage);
|
|
520
|
+
return storage;
|
|
521
|
+
}
|
|
522
|
+
fork() {
|
|
523
|
+
return new ForkedDataStorage(this);
|
|
524
|
+
}
|
|
525
|
+
async merge() {
|
|
526
|
+
for (const store of this.stores.values()) {
|
|
527
|
+
await store.master?.applyChanges(store.changes);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
// data-storage/store-state-master.ts
|
|
532
|
+
class MasterStoreState extends StoreState {
|
|
533
|
+
items = new Map;
|
|
534
|
+
isComplete = false;
|
|
535
|
+
constructor(storeName, dataStorage, deserialize) {
|
|
536
|
+
super(storeName, dataStorage, deserialize);
|
|
537
|
+
}
|
|
538
|
+
async applyChanges(changes) {
|
|
539
|
+
const transaction = await this.dataStorage.getReadWriteTransaction();
|
|
540
|
+
const events = [];
|
|
541
|
+
for (const change of changes) {
|
|
542
|
+
switch (change.type) {
|
|
543
|
+
case "set":
|
|
544
|
+
await transaction.set(this.storeName, change.data);
|
|
545
|
+
const item = this.deserialize ? this.deserialize(change.data) : change.data;
|
|
546
|
+
this.items.set(change.data._id, item);
|
|
547
|
+
events.push({
|
|
548
|
+
type: "set",
|
|
549
|
+
item: change.data,
|
|
550
|
+
id: change.data._id
|
|
551
|
+
});
|
|
552
|
+
break;
|
|
553
|
+
case "delete":
|
|
554
|
+
await transaction.remove(this.storeName, change.id);
|
|
555
|
+
this.items.set(change.id, null);
|
|
556
|
+
events.push({
|
|
557
|
+
type: "delete",
|
|
558
|
+
item: null,
|
|
559
|
+
id: change.id
|
|
560
|
+
});
|
|
561
|
+
break;
|
|
562
|
+
case "modify":
|
|
563
|
+
{
|
|
564
|
+
const existing = await transaction.findById(this.storeName, change.id);
|
|
565
|
+
const updated = existing ? { ...existing, ...change.data } : change.data;
|
|
566
|
+
await transaction.set(this.storeName, updated);
|
|
567
|
+
const item2 = this.deserialize ? this.deserialize(updated) : updated;
|
|
568
|
+
this.items.set(change.id, item2);
|
|
569
|
+
events.push({
|
|
570
|
+
type: "set",
|
|
571
|
+
item: item2,
|
|
572
|
+
id: change.id
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
await transaction.commit();
|
|
579
|
+
if (events.length > 0) {
|
|
580
|
+
this.notifyListeners(events);
|
|
416
581
|
}
|
|
417
|
-
return collection3.applyChange(transaction, change, events);
|
|
418
582
|
}
|
|
419
|
-
|
|
420
|
-
|
|
583
|
+
async findById(id, listener) {
|
|
584
|
+
if (listener)
|
|
585
|
+
this.listeners.add({ callback: listener, id });
|
|
586
|
+
if (this.items.has(id))
|
|
587
|
+
return this.items.get(id);
|
|
588
|
+
const transaction = await this.dataStorage.getReadTransaction();
|
|
589
|
+
const result = await transaction.findById(this.storeName, id);
|
|
590
|
+
if (!result)
|
|
591
|
+
return;
|
|
592
|
+
const item = this.deserialize ? this.deserialize(result) : result;
|
|
593
|
+
this.items.set(id, item);
|
|
594
|
+
return item;
|
|
595
|
+
}
|
|
596
|
+
async findByIndex(index, data, listener) {
|
|
597
|
+
if (listener)
|
|
598
|
+
this.listeners.add({ callback: listener });
|
|
599
|
+
if (this.isComplete) {
|
|
600
|
+
const results2 = Array.from(this.items.values()).filter((item) => {
|
|
601
|
+
if (!item)
|
|
602
|
+
return false;
|
|
603
|
+
const notCorrect = Object.entries(data).some(([key, value]) => item[key] !== value);
|
|
604
|
+
return !notCorrect;
|
|
605
|
+
});
|
|
606
|
+
return results2;
|
|
607
|
+
}
|
|
608
|
+
const transaction = await this.dataStorage.getReadTransaction();
|
|
609
|
+
const dbResults = await transaction.findByIndex(this.storeName, index, data);
|
|
610
|
+
const results = dbResults.map((item) => {
|
|
611
|
+
const id = item._id;
|
|
612
|
+
if (this.items.has(id))
|
|
613
|
+
return this.items.get(id);
|
|
614
|
+
const processedItem = this.deserialize ? this.deserialize(item) : item;
|
|
615
|
+
return processedItem;
|
|
616
|
+
});
|
|
617
|
+
return results;
|
|
618
|
+
}
|
|
619
|
+
async findAll(listener) {
|
|
620
|
+
if (listener)
|
|
621
|
+
this.listeners.add({ callback: listener });
|
|
622
|
+
if (this.isComplete)
|
|
623
|
+
return Array.from(this.items.values()).filter((e) => !!e);
|
|
624
|
+
const transaction = await this.dataStorage.getReadTransaction();
|
|
625
|
+
const dbResults = await transaction.findAll(this.storeName);
|
|
626
|
+
const items = dbResults.map((item) => {
|
|
627
|
+
const id = item._id;
|
|
628
|
+
if (this.items.has(id))
|
|
629
|
+
return this.items.get(id);
|
|
630
|
+
const processedItem = this.deserialize ? this.deserialize(item) : item;
|
|
631
|
+
this.items.set(processedItem._id, processedItem);
|
|
632
|
+
return processedItem;
|
|
633
|
+
});
|
|
634
|
+
this.isComplete = true;
|
|
635
|
+
return items;
|
|
421
636
|
}
|
|
422
637
|
}
|
|
423
638
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
639
|
+
// data-storage/data-storage-master.ts
|
|
640
|
+
class MasterDataStorage {
|
|
641
|
+
dbAdapter;
|
|
642
|
+
arcContext;
|
|
643
|
+
stores = new Map;
|
|
644
|
+
rtcAdapter;
|
|
645
|
+
constructor(dbAdapter, rtcAdapterFactory, arcContext) {
|
|
646
|
+
this.dbAdapter = dbAdapter;
|
|
647
|
+
this.arcContext = arcContext;
|
|
648
|
+
this.rtcAdapter = rtcAdapterFactory(this);
|
|
649
|
+
}
|
|
650
|
+
async getReadTransaction() {
|
|
651
|
+
return (await this.dbAdapter).readTransaction();
|
|
652
|
+
}
|
|
653
|
+
async getReadWriteTransaction() {
|
|
654
|
+
return (await this.dbAdapter).readWriteTransaction();
|
|
655
|
+
}
|
|
656
|
+
getStore(storeName) {
|
|
657
|
+
if (!this.stores.has(storeName)) {
|
|
658
|
+
const contextElement = this.arcContext.elementsMap[storeName];
|
|
659
|
+
if (!contextElement)
|
|
660
|
+
console.log(`Can't find ${storeName} as context element`);
|
|
661
|
+
this.stores.set(storeName, new MasterStoreState(storeName, this, contextElement && contextElement.deserialize ? (a) => contextElement.deserialize(a) : undefined));
|
|
662
|
+
}
|
|
663
|
+
return this.stores.get(storeName);
|
|
664
|
+
}
|
|
665
|
+
fork() {
|
|
666
|
+
return new ForkedDataStorage(this);
|
|
429
667
|
}
|
|
430
668
|
}
|
|
431
669
|
// elements/optional.ts
|
|
@@ -689,257 +927,18 @@ class ArcStringEnum extends ArcAbstract {
|
|
|
689
927
|
return this.values;
|
|
690
928
|
}
|
|
691
929
|
}
|
|
692
|
-
// model/model.ts
|
|
693
|
-
import { Subject as Subject2 } from "rxjs";
|
|
694
|
-
function model(context3, dependencies) {
|
|
695
|
-
return new ArcModel(context3, dependencies.dbAdapterFactory, dependencies.rtcAdapterFactory);
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
class ArcModel {
|
|
699
|
-
context3;
|
|
700
|
-
rtc;
|
|
701
|
-
dbAdapterPromise;
|
|
702
|
-
changes$ = new Subject2;
|
|
703
|
-
constructor(context3, dbAdapterFactory, rtcAdapterFactory) {
|
|
704
|
-
this.context = context3;
|
|
705
|
-
this.rtc = rtcAdapterFactory(this);
|
|
706
|
-
this.dbAdapterPromise = dbAdapterFactory(this.context);
|
|
707
|
-
}
|
|
708
|
-
query(queryFactory) {
|
|
709
|
-
const queryBuilder = this.context.queryBuilder();
|
|
710
|
-
const query = queryFactory(queryBuilder).toQuery();
|
|
711
|
-
this.runQuery(query);
|
|
712
|
-
return query;
|
|
713
|
-
}
|
|
714
|
-
async runQuery(query) {
|
|
715
|
-
const dbAdapter = await this.dbAdapterPromise;
|
|
716
|
-
query.run(dbAdapter, this.changes$);
|
|
717
|
-
}
|
|
718
|
-
commands() {
|
|
719
|
-
return new Proxy({}, {
|
|
720
|
-
get: (target, name) => {
|
|
721
|
-
if (name in this.context.commands) {
|
|
722
|
-
return async (...args) => {
|
|
723
|
-
const { result } = await this.executeCommand(this.context.commands[name], ...args);
|
|
724
|
-
return result;
|
|
725
|
-
};
|
|
726
|
-
}
|
|
727
|
-
console.warn(`Command '${name}' not found in the context.`);
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
async executeCommand(command, ...args) {
|
|
733
|
-
const dbAdapter = await this.dbAdapterPromise;
|
|
734
|
-
const transaction = await dbAdapter.readWriteTransaction(this.context.collections);
|
|
735
|
-
const { context: context3, finalize } = await this.context.commandContext(transaction);
|
|
736
|
-
const result = await command(context3, ...args);
|
|
737
|
-
const changes = await finalize();
|
|
738
|
-
await this.applyChangesForTransaction(transaction, changes);
|
|
739
|
-
this.rtc.changesExecuted(changes);
|
|
740
|
-
return { changes, result };
|
|
741
|
-
}
|
|
742
|
-
async applyChangesForTransaction(transaction, changes) {
|
|
743
|
-
const events = [];
|
|
744
|
-
for (const change of changes) {
|
|
745
|
-
await this.context.applyChange(transaction, change, events);
|
|
746
|
-
}
|
|
747
|
-
await transaction.commit();
|
|
748
|
-
events.forEach((change) => this.notifyChange(change));
|
|
749
|
-
}
|
|
750
|
-
notifyChange(change) {
|
|
751
|
-
this.changes$.next(change);
|
|
752
|
-
}
|
|
753
|
-
async applyChanges(changes) {
|
|
754
|
-
const dbAdapter = await this.dbAdapterPromise;
|
|
755
|
-
const transaction = await dbAdapter.readWriteTransaction(this.context.collections);
|
|
756
|
-
await this.applyChangesForTransaction(transaction, changes);
|
|
757
|
-
}
|
|
758
|
-
getCollection(name) {
|
|
759
|
-
return this.context.collectionsMap[name];
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
// model/submodel.ts
|
|
763
|
-
import { Subject as Subject3 } from "rxjs";
|
|
764
|
-
|
|
765
|
-
// collection/in-memory-db-proxy.ts
|
|
766
|
-
class InMemoryTransaction {
|
|
767
|
-
parentTransaction;
|
|
768
|
-
local;
|
|
769
|
-
constructor(parentTransaction, local) {
|
|
770
|
-
this.parentTransaction = parentTransaction;
|
|
771
|
-
this.local = local;
|
|
772
|
-
}
|
|
773
|
-
async set(collection3, data) {
|
|
774
|
-
let collectionLocal = this.local.get(collection3.name);
|
|
775
|
-
if (!collectionLocal) {
|
|
776
|
-
collectionLocal = new Map;
|
|
777
|
-
this.local.set(collection3.name, collectionLocal);
|
|
778
|
-
}
|
|
779
|
-
collectionLocal.set(data._id, data);
|
|
780
|
-
}
|
|
781
|
-
async remove(collection3, id3) {
|
|
782
|
-
let collectionLocal = this.local.get(collection3.name);
|
|
783
|
-
if (!collectionLocal) {
|
|
784
|
-
collectionLocal = new Map;
|
|
785
|
-
this.local.set(collection3.name, collectionLocal);
|
|
786
|
-
}
|
|
787
|
-
collectionLocal.set(id3, null);
|
|
788
|
-
}
|
|
789
|
-
async findById(collection3, id3) {
|
|
790
|
-
const localItem = this.local.get(collection3.name)?.get(id3);
|
|
791
|
-
if (localItem !== undefined) {
|
|
792
|
-
return localItem === null ? undefined : localItem;
|
|
793
|
-
}
|
|
794
|
-
return this.parentTransaction.findById(collection3, id3);
|
|
795
|
-
}
|
|
796
|
-
async findByIndex(collection3, index, data) {
|
|
797
|
-
const parentResults = await this.parentTransaction.findByIndex(collection3, index, data);
|
|
798
|
-
const localResults = Array.from(this.local.get(collection3.name)?.values() || []).filter((item) => item !== null && this.matchesIndex(item, index, data));
|
|
799
|
-
return this.mergeResults(parentResults, localResults);
|
|
800
|
-
}
|
|
801
|
-
async findAll(collection3) {
|
|
802
|
-
const parentResults = await this.parentTransaction.findAll(collection3);
|
|
803
|
-
const localResults = Array.from(this.local.get(collection3.name)?.values() || []).filter((item) => item !== null);
|
|
804
|
-
return this.mergeResults(parentResults, localResults);
|
|
805
|
-
}
|
|
806
|
-
async commit() {
|
|
807
|
-
}
|
|
808
|
-
matchesIndex(item, index, data) {
|
|
809
|
-
return Object.entries(data).every(([key, value]) => item[key] === value);
|
|
810
|
-
}
|
|
811
|
-
mergeResults(parentResults, localResults) {
|
|
812
|
-
const mergedMap = new Map;
|
|
813
|
-
parentResults.forEach((item) => mergedMap.set(item._id, item));
|
|
814
|
-
localResults.forEach((item) => mergedMap.set(item._id, item));
|
|
815
|
-
return Array.from(mergedMap.values());
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
class InMemoryDatabaseProxyAdapter {
|
|
820
|
-
parentAdapter;
|
|
821
|
-
local = new Map;
|
|
822
|
-
constructor(parentAdapter) {
|
|
823
|
-
this.parentAdapter = parentAdapter;
|
|
824
|
-
}
|
|
825
|
-
readWriteTransaction(collections) {
|
|
826
|
-
const parentTransaction = this.parentAdapter.readWriteTransaction(collections);
|
|
827
|
-
return new InMemoryTransaction(parentTransaction, this.local);
|
|
828
|
-
}
|
|
829
|
-
readTransaction(collections) {
|
|
830
|
-
const parentTransaction = this.parentAdapter.readTransaction(collections);
|
|
831
|
-
return new InMemoryTransaction(parentTransaction, this.local);
|
|
832
|
-
}
|
|
833
|
-
clearLocal() {
|
|
834
|
-
this.local.clear();
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
// model/submodel.ts
|
|
839
|
-
class ArcSubModel {
|
|
840
|
-
parentModel;
|
|
841
|
-
changes$ = new Subject3;
|
|
842
|
-
proxyAdapterPromise;
|
|
843
|
-
uncommitedChanges = [];
|
|
844
|
-
constructor(parentModel) {
|
|
845
|
-
this.parentModel = parentModel;
|
|
846
|
-
this.parentModel.changes$.subscribe(this.changes$);
|
|
847
|
-
this.proxyAdapterPromise = this.parentModel.dbAdapterPromise.then((dbAdapter) => new InMemoryDatabaseProxyAdapter(dbAdapter));
|
|
848
|
-
}
|
|
849
|
-
query(queryFactory) {
|
|
850
|
-
const queryBuilder = this.context.queryBuilder();
|
|
851
|
-
const query = queryFactory(queryBuilder).toQuery();
|
|
852
|
-
this.runQuery(query);
|
|
853
|
-
return query;
|
|
854
|
-
}
|
|
855
|
-
async runQuery(query) {
|
|
856
|
-
const proxyAdapter = await this.proxyAdapterPromise;
|
|
857
|
-
query.run(proxyAdapter, this.changes$);
|
|
858
|
-
}
|
|
859
|
-
commands() {
|
|
860
|
-
return new Proxy({}, {
|
|
861
|
-
get: (target, name) => {
|
|
862
|
-
if (name in this.parentModel.context.commands) {
|
|
863
|
-
return async (...args) => {
|
|
864
|
-
const { result } = await this.executeCommand(this.parentModel.context.commands[name], ...args);
|
|
865
|
-
return result;
|
|
866
|
-
};
|
|
867
|
-
}
|
|
868
|
-
console.warn(`Command '${name}' not found in the context.`);
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
});
|
|
872
|
-
}
|
|
873
|
-
async executeCommand(command, ...args) {
|
|
874
|
-
const proxyAdapter = await this.proxyAdapterPromise;
|
|
875
|
-
const transaction = proxyAdapter.readWriteTransaction(this.parentModel.context.collections);
|
|
876
|
-
const { context: context3, finalize } = await this.parentModel.context.commandContext(transaction);
|
|
877
|
-
const result = await command(context3, ...args);
|
|
878
|
-
const changes = await finalize();
|
|
879
|
-
const events = [];
|
|
880
|
-
for (const change of changes) {
|
|
881
|
-
await this.context.applyChange(transaction, change, events);
|
|
882
|
-
}
|
|
883
|
-
this.uncommitedChanges.push(...changes);
|
|
884
|
-
events.forEach((change) => this.changes$.next(change));
|
|
885
|
-
return { changes, result };
|
|
886
|
-
}
|
|
887
|
-
getCollection(name) {
|
|
888
|
-
return this.parentModel.getCollection(name);
|
|
889
|
-
}
|
|
890
|
-
async applyChanges(changes) {
|
|
891
|
-
const proxyAdapter = await this.proxyAdapterPromise;
|
|
892
|
-
const transaction = proxyAdapter.readWriteTransaction(this.parentModel.context.collections);
|
|
893
|
-
await this.parentModel.applyChangesForTransaction(transaction, changes);
|
|
894
|
-
}
|
|
895
|
-
get context() {
|
|
896
|
-
return this.parentModel.context;
|
|
897
|
-
}
|
|
898
|
-
async commitChanges() {
|
|
899
|
-
this.parentModel.applyChanges(this.uncommitedChanges);
|
|
900
|
-
this.parentModel.rtc.changesExecuted(this.uncommitedChanges);
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
// rtc/deserializeChanges.ts
|
|
904
|
-
function deserializeChanges(changes, getCollection) {
|
|
905
|
-
return changes.map((change) => {
|
|
906
|
-
const c = getCollection(change.collection);
|
|
907
|
-
if (!c) {
|
|
908
|
-
console.error(`Collection ${change.collection} not found`);
|
|
909
|
-
return change;
|
|
910
|
-
}
|
|
911
|
-
switch (change.type) {
|
|
912
|
-
case "set":
|
|
913
|
-
return {
|
|
914
|
-
...change,
|
|
915
|
-
body: c.deserialize(change.body)
|
|
916
|
-
};
|
|
917
|
-
case "mutate":
|
|
918
|
-
return {
|
|
919
|
-
...change,
|
|
920
|
-
patches: change.patches.map((patch) => ({
|
|
921
|
-
...patch,
|
|
922
|
-
value: c.schema.deserializePath(patch.path, patch.value)
|
|
923
|
-
}))
|
|
924
|
-
};
|
|
925
|
-
default:
|
|
926
|
-
return change;
|
|
927
|
-
}
|
|
928
|
-
});
|
|
929
|
-
}
|
|
930
|
-
|
|
931
930
|
// rtc/client.ts
|
|
932
931
|
class RTCClient {
|
|
933
|
-
|
|
932
|
+
storage;
|
|
934
933
|
_socket;
|
|
935
934
|
openSocket;
|
|
936
935
|
reconnectAttempts = 0;
|
|
937
936
|
maxReconnectAttempts = 5;
|
|
938
|
-
constructor(
|
|
939
|
-
this.
|
|
937
|
+
constructor(storage) {
|
|
938
|
+
this.storage = storage;
|
|
940
939
|
this.connect();
|
|
941
940
|
}
|
|
942
|
-
connect() {
|
|
941
|
+
async connect() {
|
|
943
942
|
this._socket = new WebSocket(`wss://${window.location.host}/ws`);
|
|
944
943
|
this.openSocket = new Promise((resolve) => {
|
|
945
944
|
this._socket.addEventListener("open", () => {
|
|
@@ -947,6 +946,7 @@ class RTCClient {
|
|
|
947
946
|
resolve(this._socket);
|
|
948
947
|
});
|
|
949
948
|
});
|
|
949
|
+
const arcState = await this.storage.getStore("state").findById("$arc", (a) => a);
|
|
950
950
|
this._socket.addEventListener("message", (e) => {
|
|
951
951
|
this.onMessage(JSON.parse(e.data));
|
|
952
952
|
});
|
|
@@ -957,7 +957,7 @@ class RTCClient {
|
|
|
957
957
|
});
|
|
958
958
|
this.sendMessage({
|
|
959
959
|
type: "sync",
|
|
960
|
-
lastDate:
|
|
960
|
+
lastDate: arcState?.lastSyncDate || null
|
|
961
961
|
});
|
|
962
962
|
}
|
|
963
963
|
reconnect() {
|
|
@@ -971,7 +971,7 @@ class RTCClient {
|
|
|
971
971
|
console.error("Max reconnect attempts reached. Giving up.");
|
|
972
972
|
}
|
|
973
973
|
}
|
|
974
|
-
|
|
974
|
+
commitChanges(changes) {
|
|
975
975
|
return this.sendMessage({
|
|
976
976
|
type: "changes-executed",
|
|
977
977
|
changes
|
|
@@ -981,35 +981,37 @@ class RTCClient {
|
|
|
981
981
|
switch (message.type) {
|
|
982
982
|
case "sync-result":
|
|
983
983
|
{
|
|
984
|
-
const {
|
|
985
|
-
const
|
|
986
|
-
if (!
|
|
987
|
-
console.error(`
|
|
984
|
+
const { store, items } = message;
|
|
985
|
+
const storeState = this.storage.getStore(store);
|
|
986
|
+
if (!storeState) {
|
|
987
|
+
console.error(`Store ${store} not found`);
|
|
988
988
|
return;
|
|
989
989
|
}
|
|
990
|
-
const
|
|
990
|
+
const changes = items.map((item) => {
|
|
991
991
|
if (item.deleted) {
|
|
992
992
|
return {
|
|
993
|
-
collection: collection3,
|
|
994
993
|
type: "delete",
|
|
995
994
|
id: item._id
|
|
996
995
|
};
|
|
997
996
|
}
|
|
998
997
|
return {
|
|
999
|
-
collection: collection3,
|
|
1000
998
|
type: "set",
|
|
1001
|
-
|
|
999
|
+
data: item
|
|
1002
1000
|
};
|
|
1003
1001
|
});
|
|
1004
|
-
|
|
1002
|
+
storeState.applyChanges(changes);
|
|
1005
1003
|
}
|
|
1006
1004
|
break;
|
|
1007
1005
|
case "sync-done":
|
|
1008
|
-
|
|
1006
|
+
const stateStorage = this.storage.getStore("state");
|
|
1007
|
+
stateStorage.applyChanges([
|
|
1008
|
+
{
|
|
1009
|
+
type: "set",
|
|
1010
|
+
data: { _id: "$arc", lastSyncDate: message.date }
|
|
1011
|
+
}
|
|
1012
|
+
]);
|
|
1009
1013
|
break;
|
|
1010
|
-
case "
|
|
1011
|
-
const deserializedChanges = deserializeChanges(message.changes, (name) => this.model.getCollection(name));
|
|
1012
|
-
this.model.applyChanges(deserializedChanges);
|
|
1014
|
+
case "state-changes":
|
|
1013
1015
|
break;
|
|
1014
1016
|
default:
|
|
1015
1017
|
console.warn(`Message unsupported`, message);
|
|
@@ -1020,16 +1022,42 @@ class RTCClient {
|
|
|
1020
1022
|
socket.send(JSON.stringify(message));
|
|
1021
1023
|
}
|
|
1022
1024
|
}
|
|
1023
|
-
var rtcClientFactory = (
|
|
1024
|
-
return new RTCClient(
|
|
1025
|
+
var rtcClientFactory = (storage) => {
|
|
1026
|
+
return new RTCClient(storage);
|
|
1025
1027
|
};
|
|
1028
|
+
// rtc/deserializeChanges.ts
|
|
1029
|
+
function deserializeChanges(changes, getCollection) {
|
|
1030
|
+
return changes.map((change) => {
|
|
1031
|
+
const c = getCollection(change.collection);
|
|
1032
|
+
if (!c) {
|
|
1033
|
+
console.error(`Collection ${change.collection} not found`);
|
|
1034
|
+
return change;
|
|
1035
|
+
}
|
|
1036
|
+
switch (change.type) {
|
|
1037
|
+
case "set":
|
|
1038
|
+
return {
|
|
1039
|
+
...change,
|
|
1040
|
+
body: c.deserialize(change.body)
|
|
1041
|
+
};
|
|
1042
|
+
case "mutate":
|
|
1043
|
+
return {
|
|
1044
|
+
...change,
|
|
1045
|
+
patches: change.patches.map((patch) => ({
|
|
1046
|
+
...patch,
|
|
1047
|
+
value: c.schema.deserializePath(patch.path, patch.value)
|
|
1048
|
+
}))
|
|
1049
|
+
};
|
|
1050
|
+
default:
|
|
1051
|
+
return change;
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1026
1055
|
export {
|
|
1027
1056
|
stringEnum,
|
|
1028
1057
|
string,
|
|
1029
1058
|
rtcClientFactory,
|
|
1030
1059
|
object,
|
|
1031
1060
|
number,
|
|
1032
|
-
model,
|
|
1033
1061
|
id,
|
|
1034
1062
|
deserializeChanges,
|
|
1035
1063
|
date,
|
|
@@ -1037,17 +1065,22 @@ export {
|
|
|
1037
1065
|
collection,
|
|
1038
1066
|
boolean,
|
|
1039
1067
|
array,
|
|
1040
|
-
|
|
1068
|
+
StoreState,
|
|
1069
|
+
MasterStoreState,
|
|
1070
|
+
MasterDataStorage,
|
|
1071
|
+
ForkedStoreState,
|
|
1072
|
+
ForkedDataStorage,
|
|
1041
1073
|
ArcStringEnum,
|
|
1042
1074
|
ArcString,
|
|
1075
|
+
ArcQueryBuilder,
|
|
1043
1076
|
ArcOptional,
|
|
1044
1077
|
ArcObject,
|
|
1045
1078
|
ArcNumber,
|
|
1046
|
-
ArcModel,
|
|
1047
1079
|
ArcIndexedCollection,
|
|
1048
1080
|
ArcId,
|
|
1049
1081
|
ArcDate,
|
|
1050
1082
|
ArcCollectionQuery,
|
|
1083
|
+
ArcCollection,
|
|
1051
1084
|
ArcBranded,
|
|
1052
1085
|
ArcBoolean,
|
|
1053
1086
|
ArcArray
|