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