@signaldb/core 2.0.0-beta.2 → 2.0.0-beta.21

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.
Files changed (145) hide show
  1. package/dist/.vite/manifest.json +183 -80
  2. package/dist/AsyncDataAdapter.d.ts +53 -7
  3. package/dist/AutoFetchDataAdapter.d.ts +4 -6
  4. package/dist/Collection/Cursor.d.ts +56 -4
  5. package/dist/Collection/Observer.d.ts +33 -0
  6. package/dist/Collection/index.d.ts +66 -19
  7. package/dist/Collection/types.d.ts +9 -2
  8. package/dist/DataAdapter.d.ts +24 -6
  9. package/dist/DefaultDataAdapter.d.ts +5 -5
  10. package/dist/WorkerDataAdapter.d.ts +57 -5
  11. package/dist/WorkerDataAdapterHost.d.ts +9 -7
  12. package/dist/createIndex.d.ts +2 -2
  13. package/dist/createIndexProvider.d.ts +2 -2
  14. package/dist/createReactivityAdapter.d.ts +2 -2
  15. package/dist/createStorageAdapter.d.ts +1 -1
  16. package/dist/getIndexInfo.d.ts +3 -4
  17. package/dist/index.cjs.js +33 -31
  18. package/dist/index.d.ts +6 -1
  19. package/dist/index.mjs +17 -32
  20. package/dist/index10.cjs.js +11 -0
  21. package/dist/index10.mjs +10 -18
  22. package/dist/index11.cjs.js +23 -0
  23. package/dist/index11.mjs +22 -15
  24. package/dist/index12.cjs.js +45 -0
  25. package/dist/index12.mjs +44 -353
  26. package/dist/index13.cjs.js +22 -0
  27. package/dist/index13.mjs +21 -419
  28. package/dist/index14.cjs.js +45 -0
  29. package/dist/index14.mjs +44 -206
  30. package/dist/index15.cjs.js +86 -0
  31. package/dist/index15.mjs +85 -388
  32. package/dist/index16.cjs.js +15 -0
  33. package/dist/index16.mjs +14 -579
  34. package/dist/index17.cjs.js +141 -0
  35. package/dist/index17.mjs +140 -152
  36. package/dist/index18.cjs.js +47 -0
  37. package/dist/index18.mjs +46 -26
  38. package/dist/index19.cjs.js +15 -0
  39. package/dist/index19.mjs +14 -41
  40. package/dist/index2.cjs.js +33 -0
  41. package/dist/index2.mjs +32 -258
  42. package/dist/index20.cjs.js +23 -0
  43. package/dist/index20.mjs +22 -16
  44. package/dist/index21.cjs.js +37 -0
  45. package/dist/index21.mjs +36 -104
  46. package/dist/index22.cjs.js +35 -0
  47. package/dist/index22.mjs +34 -128
  48. package/dist/index23.cjs.js +21 -0
  49. package/dist/index23.mjs +20 -7
  50. package/dist/index24.cjs.js +19 -0
  51. package/dist/index24.mjs +18 -27
  52. package/dist/index25.cjs.js +157 -0
  53. package/dist/index25.mjs +156 -11
  54. package/dist/index26.cjs.js +38 -0
  55. package/dist/index26.mjs +37 -29
  56. package/dist/index27.cjs.js +42 -0
  57. package/dist/index27.mjs +41 -46
  58. package/dist/index28.cjs.js +347 -0
  59. package/dist/index28.mjs +345 -7
  60. package/dist/index29.cjs.js +602 -0
  61. package/dist/index29.mjs +601 -7
  62. package/dist/index3.cjs.js +19 -0
  63. package/dist/index3.mjs +18 -556
  64. package/dist/index30.cjs.js +11 -0
  65. package/dist/index30.mjs +10 -42
  66. package/dist/index31.cjs.js +11 -0
  67. package/dist/index31.mjs +10 -29
  68. package/dist/index32.cjs.js +90 -0
  69. package/dist/index32.mjs +89 -10
  70. package/dist/index33.cjs.js +53 -0
  71. package/dist/index33.mjs +52 -5
  72. package/dist/index34.cjs.js +453 -0
  73. package/dist/index34.mjs +453 -0
  74. package/dist/index35.cjs.js +72 -0
  75. package/dist/index35.mjs +72 -0
  76. package/dist/index36.cjs.js +580 -0
  77. package/dist/index36.mjs +580 -0
  78. package/dist/index37.cjs.js +21 -0
  79. package/dist/index37.mjs +21 -0
  80. package/dist/index38.cjs.js +363 -0
  81. package/dist/index38.mjs +363 -0
  82. package/dist/index39.cjs.js +513 -0
  83. package/dist/index39.mjs +513 -0
  84. package/dist/index4.cjs.js +209 -0
  85. package/dist/index4.mjs +204 -5
  86. package/dist/index5.cjs.js +187 -0
  87. package/dist/index5.mjs +186 -5
  88. package/dist/index6.cjs.js +303 -0
  89. package/dist/index6.mjs +301 -28
  90. package/dist/index7.cjs.js +125 -0
  91. package/dist/index7.mjs +124 -12
  92. package/dist/index8.cjs.js +33 -0
  93. package/dist/index8.mjs +32 -5
  94. package/dist/index9.cjs.js +12 -0
  95. package/dist/index9.mjs +11 -133
  96. package/dist/types/IndexProvider.d.ts +2 -2
  97. package/dist/types/Modifier.d.ts +1 -1
  98. package/dist/types/ReactivityAdapter.d.ts +1 -1
  99. package/dist/types/StorageAdapter.d.ts +9 -1
  100. package/dist/utils/applyQueryOptions.d.ts +15 -0
  101. package/dist/utils/createSignal.d.ts +2 -2
  102. package/dist/utils/getMatchingKeys.d.ts +2 -2
  103. package/dist/utils/idIndexQuery.d.ts +20 -0
  104. package/dist/utils/incrementalQueryUpdate.d.ts +62 -0
  105. package/dist/utils/isFieldExpression.d.ts +1 -1
  106. package/dist/utils/match.d.ts +1 -1
  107. package/dist/utils/modify.d.ts +1 -1
  108. package/dist/utils/projectItems.d.ts +12 -0
  109. package/dist/utils/queryDelta.d.ts +83 -0
  110. package/dist/utils/queryId.d.ts +2 -2
  111. package/dist/utils/reactiveOrAsync.d.ts +59 -0
  112. package/dist/utils/storageIndexQuery.d.ts +20 -0
  113. package/package.json +1 -1
  114. package/dist/index.cjs10.js +0 -18
  115. package/dist/index.cjs11.js +0 -15
  116. package/dist/index.cjs12.js +0 -353
  117. package/dist/index.cjs13.js +0 -419
  118. package/dist/index.cjs14.js +0 -206
  119. package/dist/index.cjs15.js +0 -388
  120. package/dist/index.cjs16.js +0 -579
  121. package/dist/index.cjs17.js +0 -152
  122. package/dist/index.cjs18.js +0 -26
  123. package/dist/index.cjs19.js +0 -42
  124. package/dist/index.cjs2.js +0 -259
  125. package/dist/index.cjs20.js +0 -16
  126. package/dist/index.cjs21.js +0 -104
  127. package/dist/index.cjs22.js +0 -129
  128. package/dist/index.cjs23.js +0 -7
  129. package/dist/index.cjs24.js +0 -27
  130. package/dist/index.cjs25.js +0 -10
  131. package/dist/index.cjs26.js +0 -29
  132. package/dist/index.cjs27.js +0 -46
  133. package/dist/index.cjs28.js +0 -8
  134. package/dist/index.cjs29.js +0 -7
  135. package/dist/index.cjs3.js +0 -557
  136. package/dist/index.cjs30.js +0 -42
  137. package/dist/index.cjs31.js +0 -29
  138. package/dist/index.cjs32.js +0 -9
  139. package/dist/index.cjs33.js +0 -5
  140. package/dist/index.cjs4.js +0 -5
  141. package/dist/index.cjs5.js +0 -5
  142. package/dist/index.cjs6.js +0 -29
  143. package/dist/index.cjs7.js +0 -12
  144. package/dist/index.cjs8.js +0 -5
  145. package/dist/index.cjs9.js +0 -133
