@arcote.tech/arc-adapter-db-sqlite 0.7.15 → 0.7.16
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 +196 -290
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1487,7 +1487,8 @@ class EventWire {
|
|
|
1487
1487
|
onSyncedCallback;
|
|
1488
1488
|
reconnectTimeout;
|
|
1489
1489
|
syncRequested = false;
|
|
1490
|
-
|
|
1490
|
+
querySubscriptions = new Map;
|
|
1491
|
+
querySubCounter = 0;
|
|
1491
1492
|
enableEventSync;
|
|
1492
1493
|
constructor(baseUrl, options) {
|
|
1493
1494
|
this.baseUrl = baseUrl;
|
|
@@ -1542,7 +1543,7 @@ class EventWire {
|
|
|
1542
1543
|
this.requestSync();
|
|
1543
1544
|
}
|
|
1544
1545
|
this.flushPendingEvents();
|
|
1545
|
-
this.
|
|
1546
|
+
this.sendAllQuerySubscriptions();
|
|
1546
1547
|
} else {
|
|
1547
1548
|
console.log(`[EventWire] onopen called but ws is not OPEN, readyState:`, this.ws?.readyState);
|
|
1548
1549
|
}
|
|
@@ -1618,24 +1619,29 @@ class EventWire {
|
|
|
1618
1619
|
onSynced(callback) {
|
|
1619
1620
|
this.onSyncedCallback = callback;
|
|
1620
1621
|
}
|
|
1621
|
-
|
|
1622
|
-
const
|
|
1623
|
-
this.
|
|
1622
|
+
subscribeQuery(descriptor, scope, callbacks) {
|
|
1623
|
+
const subscriptionId = `qs_${this.instanceId}_${++this.querySubCounter}`;
|
|
1624
|
+
this.querySubscriptions.set(subscriptionId, {
|
|
1625
|
+
descriptor,
|
|
1626
|
+
scope,
|
|
1627
|
+
callbacks
|
|
1628
|
+
});
|
|
1624
1629
|
if (this.state === "connected" && this.ws) {
|
|
1625
1630
|
this.ws.send(JSON.stringify({
|
|
1626
|
-
type: "subscribe-
|
|
1627
|
-
|
|
1631
|
+
type: "subscribe-query",
|
|
1632
|
+
subscriptionId,
|
|
1633
|
+
descriptor,
|
|
1628
1634
|
scope
|
|
1629
1635
|
}));
|
|
1630
1636
|
}
|
|
1637
|
+
return subscriptionId;
|
|
1631
1638
|
}
|
|
1632
|
-
|
|
1633
|
-
this.
|
|
1639
|
+
unsubscribeQuery(subscriptionId) {
|
|
1640
|
+
this.querySubscriptions.delete(subscriptionId);
|
|
1634
1641
|
if (this.state === "connected" && this.ws) {
|
|
1635
1642
|
this.ws.send(JSON.stringify({
|
|
1636
|
-
type: "unsubscribe-
|
|
1637
|
-
|
|
1638
|
-
scope
|
|
1643
|
+
type: "unsubscribe-query",
|
|
1644
|
+
subscriptionId
|
|
1639
1645
|
}));
|
|
1640
1646
|
}
|
|
1641
1647
|
}
|
|
@@ -1670,17 +1676,17 @@ class EventWire {
|
|
|
1670
1676
|
this.lastHostEventId = message.lastHostEventId;
|
|
1671
1677
|
}
|
|
1672
1678
|
break;
|
|
1673
|
-
case "
|
|
1674
|
-
const sub = this.
|
|
1679
|
+
case "query-snapshot": {
|
|
1680
|
+
const sub = this.querySubscriptions.get(message.subscriptionId);
|
|
1675
1681
|
if (sub) {
|
|
1676
|
-
sub.onSnapshot(message.
|
|
1682
|
+
sub.callbacks.onSnapshot(message.result ?? null);
|
|
1677
1683
|
}
|
|
1678
1684
|
break;
|
|
1679
1685
|
}
|
|
1680
|
-
case "
|
|
1681
|
-
const sub = this.
|
|
1686
|
+
case "query-changes": {
|
|
1687
|
+
const sub = this.querySubscriptions.get(message.subscriptionId);
|
|
1682
1688
|
if (sub && Array.isArray(message.changes)) {
|
|
1683
|
-
sub.onChanges(message.changes);
|
|
1689
|
+
sub.callbacks.onChanges(message.changes);
|
|
1684
1690
|
}
|
|
1685
1691
|
break;
|
|
1686
1692
|
}
|
|
@@ -1708,17 +1714,15 @@ class EventWire {
|
|
|
1708
1714
|
this.pendingEvents = [];
|
|
1709
1715
|
}
|
|
1710
1716
|
}
|
|
1711
|
-
|
|
1717
|
+
sendAllQuerySubscriptions() {
|
|
1712
1718
|
if (!this.ws || this.state !== "connected")
|
|
1713
1719
|
return;
|
|
1714
|
-
for (const
|
|
1715
|
-
const sepIdx = key.indexOf(":");
|
|
1716
|
-
const scope = key.slice(0, sepIdx);
|
|
1717
|
-
const element = key.slice(sepIdx + 1);
|
|
1720
|
+
for (const [subscriptionId, sub] of this.querySubscriptions) {
|
|
1718
1721
|
this.ws.send(JSON.stringify({
|
|
1719
|
-
type: "subscribe-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
+
type: "subscribe-query",
|
|
1723
|
+
subscriptionId,
|
|
1724
|
+
descriptor: sub.descriptor,
|
|
1725
|
+
scope: sub.scope
|
|
1722
1726
|
}));
|
|
1723
1727
|
}
|
|
1724
1728
|
}
|
|
@@ -1742,19 +1746,12 @@ class LocalEventPublisher {
|
|
|
1742
1746
|
views = [];
|
|
1743
1747
|
syncCallback;
|
|
1744
1748
|
subscribers = new Map;
|
|
1745
|
-
viewChangesCallbacks = new Set;
|
|
1746
1749
|
constructor(dataStorage) {
|
|
1747
1750
|
this.dataStorage = dataStorage;
|
|
1748
1751
|
}
|
|
1749
1752
|
onPublish(callback) {
|
|
1750
1753
|
this.syncCallback = callback;
|
|
1751
1754
|
}
|
|
1752
|
-
onViewChanges(callback) {
|
|
1753
|
-
this.viewChangesCallbacks.add(callback);
|
|
1754
|
-
return () => {
|
|
1755
|
-
this.viewChangesCallbacks.delete(callback);
|
|
1756
|
-
};
|
|
1757
|
-
}
|
|
1758
1755
|
registerViews(views) {
|
|
1759
1756
|
this.views = views;
|
|
1760
1757
|
}
|
|
@@ -1822,19 +1819,7 @@ class LocalEventPublisher {
|
|
|
1822
1819
|
});
|
|
1823
1820
|
const viewChanges = await this.collectViewChanges(event);
|
|
1824
1821
|
allChanges.push(...viewChanges);
|
|
1825
|
-
|
|
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
|
-
}
|
|
1822
|
+
await this.dataStorage.commitChanges(allChanges);
|
|
1838
1823
|
await this.notifySubscribers(event);
|
|
1839
1824
|
if (this.syncCallback) {
|
|
1840
1825
|
this.syncCallback(event);
|
|
@@ -2474,9 +2459,8 @@ class ArcObject extends ArcAbstract {
|
|
|
2474
2459
|
}
|
|
2475
2460
|
}
|
|
2476
2461
|
class DataStorage {
|
|
2477
|
-
async commitChanges(changes
|
|
2462
|
+
async commitChanges(changes) {
|
|
2478
2463
|
await Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applyChanges(changes2)));
|
|
2479
|
-
return [];
|
|
2480
2464
|
}
|
|
2481
2465
|
}
|
|
2482
2466
|
|
|
@@ -3567,6 +3551,48 @@ function deepMerge(target, source) {
|
|
|
3567
3551
|
function isPlainObject(item) {
|
|
3568
3552
|
return item && typeof item === "object" && !Array.isArray(item) && !(item instanceof Date) && Object.prototype.toString.call(item) === "[object Object]";
|
|
3569
3553
|
}
|
|
3554
|
+
function murmurHash(key, seed = 0) {
|
|
3555
|
+
let remainder, bytes, h1, h1b, c1, c2, k1, i;
|
|
3556
|
+
remainder = key.length & 3;
|
|
3557
|
+
bytes = key.length - remainder;
|
|
3558
|
+
h1 = seed;
|
|
3559
|
+
c1 = 3432918353;
|
|
3560
|
+
c2 = 461845907;
|
|
3561
|
+
i = 0;
|
|
3562
|
+
while (i < bytes) {
|
|
3563
|
+
k1 = key.charCodeAt(i) & 255 | (key.charCodeAt(++i) & 255) << 8 | (key.charCodeAt(++i) & 255) << 16 | (key.charCodeAt(++i) & 255) << 24;
|
|
3564
|
+
++i;
|
|
3565
|
+
k1 = (k1 & 65535) * c1 + (((k1 >>> 16) * c1 & 65535) << 16) & 4294967295;
|
|
3566
|
+
k1 = k1 << 15 | k1 >>> 17;
|
|
3567
|
+
k1 = (k1 & 65535) * c2 + (((k1 >>> 16) * c2 & 65535) << 16) & 4294967295;
|
|
3568
|
+
h1 ^= k1;
|
|
3569
|
+
h1 = h1 << 13 | h1 >>> 19;
|
|
3570
|
+
h1b = (h1 & 65535) * 5 + (((h1 >>> 16) * 5 & 65535) << 16) & 4294967295;
|
|
3571
|
+
h1 = (h1b & 65535) + 27492 + (((h1b >>> 16) + 58964 & 65535) << 16);
|
|
3572
|
+
}
|
|
3573
|
+
k1 = 0;
|
|
3574
|
+
if (remainder >= 3) {
|
|
3575
|
+
k1 ^= (key.charCodeAt(i + 2) & 255) << 16;
|
|
3576
|
+
}
|
|
3577
|
+
if (remainder >= 2) {
|
|
3578
|
+
k1 ^= (key.charCodeAt(i + 1) & 255) << 8;
|
|
3579
|
+
}
|
|
3580
|
+
if (remainder >= 1) {
|
|
3581
|
+
k1 ^= key.charCodeAt(i) & 255;
|
|
3582
|
+
k1 = (k1 & 65535) * c1 + (((k1 >>> 16) * c1 & 65535) << 16) & 4294967295;
|
|
3583
|
+
k1 = k1 << 15 | k1 >>> 17;
|
|
3584
|
+
k1 = (k1 & 65535) * c2 + (((k1 >>> 16) * c2 & 65535) << 16) & 4294967295;
|
|
3585
|
+
h1 ^= k1;
|
|
3586
|
+
}
|
|
3587
|
+
h1 ^= key.length;
|
|
3588
|
+
h1 ^= h1 >>> 16;
|
|
3589
|
+
h1 = (h1 & 65535) * 2246822507 + (((h1 >>> 16) * 2246822507 & 65535) << 16) & 4294967295;
|
|
3590
|
+
h1 ^= h1 >>> 13;
|
|
3591
|
+
h1 = (h1 & 65535) * 3266489909 + (((h1 >>> 16) * 3266489909 & 65535) << 16) & 4294967295;
|
|
3592
|
+
h1 ^= h1 >>> 16;
|
|
3593
|
+
return h1 >>> 0;
|
|
3594
|
+
}
|
|
3595
|
+
|
|
3570
3596
|
class ForkedStoreState extends StoreState {
|
|
3571
3597
|
master;
|
|
3572
3598
|
changedItems = new Map;
|
|
@@ -3722,12 +3748,8 @@ class MasterStoreState extends StoreState {
|
|
|
3722
3748
|
}
|
|
3723
3749
|
return transaction.find(this.storeName, { where: { _id: id2 } }).then((results) => results[0]);
|
|
3724
3750
|
}
|
|
3725
|
-
async applyChangeAndReturnEvent(transaction, change, transactionCache
|
|
3751
|
+
async applyChangeAndReturnEvent(transaction, change, transactionCache) {
|
|
3726
3752
|
if (change.type === "set") {
|
|
3727
|
-
let existing;
|
|
3728
|
-
if (options?.captureRows) {
|
|
3729
|
-
existing = await this.readExisting(transaction, change.data._id, transactionCache);
|
|
3730
|
-
}
|
|
3731
3753
|
await transaction.set(this.storeName, change.data);
|
|
3732
3754
|
const item = this.deserialize ? this.deserialize(change.data) : change.data;
|
|
3733
3755
|
if (transactionCache) {
|
|
@@ -3740,16 +3762,10 @@ class MasterStoreState extends StoreState {
|
|
|
3740
3762
|
type: "set",
|
|
3741
3763
|
item: change.data,
|
|
3742
3764
|
id: change.data._id
|
|
3743
|
-
}
|
|
3744
|
-
oldRow: existing ?? null,
|
|
3745
|
-
newRow: change.data
|
|
3765
|
+
}
|
|
3746
3766
|
};
|
|
3747
3767
|
}
|
|
3748
3768
|
if (change.type === "delete") {
|
|
3749
|
-
let existing;
|
|
3750
|
-
if (options?.captureRows) {
|
|
3751
|
-
existing = await this.readExisting(transaction, change.id, transactionCache);
|
|
3752
|
-
}
|
|
3753
3769
|
await transaction.remove(this.storeName, change.id);
|
|
3754
3770
|
if (transactionCache) {
|
|
3755
3771
|
transactionCache.delete(`${this.storeName}:${change.id}`);
|
|
@@ -3761,9 +3777,7 @@ class MasterStoreState extends StoreState {
|
|
|
3761
3777
|
type: "delete",
|
|
3762
3778
|
item: null,
|
|
3763
3779
|
id: change.id
|
|
3764
|
-
}
|
|
3765
|
-
oldRow: existing ?? null,
|
|
3766
|
-
newRow: null
|
|
3780
|
+
}
|
|
3767
3781
|
};
|
|
3768
3782
|
}
|
|
3769
3783
|
if (change.type === "modify") {
|
|
@@ -3781,9 +3795,7 @@ class MasterStoreState extends StoreState {
|
|
|
3781
3795
|
type: "set",
|
|
3782
3796
|
item,
|
|
3783
3797
|
id: change.id
|
|
3784
|
-
}
|
|
3785
|
-
oldRow: existing ?? null,
|
|
3786
|
-
newRow: updated
|
|
3798
|
+
}
|
|
3787
3799
|
};
|
|
3788
3800
|
}
|
|
3789
3801
|
if (change.type === "mutate") {
|
|
@@ -3801,9 +3813,7 @@ class MasterStoreState extends StoreState {
|
|
|
3801
3813
|
type: "set",
|
|
3802
3814
|
item,
|
|
3803
3815
|
id: change.id
|
|
3804
|
-
}
|
|
3805
|
-
oldRow: existing ?? null,
|
|
3806
|
-
newRow: updated
|
|
3816
|
+
}
|
|
3807
3817
|
};
|
|
3808
3818
|
}
|
|
3809
3819
|
throw new Error("Unknown change type");
|
|
@@ -3881,22 +3891,17 @@ class MasterDataStorage extends DataStorage {
|
|
|
3881
3891
|
applySerializedChanges(changes) {
|
|
3882
3892
|
return Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applySerializedChanges(changes2)));
|
|
3883
3893
|
}
|
|
3884
|
-
async commitChanges(changes
|
|
3894
|
+
async commitChanges(changes) {
|
|
3885
3895
|
const transaction = await this.getReadWriteTransaction();
|
|
3886
3896
|
const transactionCache = new Map;
|
|
3887
3897
|
const eventsByStore = new Map;
|
|
3888
|
-
const committed = [];
|
|
3889
3898
|
for (const { store, changes: storeChanges } of changes) {
|
|
3890
3899
|
const storeState = this.getStore(store);
|
|
3891
3900
|
const storeEvents = [];
|
|
3892
|
-
const capture = options?.captureRowsFor?.has(store) ?? false;
|
|
3893
3901
|
for (const change of storeChanges) {
|
|
3894
|
-
const { event: event3
|
|
3902
|
+
const { event: event3 } = await storeState.applyChangeAndReturnEvent(transaction, change, transactionCache);
|
|
3895
3903
|
if (event3)
|
|
3896
3904
|
storeEvents.push(event3);
|
|
3897
|
-
if (capture) {
|
|
3898
|
-
committed.push({ store, id: event3.id, oldRow, newRow });
|
|
3899
|
-
}
|
|
3900
3905
|
}
|
|
3901
3906
|
if (storeEvents.length > 0) {
|
|
3902
3907
|
eventsByStore.set(store, storeEvents);
|
|
@@ -3907,7 +3912,6 @@ class MasterDataStorage extends DataStorage {
|
|
|
3907
3912
|
const storeState = this.getStore(store);
|
|
3908
3913
|
storeState.notifyListenersPublic(events);
|
|
3909
3914
|
}
|
|
3910
|
-
return committed;
|
|
3911
3915
|
}
|
|
3912
3916
|
fork() {
|
|
3913
3917
|
return new ForkedDataStorage(this);
|
|
@@ -4022,8 +4026,8 @@ class ObservableDataStorage {
|
|
|
4022
4026
|
getReadWriteTransaction() {
|
|
4023
4027
|
return this.source.getReadWriteTransaction();
|
|
4024
4028
|
}
|
|
4025
|
-
commitChanges(changes
|
|
4026
|
-
return this.source.commitChanges(changes
|
|
4029
|
+
commitChanges(changes) {
|
|
4030
|
+
return this.source.commitChanges(changes);
|
|
4027
4031
|
}
|
|
4028
4032
|
trackQuery(storeName, options, result, listener4) {
|
|
4029
4033
|
const key = this.getQueryKey(storeName, options);
|
|
@@ -4036,7 +4040,8 @@ class ObservableDataStorage {
|
|
|
4036
4040
|
}
|
|
4037
4041
|
handleStoreChange(storeName, events) {
|
|
4038
4042
|
let hasChanges = false;
|
|
4039
|
-
|
|
4043
|
+
const staleKeys = [];
|
|
4044
|
+
for (const [key, query] of this.trackedQueries) {
|
|
4040
4045
|
if (query.storeName !== storeName)
|
|
4041
4046
|
continue;
|
|
4042
4047
|
let currentResult = query.result;
|
|
@@ -4048,10 +4053,20 @@ class ObservableDataStorage {
|
|
|
4048
4053
|
queryChanged = true;
|
|
4049
4054
|
}
|
|
4050
4055
|
}
|
|
4051
|
-
if (queryChanged)
|
|
4052
|
-
|
|
4056
|
+
if (!queryChanged)
|
|
4057
|
+
continue;
|
|
4058
|
+
if (query.options.limit !== undefined && query.result.length === query.options.limit && currentResult.length < query.options.limit) {
|
|
4059
|
+
staleKeys.push(key);
|
|
4053
4060
|
hasChanges = true;
|
|
4061
|
+
continue;
|
|
4054
4062
|
}
|
|
4063
|
+
query.result = currentResult;
|
|
4064
|
+
hasChanges = true;
|
|
4065
|
+
}
|
|
4066
|
+
for (const key of staleKeys) {
|
|
4067
|
+
const query = this.trackedQueries.get(key);
|
|
4068
|
+
this.source.getStore(query.storeName).unsubscribe(query.listener);
|
|
4069
|
+
this.trackedQueries.delete(key);
|
|
4055
4070
|
}
|
|
4056
4071
|
if (hasChanges) {
|
|
4057
4072
|
this.onChange();
|
|
@@ -4322,244 +4337,135 @@ class Model {
|
|
|
4322
4337
|
return s;
|
|
4323
4338
|
}
|
|
4324
4339
|
}
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
static UNSUBSCRIBE_DELAY_MS = 5000;
|
|
4333
|
-
storeKey(viewName, scope) {
|
|
4334
|
-
return `${scope ?? DEFAULT_SCOPE}:${viewName}`;
|
|
4335
|
-
}
|
|
4336
|
-
registerViews(views) {
|
|
4337
|
-
this.views = views;
|
|
4338
|
-
}
|
|
4339
|
-
getStore(viewName, scope) {
|
|
4340
|
-
const key = this.storeKey(viewName, scope);
|
|
4341
|
-
if (!this.stores.has(key)) {
|
|
4342
|
-
this.stores.set(key, new StreamingStore);
|
|
4340
|
+
function applyQueryChanges(result, changes) {
|
|
4341
|
+
const next = [...result];
|
|
4342
|
+
for (const change of changes) {
|
|
4343
|
+
if (change.type === "delete") {
|
|
4344
|
+
const idx = next.findIndex((it) => it._id === change.id);
|
|
4345
|
+
if (idx !== -1)
|
|
4346
|
+
next.splice(idx, 1);
|
|
4343
4347
|
}
|
|
4344
|
-
return this.stores.get(key);
|
|
4345
4348
|
}
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
if (pending) {
|
|
4353
|
-
clearTimeout(pending);
|
|
4354
|
-
this.pendingUnsubscribes.delete(key);
|
|
4349
|
+
for (const change of changes) {
|
|
4350
|
+
if (change.type === "set") {
|
|
4351
|
+
const idx = next.findIndex((it) => it._id === change.id);
|
|
4352
|
+
if (idx !== -1)
|
|
4353
|
+
next.splice(idx, 1);
|
|
4354
|
+
next.splice(change.index, 0, change.item);
|
|
4355
4355
|
}
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4356
|
+
}
|
|
4357
|
+
return next;
|
|
4358
|
+
}
|
|
4359
|
+
class StreamingQueryCache {
|
|
4360
|
+
entries = new Map;
|
|
4361
|
+
static UNSUBSCRIBE_DELAY_MS = 5000;
|
|
4362
|
+
entryKey(descriptor, scope) {
|
|
4363
|
+
return `${scope ?? "default"}:${murmurHash(JSON.stringify(descriptor))}`;
|
|
4364
|
+
}
|
|
4365
|
+
subscribe(descriptor, scope, eventWire, onChange) {
|
|
4366
|
+
const key = this.entryKey(descriptor, scope);
|
|
4367
|
+
let entry = this.entries.get(key);
|
|
4368
|
+
if (entry) {
|
|
4369
|
+
if (entry.pendingUnsub) {
|
|
4370
|
+
clearTimeout(entry.pendingUnsub);
|
|
4371
|
+
entry.pendingUnsub = undefined;
|
|
4372
|
+
}
|
|
4373
|
+
entry.refCount++;
|
|
4374
|
+
} else {
|
|
4375
|
+
const newEntry = {
|
|
4376
|
+
result: undefined,
|
|
4377
|
+
hasResult: false,
|
|
4378
|
+
listeners: new Set,
|
|
4379
|
+
refCount: 1,
|
|
4380
|
+
subscriptionId: ""
|
|
4362
4381
|
};
|
|
4382
|
+
newEntry.subscriptionId = eventWire.subscribeQuery(descriptor, scope, {
|
|
4383
|
+
onSnapshot: (result) => {
|
|
4384
|
+
newEntry.result = result;
|
|
4385
|
+
newEntry.hasResult = true;
|
|
4386
|
+
this.notify(newEntry);
|
|
4387
|
+
},
|
|
4388
|
+
onChanges: (changes) => {
|
|
4389
|
+
if (!newEntry.hasResult || !Array.isArray(newEntry.result)) {
|
|
4390
|
+
return;
|
|
4391
|
+
}
|
|
4392
|
+
newEntry.result = applyQueryChanges(newEntry.result, changes);
|
|
4393
|
+
this.notify(newEntry);
|
|
4394
|
+
}
|
|
4395
|
+
});
|
|
4396
|
+
this.entries.set(key, newEntry);
|
|
4397
|
+
entry = newEntry;
|
|
4363
4398
|
}
|
|
4364
|
-
const
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
refCount: 1
|
|
4368
|
-
});
|
|
4399
|
+
const subscribed = entry;
|
|
4400
|
+
subscribed.listeners.add(onChange);
|
|
4401
|
+
let active = true;
|
|
4369
4402
|
return {
|
|
4370
|
-
|
|
4371
|
-
|
|
4403
|
+
read: () => ({
|
|
4404
|
+
result: subscribed.result,
|
|
4405
|
+
loading: !subscribed.hasResult
|
|
4406
|
+
}),
|
|
4407
|
+
unsubscribe: () => {
|
|
4408
|
+
if (!active)
|
|
4409
|
+
return;
|
|
4410
|
+
active = false;
|
|
4411
|
+
subscribed.listeners.delete(onChange);
|
|
4412
|
+
subscribed.refCount--;
|
|
4413
|
+
if (subscribed.refCount > 0)
|
|
4414
|
+
return;
|
|
4415
|
+
subscribed.pendingUnsub = setTimeout(() => {
|
|
4416
|
+
subscribed.pendingUnsub = undefined;
|
|
4417
|
+
if (subscribed.refCount > 0)
|
|
4418
|
+
return;
|
|
4419
|
+
eventWire.unsubscribeQuery(subscribed.subscriptionId);
|
|
4420
|
+
this.entries.delete(key);
|
|
4421
|
+
}, StreamingQueryCache.UNSUBSCRIBE_DELAY_MS);
|
|
4422
|
+
}
|
|
4372
4423
|
};
|
|
4373
4424
|
}
|
|
4374
|
-
|
|
4375
|
-
const stream = this.activeStreams.get(key);
|
|
4376
|
-
if (!stream)
|
|
4377
|
-
return;
|
|
4378
|
-
stream.refCount--;
|
|
4379
|
-
if (stream.refCount <= 0) {
|
|
4380
|
-
const timeout = setTimeout(() => {
|
|
4381
|
-
this.pendingUnsubscribes.delete(key);
|
|
4382
|
-
const current2 = this.activeStreams.get(key);
|
|
4383
|
-
if (current2 && current2.refCount <= 0) {
|
|
4384
|
-
current2.unsubscribe();
|
|
4385
|
-
this.activeStreams.delete(key);
|
|
4386
|
-
}
|
|
4387
|
-
}, StreamingQueryCache.UNSUBSCRIBE_DELAY_MS);
|
|
4388
|
-
this.pendingUnsubscribes.set(key, timeout);
|
|
4389
|
-
}
|
|
4390
|
-
}
|
|
4391
|
-
subscribeView(viewName, eventWire, scope) {
|
|
4392
|
-
const key = this.storeKey(viewName, scope);
|
|
4393
|
-
const { unsubscribe } = this.registerStream(key, () => {
|
|
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
|
-
};
|
|
4403
|
-
});
|
|
4404
|
-
return unsubscribe;
|
|
4405
|
-
}
|
|
4406
|
-
invalidateScope(scope) {
|
|
4425
|
+
invalidateScope(scope, eventWire) {
|
|
4407
4426
|
const prefix = `${scope}:`;
|
|
4408
|
-
for (const [key,
|
|
4409
|
-
if (!key.startsWith(prefix))
|
|
4410
|
-
continue;
|
|
4411
|
-
clearTimeout(timeout);
|
|
4412
|
-
this.pendingUnsubscribes.delete(key);
|
|
4413
|
-
}
|
|
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) {
|
|
4427
|
+
for (const [key, entry] of this.entries) {
|
|
4423
4428
|
if (!key.startsWith(prefix))
|
|
4424
4429
|
continue;
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
if (!handler)
|
|
4433
|
-
continue;
|
|
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
|
-
}
|
|
4458
|
-
}
|
|
4459
|
-
}
|
|
4460
|
-
clear() {
|
|
4461
|
-
for (const stream of this.activeStreams.values()) {
|
|
4462
|
-
stream.unsubscribe();
|
|
4463
|
-
}
|
|
4464
|
-
this.activeStreams.clear();
|
|
4465
|
-
for (const timeout of this.pendingUnsubscribes.values()) {
|
|
4466
|
-
clearTimeout(timeout);
|
|
4467
|
-
}
|
|
4468
|
-
this.pendingUnsubscribes.clear();
|
|
4469
|
-
for (const store of this.stores.values()) {
|
|
4470
|
-
store.clear();
|
|
4430
|
+
if (entry.pendingUnsub)
|
|
4431
|
+
clearTimeout(entry.pendingUnsub);
|
|
4432
|
+
eventWire?.unsubscribeQuery(entry.subscriptionId);
|
|
4433
|
+
this.entries.delete(key);
|
|
4434
|
+
entry.result = undefined;
|
|
4435
|
+
entry.hasResult = false;
|
|
4436
|
+
this.notify(entry);
|
|
4471
4437
|
}
|
|
4472
4438
|
}
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
initialized = false;
|
|
4479
|
-
hasData() {
|
|
4480
|
-
return this.initialized;
|
|
4481
|
-
}
|
|
4482
|
-
setAll(items) {
|
|
4483
|
-
this.initialized = true;
|
|
4484
|
-
this.data.clear();
|
|
4485
|
-
for (const item of items) {
|
|
4486
|
-
this.data.set(item._id, item);
|
|
4439
|
+
clear(eventWire) {
|
|
4440
|
+
for (const entry of this.entries.values()) {
|
|
4441
|
+
if (entry.pendingUnsub)
|
|
4442
|
+
clearTimeout(entry.pendingUnsub);
|
|
4443
|
+
eventWire?.unsubscribeQuery(entry.subscriptionId);
|
|
4487
4444
|
}
|
|
4488
|
-
this.
|
|
4445
|
+
this.entries.clear();
|
|
4489
4446
|
}
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
} else if (event3.type === "delete") {
|
|
4497
|
-
this.data.delete(event3.id);
|
|
4447
|
+
notify(entry) {
|
|
4448
|
+
for (const listener4 of entry.listeners) {
|
|
4449
|
+
try {
|
|
4450
|
+
listener4();
|
|
4451
|
+
} catch (err) {
|
|
4452
|
+
console.error(`[Arc] Query cache listener error:`, err);
|
|
4498
4453
|
}
|
|
4499
4454
|
}
|
|
4500
|
-
this.notifyListeners(events);
|
|
4501
|
-
}
|
|
4502
|
-
set(id3, item) {
|
|
4503
|
-
this.data.set(id3, item);
|
|
4504
|
-
this.notifyListeners([{ type: "set", id: id3, item }]);
|
|
4505
|
-
}
|
|
4506
|
-
modify(id3, updates) {
|
|
4507
|
-
const existing = this.data.get(id3);
|
|
4508
|
-
if (existing) {
|
|
4509
|
-
const updated = { ...existing, ...updates };
|
|
4510
|
-
this.data.set(id3, updated);
|
|
4511
|
-
this.notifyListeners([{ type: "set", id: id3, item: updated }]);
|
|
4512
|
-
}
|
|
4513
|
-
}
|
|
4514
|
-
remove(id3) {
|
|
4515
|
-
if (this.data.delete(id3)) {
|
|
4516
|
-
this.notifyListeners([{ type: "delete", id: id3, item: null }]);
|
|
4517
|
-
}
|
|
4518
|
-
}
|
|
4519
|
-
clear() {
|
|
4520
|
-
this.initialized = false;
|
|
4521
|
-
this.data.clear();
|
|
4522
|
-
this.notifyListeners(null);
|
|
4523
|
-
}
|
|
4524
|
-
find(options = {}) {
|
|
4525
|
-
let results = Array.from(this.data.values());
|
|
4526
|
-
if (options.where) {
|
|
4527
|
-
results = results.filter((item) => checkItemMatchesWhere(item, options.where));
|
|
4528
|
-
}
|
|
4529
|
-
return applyOrderByAndLimit(results, options);
|
|
4530
|
-
}
|
|
4531
|
-
findOne(where) {
|
|
4532
|
-
const results = this.find({ where });
|
|
4533
|
-
return results[0];
|
|
4534
|
-
}
|
|
4535
|
-
subscribe(listener4) {
|
|
4536
|
-
this.listeners.add(listener4);
|
|
4537
|
-
return () => {
|
|
4538
|
-
this.listeners.delete(listener4);
|
|
4539
|
-
};
|
|
4540
|
-
}
|
|
4541
|
-
notifyListeners(events) {
|
|
4542
|
-
for (const listener4 of this.listeners) {
|
|
4543
|
-
listener4(events);
|
|
4544
|
-
}
|
|
4545
4455
|
}
|
|
4546
4456
|
}
|
|
4547
4457
|
|
|
4548
4458
|
class StreamingEventPublisher {
|
|
4549
|
-
cache;
|
|
4550
4459
|
eventWire;
|
|
4551
4460
|
views = [];
|
|
4552
4461
|
subscribers = new Map;
|
|
4553
|
-
constructor(
|
|
4554
|
-
this.cache = cache;
|
|
4462
|
+
constructor(eventWire) {
|
|
4555
4463
|
this.eventWire = eventWire;
|
|
4556
4464
|
}
|
|
4557
4465
|
registerViews(views) {
|
|
4558
4466
|
this.views = views;
|
|
4559
|
-
this.cache.registerViews(views);
|
|
4560
4467
|
}
|
|
4561
4468
|
async publish(event3) {
|
|
4562
|
-
await this.cache.applyEvent(event3);
|
|
4563
4469
|
await this.notifySubscribers(event3);
|
|
4564
4470
|
this.eventWire.syncEvents([
|
|
4565
4471
|
{
|
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.16",
|
|
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.16"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"typescript": "^5.0.0"
|