@signaldb/core 2.0.0-beta.3 → 2.0.0-beta.5

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 (54) hide show
  1. package/dist/.vite/manifest.json +24 -18
  2. package/dist/Collection/Observer.d.ts +2 -0
  3. package/dist/Collection/index.d.ts +11 -10
  4. package/dist/Collection/types.d.ts +7 -0
  5. package/dist/DefaultDataAdapter.d.ts +2 -0
  6. package/dist/index.cjs.js +8 -5
  7. package/dist/index.cjs12.js +41 -346
  8. package/dist/index.cjs13.js +308 -362
  9. package/dist/index.cjs14.js +387 -177
  10. package/dist/index.cjs15.js +182 -364
  11. package/dist/index.cjs16.js +287 -478
  12. package/dist/index.cjs17.js +563 -136
  13. package/dist/index.cjs18.js +154 -23
  14. package/dist/index.cjs19.js +23 -39
  15. package/dist/index.cjs2.js +1 -1
  16. package/dist/index.cjs20.js +39 -13
  17. package/dist/index.cjs21.js +14 -102
  18. package/dist/index.cjs22.js +93 -118
  19. package/dist/index.cjs23.js +127 -5
  20. package/dist/index.cjs24.js +5 -25
  21. package/dist/index.cjs25.js +24 -7
  22. package/dist/index.cjs26.js +8 -27
  23. package/dist/index.cjs27.js +25 -42
  24. package/dist/index.cjs28.js +44 -6
  25. package/dist/index.cjs29.js +6 -7
  26. package/dist/index.cjs3.js +9 -26
  27. package/dist/index.cjs34.js +9 -0
  28. package/dist/index.cjs7.js +1 -1
  29. package/dist/index.d.ts +2 -1
  30. package/dist/index.mjs +10 -7
  31. package/dist/index12.mjs +40 -346
  32. package/dist/index13.mjs +308 -362
  33. package/dist/index14.mjs +387 -177
  34. package/dist/index15.mjs +182 -364
  35. package/dist/index16.mjs +287 -478
  36. package/dist/index17.mjs +563 -136
  37. package/dist/index18.mjs +154 -23
  38. package/dist/index19.mjs +23 -38
  39. package/dist/index2.mjs +1 -1
  40. package/dist/index20.mjs +38 -13
  41. package/dist/index21.mjs +14 -102
  42. package/dist/index22.mjs +93 -117
  43. package/dist/index23.mjs +126 -5
  44. package/dist/index24.mjs +5 -25
  45. package/dist/index25.mjs +24 -7
  46. package/dist/index26.mjs +8 -27
  47. package/dist/index27.mjs +25 -42
  48. package/dist/index28.mjs +44 -6
  49. package/dist/index29.mjs +6 -7
  50. package/dist/index3.mjs +9 -26
  51. package/dist/index34.mjs +10 -0
  52. package/dist/index7.mjs +1 -1
  53. package/dist/utils/reactiveOrAsync.d.ts +59 -0
  54. package/package.json +1 -1
@@ -1,216 +1,69 @@
1
1
  "use strict";
2
- const deepClone = require("./index.cjs19.js");
3
- const match = require("./index.cjs23.js");
4
- const modify = require("./index.cjs7.js");
5
- const queryId = require("./index.cjs20.js");
2
+ const createIndex = require("./index.cjs22.js");
3
+ const getIndexInfo = require("./index.cjs23.js");
4
+ const deepClone = require("./index.cjs20.js");
5
+ const EventEmitter = require("./index.cjs9.js");
6
6
  const isEqual = require("./index.cjs6.js");