@@ -0,0 +1,580 @@
1
+ const require_queryDelta = require("./index4.cjs.js");
2
+ const require_randomId = require("./index9.cjs.js");
3
+ const require_deepClone = require("./index18.cjs.js");
4
+ const require_match = require("./index19.cjs.js");
5
+ const require_modify = require("./index20.cjs.js");
6
+ const require_incrementalQueryUpdate = require("./index25.cjs.js");
7
+ const require_queryId = require("./index26.cjs.js");
8
+ const require_batchOnNextTick = require("./index35.cjs.js");
9
+ //#region src/WorkerDataAdapter.ts
10
+ /**
11
+ * Extracts the ids a selector names outright.
12
+ * @param selector - The selector to inspect.
13
+ * @returns The named ids, or `null` when the selector asks more than ids can answer.
14
+ */
15
+ function selectorIds(selector) {
16
+ if (selector == null || typeof selector !== "object") return null;
17
+ const keys = Object.keys(selector);
18
+ if (keys.length !== 1 || keys[0] !== "id") return null;
19
+ const value = selector.id;
20
+ if (value == null) return null;
21
+ if (typeof value !== "object") return [value];
22
+ const valueKeys = Object.keys(value);
23
+ if (valueKeys.length !== 1 || valueKeys[0] !== "$in") return null;
24
+ const inValues = value.$in;
25
+ return Array.isArray(inValues) ? inValues : null;
26
+ }
27
+ var WorkerDataAdapter = class WorkerDataAdapter {
28
+ worker;
29
+ options;
30
+ id;
31
+ isDisposed = false;
32
+ workerReady;
33
+ log = () => {};
34
+ collectionReady = /* @__PURE__ */ new Map();
35
+ batchExecutionHelpers = /* @__PURE__ */ new Map();
36
+ queries = {};
37
+ pendingRequests = /* @__PURE__ */ new Map();
38
+ pendingWrites = /* @__PURE__ */ new Map();
39
+ pendingWriteSeq = 0;
40
+ pendingWriteVersions = /* @__PURE__ */ new Map();
41
+ bumpPendingWriteVersion(collectionName) {
42
+ const current = this.pendingWriteVersions.get(collectionName) ?? 0;
43
+ this.pendingWriteVersions.set(collectionName, current + 1);
44
+ }
45
+ constructor(worker, options) {
46
+ this.worker = worker;
47
+ this.options = options;
48
+ this.id = this.options.id || "default-worker-data-adapter";
49
+ if (this.options.log) this.log = this.options.log;
50
+ this.workerReady = new Promise((resolve, reject) => {
51
+ const timeoutId = setTimeout(() => {
52
+ reject(/* @__PURE__ */ new Error("WorkerDataAdapter initialization timed out"));
53
+ }, 5e3);
54
+ this.resolveWorkerReady = () => {
55
+ clearTimeout(timeoutId);
56
+ resolve();
57
+ };
58
+ });
59
+ this.worker.addEventListener("message", this.handleWorkerMessage);
60
+ }
61
+ resolveWorkerReady = () => {};
62
+ handleWorkerMessage = (event) => {
63
+ const message = event.data;
64
+ if (message == null) return;
65
+ if (message.workerId !== this.id) return;
66
+ if (message.type === "ready") {
67
+ this.resolveWorkerReady();
68
+ return;
69
+ }
70
+ if (message.type === "response") {
71
+ if (message.id == null) return;
72
+ const pending = this.pendingRequests.get(message.id);
73
+ if (!pending) return;
74
+ this.pendingRequests.delete(message.id);
75
+ this.log("response", message.data ?? message.error);
76
+ if (message.error) pending.reject(message.error);
77
+ else pending.resolve(message.data);
78
+ return;
79
+ }
80
+ if (message.type === "queryUpdate") this.handleQueryUpdate(message.data, message.error ?? null);
81
+ };
82
+ handleQueryUpdate(data, error) {
83
+ if (data == null) return;
84
+ const { collectionName, qid, selector, options, state, items, delta } = data;
85
+ if (collectionName == null) return;
86
+ const collectionQueries = this.queries[collectionName];
87
+ if (!collectionQueries) return;
88
+ const id = qid ?? (selector === void 0 ? void 0 : require_queryId.default(selector, options));
89
+ if (id == null) return;
90
+ const query = collectionQueries.get(id);
91
+ if (!query) return;
92
+ this.log("queryUpdate", query.selector, query.options, state, data ?? error);
93
+ let nextItems = items;
94
+ let deltaToPublish;
95
+ if (delta != null) {
96
+ const canApply = require_queryDelta.canApplyQueryDelta(query.items, delta);
97
+ if (!canApply || require_queryDelta.isEmptyQueryDelta(delta)) {
98
+ if (state === query.state) return;
99
+ this.updateQuery(collectionName, {
100
+ selector: query.selector,
101
+ options: query.options
102
+ }, {
103
+ state,
104
+ error
105
+ });
106
+ const settled = collectionQueries.get(id);
107
+ if (!settled) return;
108
+ settled.stateChangeCallbacks.forEach((callback) => require_queryDelta.callWithDelta(callback, state, canApply ? delta : void 0));
109
+ return;
110
+ }
111
+ const servedBefore = this.flattenPendingWrites(collectionName) == null ? null : this.servedResult(collectionName, query);
112
+ nextItems = require_queryDelta.applyQueryDelta(query.items, delta);
113
+ if (servedBefore == null) deltaToPublish = delta;
114
+ else {
115
+ this.updateQuery(collectionName, {
116
+ selector: query.selector,
117
+ options: query.options
118
+ }, {
119
+ state,
120
+ error,
121
+ items: nextItems
122
+ });
123
+ const stored = collectionQueries.get(id);
124
+ if (!stored) return;
125
+ const servedDelta = require_queryDelta.diffQueryResults(servedBefore, this.servedResult(collectionName, stored));
126
+ if (require_queryDelta.isEmptyQueryDelta(servedDelta) && state === query.state) return;
127
+ stored.stateChangeCallbacks.forEach((callback) => require_queryDelta.callWithDelta(callback, state, servedDelta));
128
+ return;
129
+ }
130
+ }
131
+ this.updateQuery(collectionName, {
132
+ selector: query.selector,
133
+ options: query.options
134
+ }, {
135
+ state,
136
+ error,
137
+ items: nextItems
138
+ });
139
+ const updated = collectionQueries.get(id);
140
+ if (!updated) return;
141
+ updated.stateChangeCallbacks.forEach((callback) => require_queryDelta.callWithDelta(callback, state, deltaToPublish));
142
+ }
143
+ async exec(method, collectionName, ...args) {
144
+ await this.workerReady;
145
+ if (method !== "isReady") {
146
+ const collectionReady = this.collectionReady.get(collectionName);
147
+ if (!collectionReady) throw new Error(`Collection "${collectionName}" is not registered in WorkerDataAdapter`);
148
+ await collectionReady;
149
+ }
150
+ if (this.isDisposed) throw new Error("WorkerDataAdapter is disposed");
151
+ return new Promise((resolve, reject) => {
152
+ const messageId = require_randomId.default();
153
+ this.pendingRequests.set(messageId, {
154
+ resolve,
155
+ reject
156
+ });
157
+ this.worker.postMessage({
158
+ id: messageId,
159
+ workerId: this.id,
160
+ method,
161
+ args: [collectionName, ...args]
162
+ });
163
+ });
164
+ }
165
+ /**
166
+ * Issues a call whose result nobody is waiting for, and makes sure a failure has somewhere to
167
+ * go. A bare rejection here would surface as an uncaught error — which is what a disposed
168
+ * collection produced every time a cursor was cleaned up after it.
169
+ * @param method - The method to call on the worker.
170
+ * @param collectionName - The collection it applies to.
171
+ * @param args - The remaining arguments.
172
+ * @param onError - Called when the call fails, in place of merely logging it.
173
+ */
174
+ execInBackground(method, collectionName, args = [], onError) {
175
+ this.exec(method, collectionName, ...args).catch((error) => {
176
+ if (onError) {
177
+ onError(error);
178
+ return;
179
+ }
180
+ this.log(method, "failed", error);
181
+ });
182
+ }
183
+ queryItemsById(query) {
184
+ if (!query.itemsById) query.itemsById = new Map(query.items.map((item) => [item.id, item]));
185
+ return query.itemsById;
186
+ }
187
+ flattenPendingWrites(collectionName) {
188
+ const state = this.pendingWrites.get(collectionName);
189
+ if (!state || state.writes.size === 0) return null;
190
+ return state.flat;
191
+ }
192
+ static pushPendingEntry(state, id, item, seq) {
193
+ const stack = state.byId.get(id);
194
+ if (stack) stack.push({
195
+ seq,
196
+ item
197
+ });
198
+ else state.byId.set(id, [{
199
+ seq,
200
+ item
201
+ }]);
202
+ WorkerDataAdapter.writeFlatEntry(state, id, item);
203
+ }
204
+ static dropPendingEntry(state, id, seq) {
205
+ const stack = state.byId.get(id);
206
+ if (!stack) return;
207
+ const index = stack.findIndex((entry) => entry.seq === seq);
208
+ if (index !== -1) stack.splice(index, 1);
209
+ const top = stack.at(-1);
210
+ if (!top) {
211
+ state.byId.delete(id);
212
+ state.flat.upserts.delete(id);
213
+ state.flat.deletes.delete(id);
214
+ return;
215
+ }
216
+ WorkerDataAdapter.writeFlatEntry(state, id, top.item);
217
+ }
218
+ static writeFlatEntry(state, id, item) {
219
+ if (item === null) {
220
+ state.flat.deletes.add(id);
221
+ state.flat.upserts.delete(id);
222
+ return;
223
+ }
224
+ state.flat.upserts.set(id, item);
225
+ state.flat.deletes.delete(id);
226
+ }
227
+ static providesFullItems(query) {
228
+ return query.options?.fields == null;
229
+ }
230
+ observableItems(collectionName) {
231
+ const byId = /* @__PURE__ */ new Map();
232
+ this.queries[collectionName]?.forEach((query) => {
233
+ if (!WorkerDataAdapter.providesFullItems(query)) return;
234
+ query.items.forEach((item) => byId.set(item.id, item));
235
+ });
236
+ const pending = this.flattenPendingWrites(collectionName);
237
+ if (pending) {
238
+ pending.upserts.forEach((item, id) => byId.set(id, item));
239
+ pending.deletes.forEach((id) => byId.delete(id));
240
+ }
241
+ return [...byId.values()];
242
+ }
243
+ observableItemsByIds(collectionName, ids) {
244
+ const pending = this.flattenPendingWrites(collectionName);
245
+ const found = /* @__PURE__ */ new Map();
246
+ ids.forEach((id) => {
247
+ if (pending?.deletes.has(id)) return;
248
+ const pendingItem = pending?.upserts.get(id);
249
+ if (pendingItem) {
250
+ found.set(id, pendingItem);
251
+ return;
252
+ }
253
+ const queries = this.queries[collectionName];
254
+ if (!queries) return;
255
+ for (const query of queries.values()) {
256
+ if (!WorkerDataAdapter.providesFullItems(query)) continue;
257
+ const item = this.queryItemsById(query).get(id);
258
+ if (item) {
259
+ found.set(id, item);
260
+ return;
261
+ }
262
+ }
263
+ });
264
+ return [...found.values()];
265
+ }
266
+ servedResult(collectionName, query) {
267
+ const pendingVersion = this.pendingWriteVersions.get(collectionName) ?? 0;
268
+ if (query.served && query.served.fromItems === query.items && query.served.pendingVersion === pendingVersion) return query.served.items;
269
+ const items = this.advanceServedResult(collectionName, query, pendingVersion) ?? this.computeServedResult(collectionName, query);
270
+ query.served = {
271
+ items,
272
+ fromItems: query.items,
273
+ pendingVersion
274
+ };
275
+ return items;
276
+ }
277
+ advanceServedResult(collectionName, query, pendingVersion) {
278
+ const served = query.served;
279
+ if (!served || served.fromItems !== query.items) return null;
280
+ if (served.pendingVersion !== pendingVersion - 1) return null;
281
+ if (!WorkerDataAdapter.providesFullItems(query) || query.options?.limit != null) return null;
282
+ const state = this.pendingWrites.get(collectionName);
283
+ if (state?.lastChange == null || state.lastChange.version !== pendingVersion) return null;
284
+ return require_incrementalQueryUpdate.mergeChangesetIntoResult(served.items, query.selector, query.options, this.changesetForIds(collectionName, query, state.lastChange.ids));
285
+ }
286
+ changesetForIds(collectionName, query, ids) {
287
+ const pending = this.flattenPendingWrites(collectionName);
288
+ const stored = this.queryItemsById(query);
289
+ const upserts = [];
290
+ const deletes = [];
291
+ ids.forEach((id) => {
292
+ const pendingItem = pending?.upserts.get(id);
293
+ if (pendingItem) {
294
+ upserts.push(pendingItem);
295
+ return;
296
+ }
297
+ if (pending?.deletes.has(id)) {
298
+ deletes.push(id);
299
+ return;
300
+ }
301
+ const storedItem = stored.get(id);
302
+ if (storedItem) upserts.push(storedItem);
303
+ else deletes.push(id);
304
+ });
305
+ return {
306
+ upserts,
307
+ deletes
308
+ };
309
+ }
310
+ computeServedResult(collectionName, query) {
311
+ const pending = this.flattenPendingWrites(collectionName);
312
+ if (!pending) return query.items;
313
+ const byId = this.queryItemsById(query);
314
+ let affected = false;
315
+ pending.deletes.forEach((id) => {
316
+ if (byId.has(id)) affected = true;
317
+ });
318
+ if (!affected) pending.upserts.forEach((item, id) => {
319
+ if (affected) return;
320
+ if (byId.has(id)) affected = true;
321
+ else if (query.selector != null && require_match.default(item, query.selector)) affected = true;
322
+ });
323
+ if (!affected) return query.items;
324
+ return require_incrementalQueryUpdate.mergeChangesetIntoResult(query.items, query.selector, query.options, {
325
+ upserts: [...pending.upserts.values()],
326
+ deletes: [...pending.deletes]
327
+ });
328
+ }
329
+ /**
330
+ * Registers a write's effect locally and notifies every active query it
331
+ * touches, then returns a function that drops it again once the write
332
+ * settles.
333
+ * @param collectionName - The collection the write targets.
334
+ * @param upserts - Items inserted or updated by the write.
335
+ * @param deletes - Ids removed by the write.
336
+ * @returns A function that drops the pending write and re-notifies.
337
+ */
338
+ applyPendingWrite(collectionName, upserts, deletes) {
339
+ if (upserts.length === 0 && deletes.length === 0) return () => {};
340
+ const affectedIds = new Set([...upserts.map((item) => item.id), ...deletes]);
341
+ const affected = this.affectedQueries(collectionName, upserts, affectedIds);
342
+ const servedBefore = this.servedResults(collectionName, affected);
343
+ const seq = this.pendingWriteSeq += 1;
344
+ const state = this.pendingWrites.get(collectionName) ?? {
345
+ writes: /* @__PURE__ */ new Map(),
346
+ byId: /* @__PURE__ */ new Map(),
347
+ flat: {
348
+ upserts: /* @__PURE__ */ new Map(),
349
+ deletes: /* @__PURE__ */ new Set()
350
+ },
351
+ lastChange: null
352
+ };
353
+ const write = {
354
+ upserts: new Map(upserts.map((item) => [item.id, item])),
355
+ deletes: new Set(deletes)
356
+ };
357
+ state.writes.set(seq, write);
358
+ write.upserts.forEach((item, id) => WorkerDataAdapter.pushPendingEntry(state, id, item, seq));
359
+ write.deletes.forEach((id) => WorkerDataAdapter.pushPendingEntry(state, id, null, seq));
360
+ this.pendingWrites.set(collectionName, state);
361
+ this.bumpPendingWriteVersion(collectionName);
362
+ state.lastChange = {
363
+ version: this.pendingWriteVersions.get(collectionName) ?? 0,
364
+ ids: [...affectedIds]
365
+ };
366
+ this.notifyWithDeltas(collectionName, affected, servedBefore);
367
+ return () => {
368
+ const current = this.pendingWrites.get(collectionName);
369
+ if (!current) return;
370
+ const settled = current.writes.get(seq);
371
+ if (!settled) return;
372
+ const affectedOnDrop = this.affectedQueries(collectionName, upserts, affectedIds);
373
+ const beforeDrop = this.servedResults(collectionName, affectedOnDrop);
374
+ current.writes.delete(seq);
375
+ settled.upserts.forEach((item, id) => WorkerDataAdapter.dropPendingEntry(current, id, seq));
376
+ settled.deletes.forEach((id) => WorkerDataAdapter.dropPendingEntry(current, id, seq));
377
+ if (current.writes.size === 0) this.pendingWrites.delete(collectionName);
378
+ this.bumpPendingWriteVersion(collectionName);
379
+ if (current.writes.size > 0) current.lastChange = {
380
+ version: this.pendingWriteVersions.get(collectionName) ?? 0,
381
+ ids: [...affectedIds]
382
+ };
383
+ this.notifyWithDeltas(collectionName, affectedOnDrop, beforeDrop);
384
+ };
385
+ }
386
+ affectedQueries(collectionName, upserts, affectedIds) {
387
+ const affected = [];
388
+ this.queries[collectionName]?.forEach((query) => {
389
+ const byId = this.queryItemsById(query);
390
+ let wasHolding = false;
391
+ affectedIds.forEach((id) => {
392
+ if (byId.has(id)) wasHolding = true;
393
+ });
394
+ const nowMatches = upserts.some((item) => query.selector != null && require_match.default(item, query.selector));
395
+ if (!wasHolding && !nowMatches) return;
396
+ affected.push(query);
397
+ });
398
+ return affected;
399
+ }
400
+ servedResults(collectionName, queries) {
401
+ return new Map(queries.map((query) => [query, this.servedResult(collectionName, query)]));
402
+ }
403
+ notifyWithDeltas(collectionName, queries, servedBefore) {
404
+ queries.forEach((query) => {
405
+ const before = servedBefore.get(query);
406
+ if (before == null) return;
407
+ const delta = require_queryDelta.diffQueryResults(before, this.servedResult(collectionName, query));
408
+ if (require_queryDelta.isEmptyQueryDelta(delta)) return;
409
+ query.stateChangeCallbacks.forEach((callback) => require_queryDelta.callWithDelta(callback, query.state, delta));
410
+ });
411
+ }
412
+ matchObservableItems(collectionName, selector, onlyFirst) {
413
+ if (selector == null) return [];
414
+ const ids = selectorIds(selector);
415
+ const matches = ids == null ? this.observableItems(collectionName).filter((item) => require_match.default(item, selector)) : this.observableItemsByIds(collectionName, ids);
416
+ return onlyFirst ? matches.slice(0, 1) : matches;
417
+ }
418
+ resolveUpdate(collectionName, selector, modifier, onlyFirst) {
419
+ const { $setOnInsert, ...restModifier } = modifier;
420
+ const upserts = [];
421
+ const deletes = [];
422
+ this.matchObservableItems(collectionName, selector, onlyFirst).forEach((item) => {
423
+ const modifiedItem = require_modify.default(require_deepClone.default(item), restModifier);
424
+ upserts.push(modifiedItem);
425
+ if (modifiedItem.id !== item.id) deletes.push(item.id);
426
+ });
427
+ return {
428
+ upserts,
429
+ deletes
430
+ };
431
+ }
432
+ resolveRemoval(collectionName, selector, onlyFirst) {
433
+ return this.matchObservableItems(collectionName, selector, onlyFirst).map((item) => item.id);
434
+ }
435
+ resolveReplacement(item, replacement) {
436
+ const modifiedItem = {
437
+ ...replacement,
438
+ id: replacement.id ?? item.id
439
+ };
440
+ return {
441
+ upserts: [modifiedItem],
442
+ deletes: modifiedItem.id === item.id ? [] : [item.id]
443
+ };
444
+ }
445
+ async withPendingWrite(collectionName, delta, run) {
446
+ const dropPendingWrite = this.applyPendingWrite(collectionName, delta.upserts, delta.deletes);
447
+ try {
448
+ return await run();
449
+ } finally {
450
+ dropPendingWrite();
451
+ }
452
+ }
453
+ enqueueBatched(collectionName, method, args) {
454
+ const helper = this.batchExecutionHelpers.get(collectionName);
455
+ if (!helper) throw new Error(`Collection "${collectionName}" is not registered in WorkerDataAdapter`);
456
+ return helper.enqueue(method, args);
457
+ }
458
+ updateQuery(collectionName, query, update) {
459
+ const id = require_queryId.default(query.selector, query.options);
460
+ const collectionQueries = this.queries[collectionName];
461
+ if (!collectionQueries) return;
462
+ const existing = collectionQueries.get(id);
463
+ const newState = {
464
+ selector: query.selector,
465
+ options: query.options,
466
+ state: "active",
467
+ error: null,
468
+ stateChangeCallbacks: [],
469
+ ...existing,
470
+ ...update,
471
+ ...update.items ? {
472
+ items: update.items,
473
+ itemsById: void 0
474
+ } : { items: existing?.items ?? [] }
475
+ };
476
+ collectionQueries.set(id, newState);
477
+ this.queries[collectionName] = collectionQueries;
478
+ }
479
+ createCollectionBackend(collection, indices) {
480
+ this.queries[collection.name] = /* @__PURE__ */ new Map();
481
+ this.execInBackground("registerCollection", collection.name, [indices]);
482
+ this.collectionReady.set(collection.name, this.exec("isReady", collection.name));
483
+ this.batchExecutionHelpers.set(collection.name, require_batchOnNextTick.default(async (method, args) => this.exec(method, collection.name, args)));
484
+ return {
485
+ insert: async (item) => {
486
+ return this.withPendingWrite(collection.name, {
487
+ upserts: [item],
488
+ deletes: []
489
+ }, () => this.enqueueBatched(collection.name, "insert", [item]));
490
+ },
491
+ updateOne: async (selector, modifier) => {
492
+ return this.withPendingWrite(collection.name, this.resolveUpdate(collection.name, selector, modifier, true), () => this.enqueueBatched(collection.name, "updateOne", [selector, modifier]));
493
+ },
494
+ updateMany: async (selector, modifier) => {
495
+ return this.withPendingWrite(collection.name, this.resolveUpdate(collection.name, selector, modifier, false), () => this.enqueueBatched(collection.name, "updateMany", [selector, modifier]));
496
+ },
497
+ replaceOne: async (selector, replacement) => {
498
+ const [item] = this.matchObservableItems(collection.name, selector, true);
499
+ return this.withPendingWrite(collection.name, item == null ? {
500
+ upserts: [],
501
+ deletes: []
502
+ } : this.resolveReplacement(item, replacement), () => this.enqueueBatched(collection.name, "replaceOne", [selector, replacement]));
503
+ },
504
+ removeOne: async (selector) => {
505
+ return this.withPendingWrite(collection.name, {
506
+ upserts: [],
507
+ deletes: this.resolveRemoval(collection.name, selector, true)
508
+ }, () => this.enqueueBatched(collection.name, "removeOne", [selector]));
509
+ },
510
+ removeMany: async (selector) => {
511
+ return this.withPendingWrite(collection.name, {
512
+ upserts: [],
513
+ deletes: this.resolveRemoval(collection.name, selector, false)
514
+ }, () => this.enqueueBatched(collection.name, "removeMany", [selector]));
515
+ },
516
+ registerQuery: (selector, options) => {
517
+ this.updateQuery(collection.name, {
518
+ selector,
519
+ options
520
+ }, {
521
+ state: "active",
522
+ error: null,
523
+ items: []
524
+ });
525
+ this.execInBackground("registerQuery", collection.name, [selector, options], (error) => {
526
+ const query = this.queries[collection.name]?.get(require_queryId.default(selector, options));
527
+ if (!query) return;
528
+ this.updateQuery(collection.name, {
529
+ selector,
530
+ options
531
+ }, {
532
+ state: "error",
533
+ error
534
+ });
535
+ query.stateChangeCallbacks.forEach((callback) => callback("error"));
536
+ });
537
+ },
538
+ unregisterQuery: (selector, options) => {
539
+ this.queries[collection.name]?.delete(require_queryId.default(selector, options));
540
+ this.execInBackground("unregisterQuery", collection.name, [selector, options]);
541
+ },
542
+ getQueryState: (selector, options) => {
543
+ return (this.queries[collection.name]?.get(require_queryId.default(selector, options)))?.state || "active";
544
+ },
545
+ getQueryError: (selector, options) => {
546
+ return (this.queries[collection.name]?.get(require_queryId.default(selector, options)))?.error || null;
547
+ },
548
+ getQueryResult: (selector, options) => {
549
+ const query = this.queries[collection.name]?.get(require_queryId.default(selector, options));
550
+ if (!query) return [];
551
+ return this.servedResult(collection.name, query);
552
+ },
553
+ onQueryStateChange: (selector, options, callback) => {
554
+ this.updateQuery(collection.name, {
555
+ selector,
556
+ options
557
+ }, { stateChangeCallbacks: [...this.queries[collection.name]?.get(require_queryId.default(selector, options))?.stateChangeCallbacks || [], callback] });
558
+ return () => {
559
+ const currentCallbacks = this.queries[collection.name]?.get(require_queryId.default(selector, options))?.stateChangeCallbacks;
560
+ if (!currentCallbacks) return;
561
+ this.updateQuery(collection.name, {
562
+ selector,
563
+ options
564
+ }, { stateChangeCallbacks: currentCallbacks.filter((existingCallback) => existingCallback !== callback) });
565
+ };
566
+ },
567
+ executeQuery: (selector, options) => this.exec("executeQuery", collection.name, selector, options),
568
+ dispose: async () => {
569
+ await this.exec("unregisterCollection", collection.name);
570
+ this.isDisposed = true;
571
+ this.worker.terminate?.();
572
+ },
573
+ isReady: async () => {
574
+ await this.collectionReady.get(collection.name);
575
+ }
576
+ };
577
+ }
578
+ };
579
+ //#endregion
580
+ exports.default = WorkerDataAdapter;