@arcote.tech/arc-adapter-db-sqlite 0.7.14 → 0.7.15
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/index.js +193 -152
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1488,11 +1488,11 @@ class EventWire {
|
|
|
1488
1488
|
reconnectTimeout;
|
|
1489
1489
|
syncRequested = false;
|
|
1490
1490
|
viewSubscriptions = new Map;
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
constructor(baseUrl) {
|
|
1491
|
+
enableEventSync;
|
|
1492
|
+
constructor(baseUrl, options) {
|
|
1494
1493
|
this.baseUrl = baseUrl;
|
|
1495
1494
|
this.instanceId = ++eventWireInstanceCounter;
|
|
1495
|
+
this.enableEventSync = options?.enableEventSync ?? true;
|
|
1496
1496
|
}
|
|
1497
1497
|
setScopeToken(scope, token) {
|
|
1498
1498
|
if (token === null) {
|
|
@@ -1538,9 +1538,11 @@ class EventWire {
|
|
|
1538
1538
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
1539
1539
|
this.state = "connected";
|
|
1540
1540
|
this.sendAllScopeTokens();
|
|
1541
|
-
this.
|
|
1541
|
+
if (this.enableEventSync) {
|
|
1542
|
+
this.requestSync();
|
|
1543
|
+
}
|
|
1542
1544
|
this.flushPendingEvents();
|
|
1543
|
-
this.
|
|
1545
|
+
this.sendAllViewSubscriptions();
|
|
1544
1546
|
} else {
|
|
1545
1547
|
console.log(`[EventWire] onopen called but ws is not OPEN, readyState:`, this.ws?.readyState);
|
|
1546
1548
|
}
|
|
@@ -1616,30 +1618,26 @@ class EventWire {
|
|
|
1616
1618
|
onSynced(callback) {
|
|
1617
1619
|
this.onSyncedCallback = callback;
|
|
1618
1620
|
}
|
|
1619
|
-
|
|
1620
|
-
const
|
|
1621
|
-
this.viewSubscriptions.set(
|
|
1621
|
+
subscribeView(element, scope, callbacks) {
|
|
1622
|
+
const key = `${scope}:${element}`;
|
|
1623
|
+
this.viewSubscriptions.set(key, callbacks);
|
|
1622
1624
|
if (this.state === "connected" && this.ws) {
|
|
1623
1625
|
this.ws.send(JSON.stringify({
|
|
1624
|
-
type: "subscribe-
|
|
1625
|
-
|
|
1626
|
-
descriptor,
|
|
1626
|
+
type: "subscribe-view",
|
|
1627
|
+
element,
|
|
1627
1628
|
scope
|
|
1628
1629
|
}));
|
|
1629
|
-
} else {
|
|
1630
|
-
this.pendingViewSubs.push({ subscriptionId, descriptor, scope });
|
|
1631
1630
|
}
|
|
1632
|
-
return subscriptionId;
|
|
1633
1631
|
}
|
|
1634
|
-
|
|
1635
|
-
this.viewSubscriptions.delete(
|
|
1632
|
+
unsubscribeView(element, scope) {
|
|
1633
|
+
this.viewSubscriptions.delete(`${scope}:${element}`);
|
|
1636
1634
|
if (this.state === "connected" && this.ws) {
|
|
1637
1635
|
this.ws.send(JSON.stringify({
|
|
1638
|
-
type: "unsubscribe-
|
|
1639
|
-
|
|
1636
|
+
type: "unsubscribe-view",
|
|
1637
|
+
element,
|
|
1638
|
+
scope
|
|
1640
1639
|
}));
|
|
1641
1640
|
}
|
|
1642
|
-
this.pendingViewSubs = this.pendingViewSubs.filter((s) => s.subscriptionId !== subscriptionId);
|
|
1643
1641
|
}
|
|
1644
1642
|
getState() {
|
|
1645
1643
|
return this.state;
|
|
@@ -1672,10 +1670,17 @@ class EventWire {
|
|
|
1672
1670
|
this.lastHostEventId = message.lastHostEventId;
|
|
1673
1671
|
}
|
|
1674
1672
|
break;
|
|
1675
|
-
case "
|
|
1676
|
-
const
|
|
1677
|
-
if (
|
|
1678
|
-
|
|
1673
|
+
case "view-snapshot": {
|
|
1674
|
+
const sub = this.viewSubscriptions.get(`${message.scope}:${message.element}`);
|
|
1675
|
+
if (sub) {
|
|
1676
|
+
sub.onSnapshot(message.items ?? []);
|
|
1677
|
+
}
|
|
1678
|
+
break;
|
|
1679
|
+
}
|
|
1680
|
+
case "view-changes": {
|
|
1681
|
+
const sub = this.viewSubscriptions.get(`${message.scope}:${message.element}`);
|
|
1682
|
+
if (sub && Array.isArray(message.changes)) {
|
|
1683
|
+
sub.onChanges(message.changes);
|
|
1679
1684
|
}
|
|
1680
1685
|
break;
|
|
1681
1686
|
}
|
|
@@ -1703,18 +1708,19 @@ class EventWire {
|
|
|
1703
1708
|
this.pendingEvents = [];
|
|
1704
1709
|
}
|
|
1705
1710
|
}
|
|
1706
|
-
|
|
1711
|
+
sendAllViewSubscriptions() {
|
|
1707
1712
|
if (!this.ws || this.state !== "connected")
|
|
1708
1713
|
return;
|
|
1709
|
-
for (const
|
|
1714
|
+
for (const key of this.viewSubscriptions.keys()) {
|
|
1715
|
+
const sepIdx = key.indexOf(":");
|
|
1716
|
+
const scope = key.slice(0, sepIdx);
|
|
1717
|
+
const element = key.slice(sepIdx + 1);
|
|
1710
1718
|
this.ws.send(JSON.stringify({
|
|
1711
|
-
type: "subscribe-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
scope: sub.scope
|
|
1719
|
+
type: "subscribe-view",
|
|
1720
|
+
element,
|
|
1721
|
+
scope
|
|
1715
1722
|
}));
|
|
1716
1723
|
}
|
|
1717
|
-
this.pendingViewSubs = [];
|
|
1718
1724
|
}
|
|
1719
1725
|
scheduleReconnect() {
|
|
1720
1726
|
if (this.reconnectTimeout)
|
|
@@ -1736,12 +1742,19 @@ class LocalEventPublisher {
|
|
|
1736
1742
|
views = [];
|
|
1737
1743
|
syncCallback;
|
|
1738
1744
|
subscribers = new Map;
|
|
1745
|
+
viewChangesCallbacks = new Set;
|
|
1739
1746
|
constructor(dataStorage) {
|
|
1740
1747
|
this.dataStorage = dataStorage;
|
|
1741
1748
|
}
|
|
1742
1749
|
onPublish(callback) {
|
|
1743
1750
|
this.syncCallback = callback;
|
|
1744
1751
|
}
|
|
1752
|
+
onViewChanges(callback) {
|
|
1753
|
+
this.viewChangesCallbacks.add(callback);
|
|
1754
|
+
return () => {
|
|
1755
|
+
this.viewChangesCallbacks.delete(callback);
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1745
1758
|
registerViews(views) {
|
|
1746
1759
|
this.views = views;
|
|
1747
1760
|
}
|
|
@@ -1809,7 +1822,19 @@ class LocalEventPublisher {
|
|
|
1809
1822
|
});
|
|
1810
1823
|
const viewChanges = await this.collectViewChanges(event);
|
|
1811
1824
|
allChanges.push(...viewChanges);
|
|
1812
|
-
|
|
1825
|
+
const viewStoreNames = new Set(viewChanges.map((c) => c.store));
|
|
1826
|
+
const committed = await this.dataStorage.commitChanges(allChanges, {
|
|
1827
|
+
captureRowsFor: viewStoreNames
|
|
1828
|
+
});
|
|
1829
|
+
if (committed.length > 0 && this.viewChangesCallbacks.size > 0) {
|
|
1830
|
+
for (const callback of this.viewChangesCallbacks) {
|
|
1831
|
+
try {
|
|
1832
|
+
callback(committed);
|
|
1833
|
+
} catch (error) {
|
|
1834
|
+
console.error(`[EventPublisher] onViewChanges callback error:`, error);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1813
1838
|
await this.notifySubscribers(event);
|
|
1814
1839
|
if (this.syncCallback) {
|
|
1815
1840
|
this.syncCallback(event);
|
|
@@ -2449,8 +2474,9 @@ class ArcObject extends ArcAbstract {
|
|
|
2449
2474
|
}
|
|
2450
2475
|
}
|
|
2451
2476
|
class DataStorage {
|
|
2452
|
-
async commitChanges(changes) {
|
|
2477
|
+
async commitChanges(changes, _options) {
|
|
2453
2478
|
await Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applyChanges(changes2)));
|
|
2479
|
+
return [];
|
|
2454
2480
|
}
|
|
2455
2481
|
}
|
|
2456
2482
|
|
|
@@ -3689,12 +3715,23 @@ class MasterStoreState extends StoreState {
|
|
|
3689
3715
|
constructor(storeName, dataStorage, deserialize) {
|
|
3690
3716
|
super(storeName, dataStorage, deserialize);
|
|
3691
3717
|
}
|
|
3692
|
-
async
|
|
3718
|
+
async readExisting(transaction, id2, transactionCache) {
|
|
3719
|
+
const cacheKey = `${this.storeName}:${id2}`;
|
|
3720
|
+
if (transactionCache && transactionCache.has(cacheKey)) {
|
|
3721
|
+
return transactionCache.get(cacheKey);
|
|
3722
|
+
}
|
|
3723
|
+
return transaction.find(this.storeName, { where: { _id: id2 } }).then((results) => results[0]);
|
|
3724
|
+
}
|
|
3725
|
+
async applyChangeAndReturnEvent(transaction, change, transactionCache, options) {
|
|
3693
3726
|
if (change.type === "set") {
|
|
3727
|
+
let existing;
|
|
3728
|
+
if (options?.captureRows) {
|
|
3729
|
+
existing = await this.readExisting(transaction, change.data._id, transactionCache);
|
|
3730
|
+
}
|
|
3694
3731
|
await transaction.set(this.storeName, change.data);
|
|
3695
3732
|
const item = this.deserialize ? this.deserialize(change.data) : change.data;
|
|
3696
3733
|
if (transactionCache) {
|
|
3697
|
-
transactionCache.set(change.data._id
|
|
3734
|
+
transactionCache.set(`${this.storeName}:${change.data._id}`, item);
|
|
3698
3735
|
}
|
|
3699
3736
|
return {
|
|
3700
3737
|
from: null,
|
|
@@ -3703,11 +3740,20 @@ class MasterStoreState extends StoreState {
|
|
|
3703
3740
|
type: "set",
|
|
3704
3741
|
item: change.data,
|
|
3705
3742
|
id: change.data._id
|
|
3706
|
-
}
|
|
3743
|
+
},
|
|
3744
|
+
oldRow: existing ?? null,
|
|
3745
|
+
newRow: change.data
|
|
3707
3746
|
};
|
|
3708
3747
|
}
|
|
3709
3748
|
if (change.type === "delete") {
|
|
3749
|
+
let existing;
|
|
3750
|
+
if (options?.captureRows) {
|
|
3751
|
+
existing = await this.readExisting(transaction, change.id, transactionCache);
|
|
3752
|
+
}
|
|
3710
3753
|
await transaction.remove(this.storeName, change.id);
|
|
3754
|
+
if (transactionCache) {
|
|
3755
|
+
transactionCache.delete(`${this.storeName}:${change.id}`);
|
|
3756
|
+
}
|
|
3711
3757
|
return {
|
|
3712
3758
|
from: null,
|
|
3713
3759
|
to: null,
|
|
@@ -3715,21 +3761,18 @@ class MasterStoreState extends StoreState {
|
|
|
3715
3761
|
type: "delete",
|
|
3716
3762
|
item: null,
|
|
3717
3763
|
id: change.id
|
|
3718
|
-
}
|
|
3764
|
+
},
|
|
3765
|
+
oldRow: existing ?? null,
|
|
3766
|
+
newRow: null
|
|
3719
3767
|
};
|
|
3720
3768
|
}
|
|
3721
3769
|
if (change.type === "modify") {
|
|
3722
|
-
|
|
3723
|
-
if (transactionCache && transactionCache.has(change.id)) {
|
|
3724
|
-
existing = transactionCache.get(change.id);
|
|
3725
|
-
} else {
|
|
3726
|
-
existing = await transaction.find(this.storeName, { where: { _id: change.id } }).then((results) => results[0]);
|
|
3727
|
-
}
|
|
3770
|
+
const existing = await this.readExisting(transaction, change.id, transactionCache);
|
|
3728
3771
|
const updated = existing ? deepMerge(existing, change.data) : { _id: change.id, ...change.data };
|
|
3729
3772
|
await transaction.set(this.storeName, updated);
|
|
3730
3773
|
const item = this.deserialize ? this.deserialize(updated) : updated;
|
|
3731
3774
|
if (transactionCache) {
|
|
3732
|
-
transactionCache.set(change.id
|
|
3775
|
+
transactionCache.set(`${this.storeName}:${change.id}`, item);
|
|
3733
3776
|
}
|
|
3734
3777
|
return {
|
|
3735
3778
|
from: null,
|
|
@@ -3738,21 +3781,18 @@ class MasterStoreState extends StoreState {
|
|
|
3738
3781
|
type: "set",
|
|
3739
3782
|
item,
|
|
3740
3783
|
id: change.id
|
|
3741
|
-
}
|
|
3784
|
+
},
|
|
3785
|
+
oldRow: existing ?? null,
|
|
3786
|
+
newRow: updated
|
|
3742
3787
|
};
|
|
3743
3788
|
}
|
|
3744
3789
|
if (change.type === "mutate") {
|
|
3745
|
-
|
|
3746
|
-
if (transactionCache && transactionCache.has(change.id)) {
|
|
3747
|
-
existing = transactionCache.get(change.id);
|
|
3748
|
-
} else {
|
|
3749
|
-
existing = await transaction.find(this.storeName, { where: { _id: change.id } }).then((results) => results[0]);
|
|
3750
|
-
}
|
|
3790
|
+
const existing = await this.readExisting(transaction, change.id, transactionCache);
|
|
3751
3791
|
const updated = apply(existing || {}, change.patches);
|
|
3752
3792
|
await transaction.set(this.storeName, updated);
|
|
3753
3793
|
const item = this.deserialize ? this.deserialize(updated) : updated;
|
|
3754
3794
|
if (transactionCache) {
|
|
3755
|
-
transactionCache.set(change.id
|
|
3795
|
+
transactionCache.set(`${this.storeName}:${change.id}`, item);
|
|
3756
3796
|
}
|
|
3757
3797
|
return {
|
|
3758
3798
|
from: null,
|
|
@@ -3761,7 +3801,9 @@ class MasterStoreState extends StoreState {
|
|
|
3761
3801
|
type: "set",
|
|
3762
3802
|
item,
|
|
3763
3803
|
id: change.id
|
|
3764
|
-
}
|
|
3804
|
+
},
|
|
3805
|
+
oldRow: existing ?? null,
|
|
3806
|
+
newRow: updated
|
|
3765
3807
|
};
|
|
3766
3808
|
}
|
|
3767
3809
|
throw new Error("Unknown change type");
|
|
@@ -3839,17 +3881,22 @@ class MasterDataStorage extends DataStorage {
|
|
|
3839
3881
|
applySerializedChanges(changes) {
|
|
3840
3882
|
return Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applySerializedChanges(changes2)));
|
|
3841
3883
|
}
|
|
3842
|
-
async commitChanges(changes) {
|
|
3884
|
+
async commitChanges(changes, options) {
|
|
3843
3885
|
const transaction = await this.getReadWriteTransaction();
|
|
3844
3886
|
const transactionCache = new Map;
|
|
3845
3887
|
const eventsByStore = new Map;
|
|
3888
|
+
const committed = [];
|
|
3846
3889
|
for (const { store, changes: storeChanges } of changes) {
|
|
3847
3890
|
const storeState = this.getStore(store);
|
|
3848
3891
|
const storeEvents = [];
|
|
3892
|
+
const capture = options?.captureRowsFor?.has(store) ?? false;
|
|
3849
3893
|
for (const change of storeChanges) {
|
|
3850
|
-
const { event: event3 } = await storeState.applyChangeAndReturnEvent(transaction, change, transactionCache);
|
|
3894
|
+
const { event: event3, oldRow, newRow } = await storeState.applyChangeAndReturnEvent(transaction, change, transactionCache, { captureRows: capture });
|
|
3851
3895
|
if (event3)
|
|
3852
3896
|
storeEvents.push(event3);
|
|
3897
|
+
if (capture) {
|
|
3898
|
+
committed.push({ store, id: event3.id, oldRow, newRow });
|
|
3899
|
+
}
|
|
3853
3900
|
}
|
|
3854
3901
|
if (storeEvents.length > 0) {
|
|
3855
3902
|
eventsByStore.set(store, storeEvents);
|
|
@@ -3860,6 +3907,7 @@ class MasterDataStorage extends DataStorage {
|
|
|
3860
3907
|
const storeState = this.getStore(store);
|
|
3861
3908
|
storeState.notifyListenersPublic(events);
|
|
3862
3909
|
}
|
|
3910
|
+
return committed;
|
|
3863
3911
|
}
|
|
3864
3912
|
fork() {
|
|
3865
3913
|
return new ForkedDataStorage(this);
|
|
@@ -3974,8 +4022,8 @@ class ObservableDataStorage {
|
|
|
3974
4022
|
getReadWriteTransaction() {
|
|
3975
4023
|
return this.source.getReadWriteTransaction();
|
|
3976
4024
|
}
|
|
3977
|
-
commitChanges(changes) {
|
|
3978
|
-
return this.source.commitChanges(changes);
|
|
4025
|
+
commitChanges(changes, options) {
|
|
4026
|
+
return this.source.commitChanges(changes, options);
|
|
3979
4027
|
}
|
|
3980
4028
|
trackQuery(storeName, options, result, listener4) {
|
|
3981
4029
|
const key = this.getQueryKey(storeName, options);
|
|
@@ -4219,13 +4267,6 @@ class ScopedModel {
|
|
|
4219
4267
|
}
|
|
4220
4268
|
return wire.query(viewName, options, this.getAuth());
|
|
4221
4269
|
}
|
|
4222
|
-
subscribeQuery(descriptor, callback) {
|
|
4223
|
-
const wire = this.parent.getAdapters().eventWire;
|
|
4224
|
-
if (!wire) {
|
|
4225
|
-
throw new Error(`Cannot subscribe to query: no eventWire available.`);
|
|
4226
|
-
}
|
|
4227
|
-
return wire.subscribeQuery(descriptor, callback, this.scopeName);
|
|
4228
|
-
}
|
|
4229
4270
|
get query() {
|
|
4230
4271
|
return buildContextAccessor(this.context, this.scopedAdapters, "queryContext", (descriptor) => descriptor);
|
|
4231
4272
|
}
|
|
@@ -4281,120 +4322,107 @@ class Model {
|
|
|
4281
4322
|
return s;
|
|
4282
4323
|
}
|
|
4283
4324
|
}
|
|
4325
|
+
var DEFAULT_SCOPE = "default";
|
|
4326
|
+
|
|
4284
4327
|
class StreamingQueryCache {
|
|
4285
4328
|
stores = new Map;
|
|
4286
4329
|
views = [];
|
|
4287
4330
|
activeStreams = new Map;
|
|
4288
4331
|
pendingUnsubscribes = new Map;
|
|
4289
|
-
streamScopes = new Map;
|
|
4290
4332
|
static UNSUBSCRIBE_DELAY_MS = 5000;
|
|
4333
|
+
storeKey(viewName, scope) {
|
|
4334
|
+
return `${scope ?? DEFAULT_SCOPE}:${viewName}`;
|
|
4335
|
+
}
|
|
4291
4336
|
registerViews(views) {
|
|
4292
4337
|
this.views = views;
|
|
4293
|
-
for (const view3 of views) {
|
|
4294
|
-
if (!this.stores.has(view3.name)) {
|
|
4295
|
-
this.stores.set(view3.name, new StreamingStore);
|
|
4296
|
-
}
|
|
4297
|
-
}
|
|
4298
4338
|
}
|
|
4299
|
-
getStore(viewName) {
|
|
4300
|
-
|
|
4301
|
-
|
|
4339
|
+
getStore(viewName, scope) {
|
|
4340
|
+
const key = this.storeKey(viewName, scope);
|
|
4341
|
+
if (!this.stores.has(key)) {
|
|
4342
|
+
this.stores.set(key, new StreamingStore);
|
|
4302
4343
|
}
|
|
4303
|
-
return this.stores.get(
|
|
4344
|
+
return this.stores.get(key);
|
|
4304
4345
|
}
|
|
4305
|
-
hasData(viewName) {
|
|
4306
|
-
const store = this.stores.get(viewName);
|
|
4346
|
+
hasData(viewName, scope) {
|
|
4347
|
+
const store = this.stores.get(this.storeKey(viewName, scope));
|
|
4307
4348
|
return store ? store.hasData() : false;
|
|
4308
4349
|
}
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
}
|
|
4312
|
-
registerStream(viewName, createStream) {
|
|
4313
|
-
const pending = this.pendingUnsubscribes.get(viewName);
|
|
4350
|
+
registerStream(key, createStream) {
|
|
4351
|
+
const pending = this.pendingUnsubscribes.get(key);
|
|
4314
4352
|
if (pending) {
|
|
4315
4353
|
clearTimeout(pending);
|
|
4316
|
-
this.pendingUnsubscribes.delete(
|
|
4354
|
+
this.pendingUnsubscribes.delete(key);
|
|
4317
4355
|
}
|
|
4318
|
-
const existing = this.activeStreams.get(
|
|
4356
|
+
const existing = this.activeStreams.get(key);
|
|
4319
4357
|
if (existing) {
|
|
4320
4358
|
existing.refCount++;
|
|
4321
4359
|
return {
|
|
4322
|
-
unsubscribe: () => this.unregisterStream(
|
|
4360
|
+
unsubscribe: () => this.unregisterStream(key),
|
|
4323
4361
|
wasReused: true
|
|
4324
4362
|
};
|
|
4325
4363
|
}
|
|
4326
4364
|
const streamConn = createStream();
|
|
4327
|
-
this.activeStreams.set(
|
|
4365
|
+
this.activeStreams.set(key, {
|
|
4328
4366
|
unsubscribe: streamConn.unsubscribe,
|
|
4329
4367
|
refCount: 1
|
|
4330
4368
|
});
|
|
4331
4369
|
return {
|
|
4332
|
-
unsubscribe: () => this.unregisterStream(
|
|
4370
|
+
unsubscribe: () => this.unregisterStream(key),
|
|
4333
4371
|
wasReused: false
|
|
4334
4372
|
};
|
|
4335
4373
|
}
|
|
4336
|
-
unregisterStream(
|
|
4337
|
-
const stream = this.activeStreams.get(
|
|
4374
|
+
unregisterStream(key) {
|
|
4375
|
+
const stream = this.activeStreams.get(key);
|
|
4338
4376
|
if (!stream)
|
|
4339
4377
|
return;
|
|
4340
4378
|
stream.refCount--;
|
|
4341
4379
|
if (stream.refCount <= 0) {
|
|
4342
4380
|
const timeout = setTimeout(() => {
|
|
4343
|
-
this.pendingUnsubscribes.delete(
|
|
4344
|
-
const current2 = this.activeStreams.get(
|
|
4381
|
+
this.pendingUnsubscribes.delete(key);
|
|
4382
|
+
const current2 = this.activeStreams.get(key);
|
|
4345
4383
|
if (current2 && current2.refCount <= 0) {
|
|
4346
4384
|
current2.unsubscribe();
|
|
4347
|
-
this.activeStreams.delete(
|
|
4348
|
-
this.streamScopes.delete(viewName);
|
|
4385
|
+
this.activeStreams.delete(key);
|
|
4349
4386
|
}
|
|
4350
4387
|
}, StreamingQueryCache.UNSUBSCRIBE_DELAY_MS);
|
|
4351
|
-
this.pendingUnsubscribes.set(
|
|
4388
|
+
this.pendingUnsubscribes.set(key, timeout);
|
|
4352
4389
|
}
|
|
4353
4390
|
}
|
|
4354
|
-
|
|
4355
|
-
const key =
|
|
4356
|
-
if (scope)
|
|
4357
|
-
this.streamScopes.set(key, scope);
|
|
4391
|
+
subscribeView(viewName, eventWire, scope) {
|
|
4392
|
+
const key = this.storeKey(viewName, scope);
|
|
4358
4393
|
const { unsubscribe } = this.registerStream(key, () => {
|
|
4359
|
-
const
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4394
|
+
const store = this.stores.get(key) ?? new StreamingStore;
|
|
4395
|
+
this.stores.set(key, store);
|
|
4396
|
+
eventWire.subscribeView(viewName, scope ?? DEFAULT_SCOPE, {
|
|
4397
|
+
onSnapshot: (items) => store.setAll(items),
|
|
4398
|
+
onChanges: (changes) => store.applyChanges(changes)
|
|
4399
|
+
});
|
|
4400
|
+
return {
|
|
4401
|
+
unsubscribe: () => eventWire.unsubscribeView(viewName, scope ?? DEFAULT_SCOPE)
|
|
4402
|
+
};
|
|
4363
4403
|
});
|
|
4364
4404
|
return unsubscribe;
|
|
4365
4405
|
}
|
|
4366
4406
|
invalidateScope(scope) {
|
|
4367
|
-
|
|
4368
|
-
|
|
4407
|
+
const prefix = `${scope}:`;
|
|
4408
|
+
for (const [key, timeout] of this.pendingUnsubscribes) {
|
|
4409
|
+
if (!key.startsWith(prefix))
|
|
4369
4410
|
continue;
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
clearTimeout(pending);
|
|
4373
|
-
this.pendingUnsubscribes.delete(viewName);
|
|
4374
|
-
}
|
|
4375
|
-
const stream = this.activeStreams.get(viewName);
|
|
4376
|
-
if (stream) {
|
|
4377
|
-
try {
|
|
4378
|
-
stream.unsubscribe();
|
|
4379
|
-
} catch {}
|
|
4380
|
-
this.activeStreams.delete(viewName);
|
|
4381
|
-
}
|
|
4382
|
-
this.streamScopes.delete(viewName);
|
|
4383
|
-
const store = this.stores.get(viewName);
|
|
4384
|
-
if (store)
|
|
4385
|
-
store.clear();
|
|
4411
|
+
clearTimeout(timeout);
|
|
4412
|
+
this.pendingUnsubscribes.delete(key);
|
|
4386
4413
|
}
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
}
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4414
|
+
for (const [key, stream] of this.activeStreams) {
|
|
4415
|
+
if (!key.startsWith(prefix))
|
|
4416
|
+
continue;
|
|
4417
|
+
try {
|
|
4418
|
+
stream.unsubscribe();
|
|
4419
|
+
} catch {}
|
|
4420
|
+
this.activeStreams.delete(key);
|
|
4421
|
+
}
|
|
4422
|
+
for (const [key, store] of this.stores) {
|
|
4423
|
+
if (!key.startsWith(prefix))
|
|
4424
|
+
continue;
|
|
4425
|
+
store.clear();
|
|
4398
4426
|
}
|
|
4399
4427
|
}
|
|
4400
4428
|
async applyEvent(event3) {
|
|
@@ -4403,28 +4431,30 @@ class StreamingQueryCache {
|
|
|
4403
4431
|
const handler = handlers[event3.type];
|
|
4404
4432
|
if (!handler)
|
|
4405
4433
|
continue;
|
|
4406
|
-
const
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4434
|
+
const suffix = `:${view3.name}`;
|
|
4435
|
+
for (const [key, store] of this.stores) {
|
|
4436
|
+
if (!key.endsWith(suffix))
|
|
4437
|
+
continue;
|
|
4438
|
+
const ctx = {
|
|
4439
|
+
set: async (id3, data) => {
|
|
4440
|
+
store.set(String(id3), { _id: String(id3), ...data });
|
|
4441
|
+
},
|
|
4442
|
+
modify: async (id3, data) => {
|
|
4443
|
+
store.modify(String(id3), data);
|
|
4444
|
+
},
|
|
4445
|
+
remove: async (id3) => {
|
|
4446
|
+
store.remove(String(id3));
|
|
4447
|
+
},
|
|
4448
|
+
find: async (options) => {
|
|
4449
|
+
return store.find(options);
|
|
4450
|
+
},
|
|
4451
|
+
findOne: async (where) => {
|
|
4452
|
+
return store.findOne(where);
|
|
4453
|
+
},
|
|
4454
|
+
$auth: {}
|
|
4455
|
+
};
|
|
4456
|
+
await handler(ctx, event3);
|
|
4457
|
+
}
|
|
4428
4458
|
}
|
|
4429
4459
|
}
|
|
4430
4460
|
clear() {
|
|
@@ -4432,7 +4462,6 @@ class StreamingQueryCache {
|
|
|
4432
4462
|
stream.unsubscribe();
|
|
4433
4463
|
}
|
|
4434
4464
|
this.activeStreams.clear();
|
|
4435
|
-
this.streamScopes.clear();
|
|
4436
4465
|
for (const timeout of this.pendingUnsubscribes.values()) {
|
|
4437
4466
|
clearTimeout(timeout);
|
|
4438
4467
|
}
|
|
@@ -4458,6 +4487,18 @@ class StreamingStore {
|
|
|
4458
4487
|
}
|
|
4459
4488
|
this.notifyListeners(null);
|
|
4460
4489
|
}
|
|
4490
|
+
applyChanges(events) {
|
|
4491
|
+
if (events.length === 0)
|
|
4492
|
+
return;
|
|
4493
|
+
for (const event3 of events) {
|
|
4494
|
+
if (event3.type === "set" && event3.item) {
|
|
4495
|
+
this.data.set(event3.id, event3.item);
|
|
4496
|
+
} else if (event3.type === "delete") {
|
|
4497
|
+
this.data.delete(event3.id);
|
|
4498
|
+
}
|
|
4499
|
+
}
|
|
4500
|
+
this.notifyListeners(events);
|
|
4501
|
+
}
|
|
4461
4502
|
set(id3, item) {
|
|
4462
4503
|
this.data.set(id3, item);
|
|
4463
4504
|
this.notifyListeners([{ type: "set", id: id3, item }]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcote.tech/arc-adapter-db-sqlite",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"test": "bun test"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@arcote.tech/arc": "^0.7.
|
|
23
|
+
"@arcote.tech/arc": "^0.7.15"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"typescript": "^5.0.0"
|