7
- const getIndexInfo = require("./index.cjs22.js");
8
- const getMatchingKeys = require("./index.cjs26.js");
9
- const sortItems = require("./index.cjs25.js");
10
- const project = require("./index.cjs24.js");
11
- class AsyncDataAdapter {
7
+ const match = require("./index.cjs24.js");
8
+ const modify = require("./index.cjs7.js");
9
+ const project = require("./index.cjs25.js");
10
+ const queryId = require("./index.cjs21.js");
11
+ const serializeValue = require("./index.cjs11.js");
12
+ const sortItems = require("./index.cjs26.js");
13
+ function hasPendingUpdates(pendingUpdates) {
14
+ return pendingUpdates.added.length > 0 || pendingUpdates.modified.length > 0 || pendingUpdates.removed.length > 0;
15
+ }
16
+ class DefaultDataAdapter {
17
+ items = /* @__PURE__ */ new Map();
12
18
  options;
13
- id;
14
- onError;
15
- // Per-collection resources
16
19
  storageAdapters = /* @__PURE__ */ new Map();
17
- storageAdapterReady = /* @__PURE__ */ new Map();
18
- collectionIndices = /* @__PURE__ */ new Map();
19
- // Per-collection query registries
20
- queries = /* @__PURE__ */ new Map();
20
+ collections = /* @__PURE__ */ new Set();
21
+ indices = /* @__PURE__ */ new Map();
22
+ activeQueries = /* @__PURE__ */ new Map();
23
+ queryEmitters = /* @__PURE__ */ new Map();
24
+ queuedQueryUpdates = /* @__PURE__ */ new Map();
25
+ cachedQueryResults = /* @__PURE__ */ new Map();
21
26
  constructor(options) {
22
- this.options = options;
23
- this.id = options.id || "async-data-adapter";
24
- this.onError = options.onError ?? ((error) => {
25
- console.error(error);
26
- });
27
- }
28
- createCollectionBackend(collection, indices) {
29
- this.collectionIndices.set(collection.name, indices);
30
- this.queries.set(collection.name, /* @__PURE__ */ new Map());
31
- this.ensureStorageAdapter(collection.name);
32
- const ready = (async () => {
33
- try {
34
- await this.setupStorage(collection.name, indices);
35
- } catch (error) {
36
- this.onError(error);
37
- throw error;
38
- }
39
- })();
40
- this.storageAdapterReady.set(collection.name, ready);
41
- const registerQuery = (selector, options) => {
42
- const qid = queryId(selector, options);
43
- const registry = this.queries.get(collection.name);
44
- if (!registry)
45
- throw new Error(`Collection ${collection.name} not initialized!`);
46
- registry.set(qid, {
47
- selector,
48
- options,
49
- items: [],
50
- listeners: /* @__PURE__ */ new Set(),
51
- ...registry.get(qid),
52
- state: "active",
53
- error: null
54
- });
55
- void this.fulfillQuery(collection.name, selector, options).catch(this.onError);
56
- };
57
- const unregisterQuery = (selector, options) => {
58
- const qid = queryId(selector, options);
59
- this.queries.get(collection.name)?.delete(qid);
60
- };
61
- const getQueryState = (selector, options) => {
62
- const q = this.queries.get(collection.name)?.get(queryId(selector, options));
63
- return q?.state ?? "active";
64
- };
65
- const getQueryError = (selector, options) => {
66
- const q = this.queries.get(collection.name)?.get(queryId(selector, options));
67
- return q?.error ?? null;
68
- };
69
- const getQueryResult = (selector, options) => {
70
- const q = this.queries.get(collection.name)?.get(queryId(selector, options));
71
- return q?.items ?? [];
72
- };
73
- const onQueryStateChange = (selector, options, callback) => {
74
- const qid = queryId(selector, options);
75
- const registry = this.queries.get(collection.name);
76
- if (!registry)
77
- throw new Error(`Collection ${collection.name} not initialized!`);
78
- if (!registry.has(qid)) {
79
- registry.set(qid, {
80
- selector,
81
- options,
82
- state: "active",
83
- error: null,
84
- items: [],
85
- listeners: /* @__PURE__ */ new Set()
86
- });
87
- }
88
- registry.get(qid)?.listeners.add(callback);
89
- return () => registry.get(qid)?.listeners.delete(callback);
90
- };
91
- return {
92
- insert: async (item) => {
93
- await ready;
94
- const inserted = await this.insert(collection.name, item);
95
- return inserted;
96
- },
97
- updateOne: async (selector, modifier) => {
98
- await ready;
99
- return this.updateOne(collection.name, selector, modifier);
100
- },
101
- updateMany: async (selector, modifier) => {
102
- await ready;
103
- return this.updateMany(collection.name, selector, modifier);
104
- },
105
- replaceOne: async (selector, replacement) => {
106
- await ready;
107
- return this.replaceOne(collection.name, selector, replacement);
108
- },
109
- removeOne: async (selector) => {
110
- await ready;
111
- return this.removeOne(collection.name, selector);
112
- },
113
- removeMany: async (selector) => {
114
- await ready;
115
- return this.removeMany(collection.name, selector);
116
- },
117
- registerQuery,
118
- unregisterQuery,
119
- getQueryState,
120
- getQueryError,
121
- getQueryResult,
122
- onQueryStateChange,
123
- executeQuery: async (selector, options) => {
124
- await ready;
125
- registerQuery(selector, options);
126
- const result = getQueryResult(selector, options);
127
- unregisterQuery(selector, options);
128
- return result;
129
- },
130
- dispose: async () => {
131
- this.storageAdapters.delete(collection.name);
132
- this.queries.delete(collection.name);
133
- this.collectionIndices.delete(collection.name);
134
- this.storageAdapterReady.delete(collection.name);
135
- },
136
- isReady: async () => {
137
- await ready;
138
- }
139
- };
140
- }
141
- async setupStorage(collectionName, indices) {
142
- const storage = this.storageAdapters.get(collectionName);
143
- if (!storage)
144
- throw new Error(`No persistence adapter for collection ${collectionName}`);
145
- await storage.setup();
146
- await Promise.all(indices.map((index) => storage.createIndex(index)));
27
+ this.options = options || {};
147
28
  }
148
29
  ensureStorageAdapter(name) {
149
- if (this.storageAdapters.has(name))
30
+ if (this.storageAdapters.get(name))
31
+ return;
32
+ if (!this.options.storage)
150
33
  return;
151
34
  const adapter = this.options.storage(name);
152
35
  if (!adapter)
153
36
  return;
154
37
  this.storageAdapters.set(name, adapter);
155
38
  }
156
- /**
157
- * Compute and publish the result for a specific query
158
- * @param collectionName - name of the collection
159
- * @param selector - query selector
160
- * @param options - query options
161
- */
162
- async fulfillQuery(collectionName, selector, options) {
163
- const qid = queryId(selector, options);
164
- const registry = this.queries.get(collectionName);
165
- if (!registry)
166
- throw new Error(`Collection ${collectionName} not initialized!`);
167
- const rec = registry.get(qid);
168
- if (!rec)
169
- return;
170
- this.publishState(collectionName, qid, "active", null);
171
- try {
172
- const items = await this.executeQuery(collectionName, selector, options);
173
- this.publishResult(collectionName, qid, items);
174
- this.publishState(collectionName, qid, "complete", null);
175
- } catch (error) {
176
- this.publishState(collectionName, qid, "error", error);
177
- }
39
+ rebuildIndices(collection) {
40
+ const items = this.items.get(collection.name);
41
+ if (!items)
42
+ throw new Error(`Items not found for collection ${collection.name}`);
43
+ const indices = this.indices.get(collection.name);
44
+ if (!indices)
45
+ throw new Error(`Indices not found for collection ${collection.name}`);
46
+ indices.forEach((index) => index.rebuild([...items.values()]));
178
47
  }
179
- /**
180
- * Notify listeners about state changes and keep the cache updated
181
- * @param collectionName - name of the collection
182
- * @param qid - query id
183
- * @param state - new state
184
- * @param error - error if state is 'error', null otherwise
185
- */
186
- publishState(collectionName, qid, state, error) {
187
- const rec = this.queries.get(collectionName)?.get(qid);
188
- if (!rec)
48
+ async setupStorageAdapter(collection) {
49
+ const storageAdapter = this.storageAdapters.get(collection.name);
50
+ if (!storageAdapter)
189
51
  return;
190
- rec.state = state;
191
- rec.error = error;
192
- for (const callback of rec.listeners) {
193
- try {
194
- callback(state);
195
- } catch (error_) {
196
- this.onError(error_);
52
+ return storageAdapter.setup().then(async () => {
53
+ await this.fetchItemsFromStorage(collection);
54
+ }).catch((error) => {
55
+ if (!this.options.onError) {
56
+ console.error(`Error during data persistence operation in collection ${collection.name}`, error);
57
+ return;
197
58
  }
198
- }
199
- }
200
- publishResult(collectionName, qid, items) {
201
- const rec = this.queries.get(collectionName)?.get(qid);
202
- if (!rec)
203
- return;
204
- rec.items = items;
59
+ this.options.onError(collection.name, error instanceof Error ? error : new Error(error));
60
+ });
205
61
  }
206
- async getIndexInfo(collectionName, selector) {
207
- const storageAdapter = this.storageAdapters.get(collectionName);
208
- if (!storageAdapter)
209
- throw new Error(`No persistence adapter for collection ${collectionName}`);
62
+ getIndexInfo(collection, selector) {
210
63
  if (selector != null && Object.keys(selector).length === 1 && "id" in selector && typeof selector.id !== "object") {
211
64
  return {
212
65
  matched: true,
213
- ids: [selector.id].filter(Boolean),
66
+ ids: [serializeValue(selector.id)],
214
67
  optimizedSelector: {}
215
68
  };
216
69
  }
@@ -221,68 +74,49 @@ class AsyncDataAdapter {
221
74
  optimizedSelector: {}
222
75
  };
223
76
  }
224
- const indices = this.collectionIndices.get(collectionName) ?? [];
225
- return getIndexInfo.default(indices.map((field) => async (flatSelector) => {
226
- if (!Object.hasOwnProperty.call(flatSelector, field))
227
- return { matched: false };
228
- const index = await storageAdapter.readIndex(field);
229
- const fieldSelector = flatSelector[field];
230
- const filtersForNull = fieldSelector == null || fieldSelector.$exists === false;
231
- const keys = filtersForNull ? { include: null, exclude: [...index.keys()].filter((key) => key != null) } : getMatchingKeys(field, flatSelector);
232
- if (keys.include == null && keys.exclude == null)
233
- return { matched: false };
234
- let includedIds = [];
235
- if (keys.include == null) {
236
- for (const set of index.values())
237
- for (const pos of set)
238
- includedIds.push(pos);
239
- } else {
240
- for (const key of keys.include) {
241
- const idSet = index.get(key);
242
- if (idSet)
243
- for (const id of idSet)
244
- includedIds.push(id);
245
- }
246
- }
247
- if (keys.exclude != null) {
248
- const excludeIds = /* @__PURE__ */ new Set();
249
- for (const key of keys.exclude) {
250
- const idSet = index.get(key);
251
- if (idSet)
252
- for (const id of idSet)
253
- excludeIds.add(id);
254
- }
255
- includedIds = includedIds.filter((pos) => !excludeIds.has(pos));
256
- }
257
- return { matched: true, ids: includedIds, fields: [field], keepSelector: filtersForNull };
258
- }), selector);
77
+ return getIndexInfo.default((this.indices.get(collection.name) ?? []).map((i) => i.query.bind(i)), selector);
78
+ }
79
+ applyIndexDeltas(collection, changes) {
80
+ const indices = this.indices.get(collection.name) ?? [];
81
+ for (const index of indices) {
82
+ if (changes.modified)
83
+ index.update(changes.modified);
84
+ if (changes.added && changes.added.length > 0)
85
+ index.insert(changes.added);
86
+ if (changes.removed && changes.removed.length > 0)
87
+ index.remove(changes.removed);
88
+ }
89
+ }
90
+ getItem(collection, selector) {
91
+ const memory = this.items.get(collection.name) ?? /* @__PURE__ */ new Map();
92
+ const indexInfo = this.getIndexInfo(collection, selector);
93
+ const items = indexInfo.matched ? indexInfo.ids.map((id) => memory.get(serializeValue(id))).filter((i) => i != null) : [...memory.values()];
94
+ const item = items.find((document) => match(document, selector));
95
+ return item;
259
96
  }
260
- async queryItems(collectionName, selector) {
261
- const storage = this.storageAdapters.get(collectionName);
262
- if (!storage)
263
- throw new Error(`No persistence adapter for collection ${collectionName}`);
264
- const index = await this.getIndexInfo(collectionName, selector);
97
+ queryItems(collection, selector) {
98
+ const indexInfo = this.getIndexInfo(collection, selector);
265
99
  const matchItems = (item) => {
266
- if (index.optimizedSelector == null)
100
+ if (indexInfo.optimizedSelector == null)
267
101
  return true;
268
- if (Object.keys(index.optimizedSelector).length <= 0)
102
+ if (Object.keys(indexInfo.optimizedSelector).length <= 0)
269
103
  return true;
270
- return match(item, index.optimizedSelector);
104
+ const matches = match(item, indexInfo.optimizedSelector);
105
+ return matches;
271
106
  };
272
- if (index.matched) {
273
- const items = await storage.readIds(index.ids);
274
- if (isEqual(index.optimizedSelector, {}))
275
- return items;
276
- return items.filter(matchItems);
277
- } else {
278
- const allItems = await storage.readAll();
107
+ const items = this.items.get(collection.name);
108
+ if (!indexInfo.matched) {
279
109
  if (isEqual(selector, {}))
280
- return allItems;
281
- return allItems.filter(matchItems);
110
+ return [...items.values()];
111
+ return [...items.values()].filter(matchItems);
282
112
  }
113
+ const foundItems = indexInfo.ids.map((ids) => items.get(serializeValue(ids))).filter((i) => i != null);
114
+ if (isEqual(indexInfo.optimizedSelector, {}))
115
+ return foundItems;
116
+ return foundItems.filter(matchItems);
283
117
  }
284
- async executeQuery(collectionName, selector, options) {
285
- const items = await this.queryItems(collectionName, selector || {});
118
+ executeQuery(collection, selector, options) {
119
+ const items = this.queryItems(collection, selector || {});
286
120
  const { sort, skip, limit, fields } = options || {};
287
121
  const sorted = sort ? sortItems(items, sort) : items;
288
122
  const skipped = skip ? sorted.slice(skip) : sorted;
@@ -291,129 +125,241 @@ class AsyncDataAdapter {
291
125
  return limited.map((item) => {
292
126
  if (!fields)
293
127
  return item;
294
- return { ...idExcluded ? {} : { id: item.id }, ...project(item, fields) };
128
+ return {
129
+ ...idExcluded ? {} : { id: item.id },
130
+ ...project(item, fields)
131
+ };
295
132
  });
296
133
  }
297
- /**
298
- * After mutations, recompute and push updates for affected active queries
299
- * @param collectionName - name of the collection
300
- * @param changedItems - items that were inserted/updated/replaced/removed
301
- */
302
- async checkQueryUpdates(collectionName, changedItems) {
303
- const registry = this.queries.get(collectionName);
304
- if (!registry)
305
- throw new Error(`Collection ${collectionName} not initialized!`);
306
- if (registry.size === 0)
134
+ flushQueuedQueryUpdates(collection) {
135
+ if (!this.queuedQueryUpdates.get(collection.name))
307
136
  return;
308
- const affected = [...registry.values()].filter(({ selector }) => changedItems.some((item) => match(item, selector)));
309
- if (affected.length === 0)
137
+ const changes = this.queuedQueryUpdates.get(collection.name);
138
+ if (!changes || !hasPendingUpdates(changes))
310
139
  return;
311
- for (const { selector, options } of affected) {
312
- const qid = queryId(selector, options);
313
- this.publishState(collectionName, qid, "active", null);
314
- }
315
- await Promise.all(affected.map(async ({ selector, options }) => {
316
- const qid = queryId(selector, options);
317
- try {
318
- const items = await this.executeQuery(collectionName, selector, options);
319
- this.publishResult(collectionName, qid, items);
320
- this.publishState(collectionName, qid, "complete", null);
321
- } catch (error) {
322
- this.publishState(collectionName, qid, "error", error);
323
- }
324
- }));
140
+ this.queuedQueryUpdates.set(collection.name, { added: [], modified: [], removed: [] });
141
+ const flatItems = [...changes.added, ...changes.modified, ...changes.removed];
142
+ const itemIds = new Set(flatItems.map((i) => i.id));
143
+ const queries = [
144
+ ...this.activeQueries.get(collection.name)?.values() ?? []
145
+ ].filter(({ selector, options }) => {
146
+ const idsInQuery = this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options))?.map((i) => i.id) ?? [];
147
+ if (idsInQuery.some((id) => itemIds.has(id)))
148
+ return true;
149
+ return flatItems.some((item) => match(item, selector));
150
+ });
151
+ queries.forEach(({ selector, options }) => {
152
+ this.executeAndCacheQuery(collection, selector, options);
153
+ });
325
154
  }
326
- async insert(collectionName, newItem) {
327
- const storage = this.storageAdapters.get(collectionName);
328
- if (!storage)
329
- throw new Error(`No persistence adapter for collection ${collectionName}`);
330
- const existingItems = await storage.readIds([newItem.id]);
331
- if (existingItems.length > 0)
332
- throw new Error(`Item with id ${String(newItem.id)} already exists`);
333
- await storage.insert([newItem]);
334
- await this.checkQueryUpdates(collectionName, [newItem]);
335
- return newItem;
155
+ executeAndCacheQuery(collection, selector, options) {
156
+ const result = this.executeQuery(collection, selector, options);
157
+ this.cachedQueryResults.set(collection.name, this.cachedQueryResults.get(collection.name) || /* @__PURE__ */ new Map());
158
+ this.cachedQueryResults.get(collection.name)?.set(queryId(selector, options), result);
159
+ const emitter = this.queryEmitters.get(collection.name);
160
+ if (!emitter)
161
+ return;
162
+ emitter.emit("change", selector, options, "complete");
336
163
  }
337
- async updateOne(collectionName, selector, modifier) {
338
- const storage = this.storageAdapters.get(collectionName);
339
- if (!storage)
340
- throw new Error(`No persistence adapter for collection ${collectionName}`);
341
- const items = await this.executeQuery(collectionName, selector, { limit: 1 });
342
- const [item] = items;
343
- const { $setOnInsert, ...rest } = modifier;
344
- if (item == null)
345
- return [];
346
- const modified = modify(deepClone.default(item), rest);
347
- if (item.id !== modified.id) {
348
- const existing = await this.executeQuery(collectionName, { id: modified.id }, { limit: 1 });
349
- if (existing.length > 0)
350
- throw new Error(`Item with id ${String(modified.id)} already exists`);
351
- }
352
- await storage.replace([modified]);
353
- await this.checkQueryUpdates(collectionName, [modified]);
354
- return [modified];
164
+ updateQueries(collection, changes) {
165
+ this.queuedQueryUpdates.set(collection.name, this.queuedQueryUpdates.get(collection.name) || { added: [], modified: [], removed: [] });
166
+ this.queuedQueryUpdates.get(collection.name)?.added.push(...changes.added);
167
+ this.queuedQueryUpdates.get(collection.name)?.modified.push(...changes.modified);
168
+ this.queuedQueryUpdates.get(collection.name)?.removed.push(...changes.removed);
169
+ this.flushQueuedQueryUpdates(collection);
355
170
  }
356
- async updateMany(collectionName, selector, modifier) {
357
- const storage = this.storageAdapters.get(collectionName);
358
- if (!storage)
359
- throw new Error(`No persistence adapter for collection ${collectionName}`);
360
- const items = await this.executeQuery(collectionName, selector);
361
- if (items.length === 0)
362
- return [];
363
- const { $setOnInsert, ...rest } = modifier;
364
- const changed = await Promise.all(items.map(async (item) => {
365
- const modified = modify(deepClone.default(item), rest);
366
- if (item.id !== modified.id) {
367
- const existing = await this.executeQuery(collectionName, { id: modified.id }, { limit: 1 });
368
- if (existing.length > 0)
369
- throw new Error(`Item with id ${String(modified.id)} already exists`);
370
- }
371
- return modified;
372
- }));
373
- await storage.replace(changed);
374
- await this.checkQueryUpdates(collectionName, changed);
375
- return changed;
171
+ createCollectionBackend(collection, indices) {
172
+ this.collections.add(collection);
173
+ this.ensureStorageAdapter(collection.name);
174
+ this.items.set(collection.name, this.items.get(collection.name) ?? /* @__PURE__ */ new Map());
175
+ this.queryEmitters.set(collection.name, this.queryEmitters.get(collection.name) ?? new EventEmitter());
176
+ this.queryEmitters.get(collection.name)?.setMaxListeners(Infinity);
177
+ this.activeQueries.set(collection.name, this.activeQueries.get(collection.name) || /* @__PURE__ */ new Map());
178
+ this.indices.set(collection.name, indices.map((field) => createIndex(field)));
179
+ this.rebuildIndices(collection);
180
+ const persistenceReadyPromise = this.setupStorageAdapter(collection);
181
+ const backend = {
182
+ // CRUD operations
183
+ insert: async (newItem) => {
184
+ const items = this.items.get(collection.name);
185
+ if (!items)
186
+ throw new Error(`Items not found for collection ${collection.name}`);
187
+ if (items.has(serializeValue(newItem.id))) {
188
+ throw new Error(`Item with id '${newItem.id}' already exists`);
189
+ }
190
+ this.items.get(collection.name)?.set(serializeValue(newItem.id), newItem);
191
+ await this.storageAdapters.get(collection.name)?.insert([newItem]);
192
+ this.applyIndexDeltas(collection, { added: [newItem] });
193
+ this.updateQueries(collection, {
194
+ added: [],
195
+ modified: [newItem],
196
+ removed: []
197
+ });
198
+ return newItem;
199
+ },
200
+ updateOne: async (selector, modifier) => {
201
+ const { $setOnInsert, ...restModifier } = modifier;
202
+ const item = this.getItem(collection, selector);
203
+ if (item == null)
204
+ return [];
205
+ const modifiedItem = modify(deepClone.default(item), restModifier);
206
+ const hasItemWithSameId = item.id !== modifiedItem.id && this.getItem(collection, { id: modifiedItem.id }) != null;
207
+ if (hasItemWithSameId) {
208
+ throw new Error(`Item with id '${modifiedItem.id}' already exists`);
209
+ }
210
+ this.items.get(collection.name)?.set(serializeValue(modifiedItem.id), modifiedItem);
211
+ await this.storageAdapters.get(collection.name)?.replace([modifiedItem]);
212
+ this.applyIndexDeltas(collection, { modified: [{ oldItem: item, newItem: modifiedItem }] });
213
+ this.updateQueries(collection, {
214
+ added: [],
215
+ modified: [modifiedItem],
216
+ removed: []
217
+ });
218
+ return [modifiedItem];
219
+ },
220
+ updateMany: async (selector, modifier) => {
221
+ const { $setOnInsert, ...restModifier } = modifier;
222
+ const items = this.executeQuery(collection, selector, {});
223
+ const changedItems = items.map((item) => {
224
+ const modifiedItem = modify(deepClone.default(item), restModifier);
225
+ const hasItemWithSameId = item.id !== modifiedItem.id && this.getItem(collection, { id: modifiedItem.id }) != null;
226
+ if (hasItemWithSameId) {
227
+ throw new Error(`Item with id '${modifiedItem.id}' already exists`);
228
+ }
229
+ return modifiedItem;
230
+ });
231
+ changedItems.forEach((item) => {
232
+ this.items.get(collection.name)?.set(serializeValue(item.id), item);
233
+ });
234
+ await this.storageAdapters.get(collection.name)?.replace(changedItems);
235
+ const pairs = items.map((oldItem, index) => ({ oldItem, newItem: changedItems[index] }));
236
+ this.applyIndexDeltas(collection, { modified: pairs });
237
+ this.updateQueries(collection, {
238
+ added: [],
239
+ modified: changedItems,
240
+ removed: []
241
+ });
242
+ return changedItems;
243
+ },
244
+ replaceOne: async (selector, replacement) => {
245
+ const item = this.getItem(collection, selector);
246
+ if (item == null)
247
+ return [];
248
+ const hasItemWithSameId = item.id !== replacement.id && replacement.id != null && this.getItem(collection, { id: replacement.id }) != null;
249
+ if (hasItemWithSameId) {
250
+ throw new Error(`Item with id '${replacement.id}' already exists`);
251
+ }
252
+ const modifiedItem = { id: item.id, ...replacement };
253
+ this.items.get(collection.name)?.set(serializeValue(modifiedItem.id), modifiedItem);
254
+ await this.storageAdapters.get(collection.name)?.replace([modifiedItem]);
255
+ this.applyIndexDeltas(collection, { modified: [{ oldItem: item, newItem: modifiedItem }] });
256
+ this.updateQueries(collection, {
257
+ added: [],
258
+ modified: [modifiedItem],
259
+ removed: []
260
+ });
261
+ return [modifiedItem];
262
+ },
263
+ removeOne: async (selector) => {
264
+ const item = this.getItem(collection, selector);
265
+ if (item == null)
266
+ return [];
267
+ this.items.get(collection.name)?.delete(serializeValue(item.id));
268
+ await this.storageAdapters.get(collection.name)?.remove([item]);
269
+ this.applyIndexDeltas(collection, { removed: [item] });
270
+ this.updateQueries(collection, {
271
+ added: [],
272
+ modified: [],
273
+ removed: [item]
274
+ });
275
+ return [item];
276
+ },
277
+ removeMany: async (selector) => {
278
+ const items = backend.getQueryResult(selector, {});
279
+ items.forEach((item) => {
280
+ this.items.get(collection.name)?.delete(serializeValue(item.id));
281
+ });
282
+ await this.storageAdapters.get(collection.name)?.remove(items);
283
+ this.applyIndexDeltas(collection, { removed: items });
284
+ this.updateQueries(collection, {
285
+ added: [],
286
+ modified: [],
287
+ removed: items
288
+ });
289
+ return items;
290
+ },
291
+ // methods for registering and unregistering queries that will be called from the collection during find/findOne
292
+ registerQuery: (selector, options) => {
293
+ this.activeQueries.set(collection.name, this.activeQueries.get(collection.name) || /* @__PURE__ */ new Map());
294
+ this.activeQueries.get(collection.name)?.set(queryId(selector, options), {
295
+ selector,
296
+ options
297
+ });
298
+ this.executeAndCacheQuery(collection, selector, options);
299
+ },
300
+ unregisterQuery: (selector, options) => {
301
+ if (!this.activeQueries.get(collection.name))
302
+ return;
303
+ this.activeQueries.get(collection.name)?.delete(queryId(selector, options));
304
+ },
305
+ getQueryState: () => "complete",
306
+ onQueryStateChange: (selector, options, callback) => {
307
+ const emitter = this.queryEmitters.get(collection.name);
308
+ if (!emitter)
309
+ throw new Error(`Query emitter not found for collection ${collection.name}`);
310
+ const handler = (querySelector, queryOptions, state) => {
311
+ if (queryId(querySelector, queryOptions) !== queryId(selector, options))
312
+ return;
313
+ callback(state);
314
+ };
315
+ emitter.on("change", handler);
316
+ return () => {
317
+ emitter.off("change", handler);
318
+ };
319
+ },
320
+ getQueryError: () => null,
321
+ getQueryResult: (selector, options) => {
322
+ const isQueryActive = this.activeQueries.get(collection.name)?.has(queryId(selector, options));
323
+ if (isQueryActive) {
324
+ const results = this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options));
325
+ if (!results)
326
+ throw new Error("Cached query results are not defined!");
327
+ return results;
328
+ }
329
+ return this.executeQuery(collection, selector, options);
330
+ },
331
+ executeQuery: (selector, options) => Promise.resolve(this.executeQuery(collection, selector, options)),
332
+ // lifecycle methods
333
+ dispose: async () => {
334
+ const adapter = this.storageAdapters.get(collection.name);
335
+ if (adapter?.teardown)
336
+ await adapter.teardown();
337
+ this.storageAdapters.delete(collection.name);
338
+ this.items.delete(collection.name);
339
+ this.indices.delete(collection.name);
340
+ this.activeQueries.delete(collection.name);
341
+ this.queryEmitters.delete(collection.name);
342
+ this.queuedQueryUpdates.delete(collection.name);
343
+ this.cachedQueryResults.delete(collection.name);
344
+ },
345
+ isReady: () => persistenceReadyPromise
346
+ };
347
+ return backend;
376
348
  }
377
- async replaceOne(collectionName, selector, replacement) {
378
- const storage = this.storageAdapters.get(collectionName);
379
- if (!storage)
380
- throw new Error(`No persistence adapter for collection ${collectionName}`);
381
- const items = await this.executeQuery(collectionName, selector, { limit: 1 });
382
- const [item] = items;
383
- if (item == null)
384
- return [];
385
- const modified = { ...replacement, id: replacement.id ?? item.id };
386
- if (item.id !== modified.id) {
387
- const existing = await this.executeQuery(collectionName, { id: modified.id }, { limit: 1 });
388
- if (existing.length > 0)
389
- throw new Error(`Item with id ${String(modified.id)} already exists`);
349
+ async fetchItemsFromStorage(collection) {
350
+ if (!collection) {
351
+ await Promise.all([...this.collections].map((currentCollection) => this.fetchItemsFromStorage(currentCollection)));
352
+ return;
390
353
  }
391
- await storage.replace([modified]);
392
- await this.checkQueryUpdates(collectionName, [modified]);
393
- return [modified];
394
- }
395
- async removeOne(collectionName, selector) {
396
- const storage = this.storageAdapters.get(collectionName);
397
- if (!storage)
398
- throw new Error(`No persistence adapter for collection ${collectionName}`);
399
- const items = await this.executeQuery(collectionName, selector, { limit: 1 });
400
- const [item] = items;
401
- if (item == null)
402
- return [];
403
- await storage.remove([item]);
404
- await this.checkQueryUpdates(collectionName, [item]);
405
- return [item];
406
- }
407
- async removeMany(collectionName, selector) {
408
- const storage = this.storageAdapters.get(collectionName);
409
- if (!storage)
410
- throw new Error(`No persistence adapter for collection ${collectionName}`);
411
- const items = await this.executeQuery(collectionName, selector);
412
- if (items.length === 0)
413
- return [];
414
- await storage.remove(items);
415
- await this.checkQueryUpdates(collectionName, items);
416
- return items;
354
+ const storageAdapter = this.storageAdapters.get(collection.name);
355
+ if (!storageAdapter)
356
+ return;
357
+ const items = await storageAdapter.readAll();
358
+ this.items.set(collection.name, items.reduce((map, item) => {
359
+ map.set(serializeValue(item.id), item);
360
+ return map;
361
+ }, /* @__PURE__ */ new Map()));
362
+ this.rebuildIndices(collection);
417
363
  }
418
364
  }
419
- module.exports = AsyncDataAdapter;
365
+ module.exports = DefaultDataAdapter;