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

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 -11
  2. package/dist/AsyncDataAdapter.d.ts +1 -1
  3. package/dist/AutoFetchDataAdapter.d.ts +1 -2
  4. package/dist/Collection/Cursor.d.ts +3 -2
  5. package/dist/Collection/index.d.ts +17 -12
  6. package/dist/Collection/types.d.ts +1 -0
  7. package/dist/DataAdapter.d.ts +9 -7
  8. package/dist/DefaultDataAdapter.d.ts +2 -1
  9. package/dist/WorkerDataAdapter.d.ts +5 -2
  10. package/dist/WorkerDataAdapterHost.d.ts +9 -6
  11. package/dist/index.cjs12.js +35 -21
  12. package/dist/index.cjs13.js +27 -15
  13. package/dist/index.cjs14.js +72 -56
  14. package/dist/index.cjs15.js +122 -75
  15. package/dist/index.cjs16.js +45 -36
  16. package/dist/index.cjs17.js +4 -2
  17. package/dist/index.cjs19.js +0 -1
  18. package/dist/index.cjs2.js +6 -2
  19. package/dist/index.cjs20.js +14 -102
  20. package/dist/index.cjs21.js +93 -118
  21. package/dist/index.cjs22.js +127 -5
  22. package/dist/index.cjs23.js +5 -25
  23. package/dist/index.cjs24.js +25 -5
  24. package/dist/index.cjs27.js +44 -3
  25. package/dist/index.cjs28.js +6 -5
  26. package/dist/index.cjs29.js +5 -27
  27. package/dist/index.cjs3.js +41 -22
  28. package/dist/index.cjs31.js +27 -7
  29. package/dist/index.cjs32.js +9 -0
  30. package/dist/index.cjs33.js +5 -0
  31. package/dist/index.d.ts +2 -1
  32. package/dist/index12.mjs +35 -21
  33. package/dist/index13.mjs +27 -15
  34. package/dist/index14.mjs +72 -56
  35. package/dist/index15.mjs +122 -75
  36. package/dist/index16.mjs +45 -36
  37. package/dist/index17.mjs +4 -2
  38. package/dist/index19.mjs +0 -1
  39. package/dist/index2.mjs +6 -2
  40. package/dist/index20.mjs +14 -102
  41. package/dist/index21.mjs +93 -117
  42. package/dist/index22.mjs +126 -5
  43. package/dist/index23.mjs +5 -25
  44. package/dist/index24.mjs +25 -5
  45. package/dist/index27.mjs +44 -3
  46. package/dist/index28.mjs +6 -5
  47. package/dist/index29.mjs +5 -27
  48. package/dist/index3.mjs +41 -22
  49. package/dist/index31.mjs +27 -7
  50. package/dist/index32.mjs +10 -0
  51. package/dist/index33.mjs +6 -0
  52. package/dist/utils/batchOnNextTick.d.ts +16 -0
  53. package/dist/utils/deepClone.d.ts +1 -1
  54. package/package.json +3 -3
@@ -1,18 +1,24 @@
1
1
  "use strict";
2
- const queryId = require("./index.cjs24.js");
2
+ const queryId = require("./index.cjs20.js");
3
3
  const randomId = require("./index.cjs8.js");
4
+ const batchOnNextTick = require("./index.cjs27.js");
4
5
  class WorkerDataAdapter {
5
6
  worker;
6
7
  options;
7
8
  id;
8
9
  isDisposed = false;
9
10
  workerReady;
11
+ log = () => {
12
+ };
10
13
  collectionReady = /* @__PURE__ */ new Map();
14
+ batchExecutionHelpers = /* @__PURE__ */ new Map();
11
15
  queries = {};
12
16
  constructor(worker, options) {
13
17
  this.worker = worker;
14
18
  this.options = options;
15
19
  this.id = this.options.id || "default-worker-data-adapter";
20
+ if (this.options.log)
21
+ this.log = this.options.log;
16
22
  this.workerReady = new Promise((resolve, reject) => {
17
23
  const timeoutId = setTimeout(() => {
18
24
  reject(new Error("WorkerDataAdapter initialization timed out"));
@@ -51,6 +57,7 @@ class WorkerDataAdapter {
51
57
  return;
52
58
  if (id !== messageId)
53
59
  return;
60
+ this.log(method, "result", data ?? error);
54
61
  if (error) {
55
62
  reject(error);
56
63
  } else {
@@ -67,88 +74,59 @@ class WorkerDataAdapter {
67
74
  });
68
75
  });
69
76
  }
70
- queryListeners(collectionName, query, listeners) {
71
- if (listeners != null) {
72
- return this.updateQuery(collectionName, query, { listeners });
73
- }
74
- const id = queryId(query.selector, query.options);
75
- const collectionQueries = this.queries[collectionName];
76
- if (!collectionQueries)
77
- return 0;
78
- const existing = collectionQueries.get(id);
79
- return existing?.listeners || 0;
77
+ enqueueBatched(collectionName, method, args) {
78
+ const helper = this.batchExecutionHelpers.get(collectionName);
79
+ if (!helper)
80
+ throw new Error(`Collection "${collectionName}" is not registered in WorkerDataAdapter`);
81
+ return helper.enqueue(method, args);
80
82
  }
83
+ // ---------- end batching integration ----------
81
84
  updateQuery(collectionName, query, update) {
82
85
  const id = queryId(query.selector, query.options);
83
86
  const collectionQueries = this.queries[collectionName];
84
87
  if (!collectionQueries)
85
88
  return;
86
89
  const existing = collectionQueries.get(id);
87
- collectionQueries.set(id, {
88
- listeners: 0,
90
+ const newState = {
89
91
  state: "active",
90
92
  error: null,
91
93
  items: [],
94
+ stateChangeCallbacks: [],
95
+ eventHandler: existing?.eventHandler,
92
96
  ...existing,
93
97
  ...update
94
- });
98
+ };
99
+ collectionQueries.set(id, newState);
95
100
  this.queries[collectionName] = collectionQueries;
96
101
  }
97
- createCollectionBackend(collection, indices = []) {
102
+ createCollectionBackend(collection, indices) {
98
103
  this.queries[collection.name] = /* @__PURE__ */ new Map();
99
104
  void this.exec("registerCollection", collection.name, indices);
100
105
  this.collectionReady.set(collection.name, this.exec("isReady", collection.name));
106
+ this.batchExecutionHelpers.set(collection.name, batchOnNextTick(async (method, args) => this.exec(method, collection.name, args)));
101
107
  return {
102
108
  insert: async (item) => {
103
- return this.exec("insert", collection.name, item);
109
+ return this.enqueueBatched(collection.name, "insert", [item]);
104
110
  },
105
111
  updateOne: async (selector, modifier) => {
106
- return this.exec("updateOne", collection.name, selector, modifier);
112
+ return this.enqueueBatched(collection.name, "updateOne", [selector, modifier]);
107
113
  },
108
114
  updateMany: async (selector, modifier) => {
109
- return this.exec("updateMany", collection.name, selector, modifier);
115
+ return this.enqueueBatched(collection.name, "updateMany", [selector, modifier]);
110
116
  },
111
117
  replaceOne: async (selector, replacement) => {
112
- return this.exec("replaceOne", collection.name, selector, replacement);
118
+ return this.enqueueBatched(collection.name, "replaceOne", [selector, replacement]);
113
119
  },
114
120
  removeOne: async (selector) => {
115
- return this.exec("removeOne", collection.name, selector);
121
+ return this.enqueueBatched(collection.name, "removeOne", [selector]);
116
122
  },
117
123
  removeMany: async (selector) => {
118
- return this.exec("removeMany", collection.name, selector);
124
+ return this.enqueueBatched(collection.name, "removeMany", [selector]);
119
125
  },
120
126
  // methods for registering and unregistering queries that will be called from the collection during find/findOne
121
127
  registerQuery: (selector, options) => {
122
- const listeners = this.queryListeners(collection.name, { selector, options });
123
- if (listeners === 0) {
124
- this.updateQuery(collection.name, { selector, options }, { state: "active", error: null, items: [] });
125
- void this.exec("registerQuery", collection.name, selector, options);
126
- }
127
- this.queryListeners(collection.name, { selector, options }, listeners + 1);
128
- },
129
- unregisterQuery: (selector, options) => {
130
- setTimeout(() => {
131
- const listeners = this.queryListeners(collection.name, { selector, options });
132
- const newListeners = Math.max(0, listeners - 1);
133
- if (newListeners === 0) {
134
- this.queries[collection.name]?.delete(queryId(selector, options));
135
- void this.exec("unregisterQuery", collection.name, selector, options);
136
- }
137
- }, 0);
138
- },
139
- getQueryState: (selector, options) => {
140
- const query = this.queries[collection.name]?.get(queryId(selector, options));
141
- return query?.state || "active";
142
- },
143
- getQueryError: (selector, options) => {
144
- const query = this.queries[collection.name]?.get(queryId(selector, options));
145
- return query?.error || null;
146
- },
147
- getQueryResult: (selector, options) => {
148
- const query = this.queries[collection.name]?.get(queryId(selector, options));
149
- return query?.items || [];
150
- },
151
- onQueryStateChange: (selector, options, callback) => {
128
+ this.updateQuery(collection.name, { selector, options }, { state: "active", error: null, items: [] });
129
+ void this.exec("registerQuery", collection.name, selector, options);
152
130
  const handler = (event) => {
153
131
  const { type, data, workerId, error } = event.data;
154
132
  if (type !== "queryUpdate")
@@ -160,21 +138,59 @@ class WorkerDataAdapter {
160
138
  return;
161
139
  if (collectionName !== collection.name)
162
140
  return;
163
- if (JSON.stringify(responseSelector) !== JSON.stringify(selector))
164
- return;
165
- if (JSON.stringify(responseOptions) !== JSON.stringify(options))
141
+ if (queryId(responseSelector, responseOptions) !== queryId(selector, options))
166
142
  return;
143
+ this.log("queryUpdate", responseSelector, responseOptions, state, data ?? error);
167
144
  this.updateQuery(collection.name, {
168
145
  selector: responseSelector,
169
146
  options: responseOptions
170
147
  }, { state, error, items });
171
- callback(state);
148
+ const query = this.queries[collection.name]?.get(queryId(selector, options));
149
+ if (!query)
150
+ return;
151
+ query.stateChangeCallbacks.forEach((callback) => callback(state));
172
152
  };
173
153
  this.worker.addEventListener("message", handler);
154
+ this.updateQuery(collection.name, { selector, options }, { eventHandler: handler });
155
+ },
156
+ unregisterQuery: (selector, options) => {
157
+ const qid = queryId(selector, options);
158
+ const query = this.queries[collection.name]?.get(qid);
159
+ if (query?.eventHandler) {
160
+ this.worker.removeEventListener("message", query.eventHandler);
161
+ }
162
+ this.queries[collection.name]?.delete(qid);
163
+ void this.exec("unregisterQuery", collection.name, selector, options);
164
+ },
165
+ getQueryState: (selector, options) => {
166
+ const query = this.queries[collection.name]?.get(queryId(selector, options));
167
+ return query?.state || "active";
168
+ },
169
+ getQueryError: (selector, options) => {
170
+ const query = this.queries[collection.name]?.get(queryId(selector, options));
171
+ return query?.error || null;
172
+ },
173
+ getQueryResult: (selector, options) => {
174
+ const query = this.queries[collection.name]?.get(queryId(selector, options));
175
+ return query?.items || [];
176
+ },
177
+ onQueryStateChange: (selector, options, callback) => {
178
+ this.updateQuery(collection.name, { selector, options }, {
179
+ stateChangeCallbacks: [
180
+ ...this.queries[collection.name]?.get(queryId(selector, options))?.stateChangeCallbacks || [],
181
+ callback
182
+ ]
183
+ });
174
184
  return () => {
175
- this.worker.removeEventListener("message", handler);
185
+ const currentCallbacks = this.queries[collection.name]?.get(queryId(selector, options))?.stateChangeCallbacks;
186
+ if (!currentCallbacks)
187
+ throw new Error("State change callbacks are not defined!");
188
+ this.updateQuery(collection.name, { selector, options }, {
189
+ stateChangeCallbacks: currentCallbacks.filter((existingCallback) => existingCallback !== callback)
190
+ });
176
191
  };
177
192
  },
193
+ executeQuery: (selector, options) => this.exec("executeQuery", collection.name, selector, options),
178
194
  // lifecycle methods
179
195
  dispose: async () => {
180
196
  await this.exec("unregisterCollection", collection.name);
@@ -1,17 +1,20 @@
1
1
  "use strict";
2
2
  const deepClone = require("./index.cjs19.js");
3
- const match = require("./index.cjs22.js");
3
+ const match = require("./index.cjs23.js");
4
4
  const modify = require("./index.cjs7.js");
5
- const queryId = require("./index.cjs24.js");
5
+ const queryId = require("./index.cjs20.js");
6
6
  const isEqual = require("./index.cjs6.js");
7
- const getIndexInfo = require("./index.cjs21.js");
7
+ const getIndexInfo = require("./index.cjs22.js");
8
8
  const getMatchingKeys = require("./index.cjs26.js");
9
9
  const sortItems = require("./index.cjs25.js");
10
- const project = require("./index.cjs23.js");
10
+ const project = require("./index.cjs24.js");
11
+ const compact = require("./index.cjs28.js");
11
12
  class WorkerDataAdapterHost {
12
13
  workerContext;
13
14
  options;
14
15
  id;
16
+ log = () => {
17
+ };
15
18
  storageAdapters = /* @__PURE__ */ new Map();
16
19
  storageAdapterReady = /* @__PURE__ */ new Map();
17
20
  collectionIndices = /* @__PURE__ */ new Map();
@@ -26,6 +29,8 @@ class WorkerDataAdapterHost {
26
29
  if (this.options.onError) {
27
30
  this.onError = this.options.onError;
28
31
  }
32
+ if (this.options.log)
33
+ this.log = this.options.log;
29
34
  if (typeof addEventListener === "undefined" || typeof postMessage === "undefined") {
30
35
  throw new TypeError("WorkerDataAdapterHost can only be used in a Web Worker context");
31
36
  }
@@ -50,6 +55,8 @@ class WorkerDataAdapterHost {
50
55
  this.respond(id, null, new Error(`Method ${method} not found`));
51
56
  return;
52
57
  }
58
+ this.log(method, ...args);
59
+ await this.isReady(args[0]);
53
60
  try {
54
61
  const result = await fn.apply(this, args);
55
62
  this.respond(id, result);
@@ -64,7 +71,7 @@ class WorkerDataAdapterHost {
64
71
  if (selector != null && Object.keys(selector).length === 1 && "id" in selector && typeof selector.id !== "object") {
65
72
  return {
66
73
  matched: true,
67
- ids: [selector.id],
74
+ ids: compact([selector.id]),
68
75
  optimizedSelector: {}
69
76
  };
70
77
  }
@@ -149,6 +156,8 @@ class WorkerDataAdapterHost {
149
156
  }
150
157
  }
151
158
  async executeQuery(collectionName, selector, options) {
159
+ if (selector === null)
160
+ return [];
152
161
  const items = await this.queryItems(collectionName, selector || {});
153
162
  const { sort, skip, limit, fields } = options || {};
154
163
  const sorted = sort ? sortItems(items, sort) : items;
@@ -214,10 +223,7 @@ class WorkerDataAdapterHost {
214
223
  if (!storageAdapter)
215
224
  throw new Error(`No persistence adapter for collection ${collectionName}`);
216
225
  const setupPromise = (async () => {
217
- await Promise.all([
218
- storageAdapter.createIndex("id"),
219
- ...indices.map((index) => storageAdapter.createIndex(index))
220
- ]);
226
+ await Promise.all(indices.map((index) => storageAdapter.createIndex(index)));
221
227
  await storageAdapter.setup();
222
228
  })();
223
229
  this.storageAdapterReady.set(collectionName, setupPromise);
@@ -238,101 +244,142 @@ class WorkerDataAdapterHost {
238
244
  throw new Error(`Collection ${collectionName} not initialized!`);
239
245
  this.queries.get(collectionName)?.delete(id);
240
246
  };
241
- insert = async (collectionName, newItem) => {
247
+ insert = async (collectionName, input) => {
242
248
  const storageAdapter = this.storageAdapters.get(collectionName);
243
249
  if (!storageAdapter)
244
250
  throw new Error(`No persistence adapter for collection ${collectionName}`);
245
- const existingItems = await this.executeQuery(collectionName, { id: newItem.id }, { limit: 1 });
246
- if (existingItems.length > 0) {
247
- throw new Error(`Item with id ${newItem.id} already exists`);
248
- }
249
- await storageAdapter.insert([newItem]);
250
- await this.checkQueryUpdates(collectionName, [newItem]);
251
- return newItem;
252
- };
253
- updateOne = async (collectionName, selector, modifier) => {
254
- const storageAdapter = this.storageAdapters.get(collectionName);
255
- if (!storageAdapter)
256
- throw new Error(`No persistence adapter for collection ${collectionName}`);
257
- const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then((items) => items[0] ?? null);
258
- const { $setOnInsert, ...restModifier } = modifier;
259
- if (item == null)
260
- return [];
261
- const modifiedItem = modify(deepClone.default(item), restModifier);
262
- if (item.id !== modifiedItem.id) {
263
- const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
264
- if (existingItems.length > 0) {
265
- throw new Error(`Item with id ${modifiedItem.id} already exists`);
251
+ const existingItems = await this.executeQuery(collectionName, { id: { $in: input.map((i) => i[0].id) } });
252
+ const result = input.map(([item]) => {
253
+ if (item.id == null)
254
+ return new Error("Item must have an id");
255
+ if (existingItems.some((existing) => existing.id === item.id)) {
256
+ return new Error(`Item with id ${item.id} already exists`);
266
257
  }
267
- }
268
- await storageAdapter.replace([modifiedItem]);
269
- await this.checkQueryUpdates(collectionName, [modifiedItem]);
270
- return [modifiedItem];
258
+ return item;
259
+ });
260
+ const newItems = result.filter((item) => !(item instanceof Error));
261
+ await storageAdapter.insert(newItems);
262
+ await this.checkQueryUpdates(collectionName, newItems);
263
+ return result;
271
264
  };
272
- updateMany = async (collectionName, selector, modifier) => {
265
+ updateOne = async (collectionName, parameters) => {
273
266
  const storageAdapter = this.storageAdapters.get(collectionName);
274
267
  if (!storageAdapter)
275
268
  throw new Error(`No persistence adapter for collection ${collectionName}`);
276
- const items = await this.executeQuery(collectionName, selector);
277
- if (items.length === 0)
278
- return [];
279
- const { $setOnInsert, ...restModifier } = modifier;
280
- const changedItems = await Promise.all(items.map(async (item) => {
269
+ const previousItems = [];
270
+ const result = await Promise.all(parameters.map(async ([selector, modifier]) => {
271
+ const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then((items) => items[0] ?? null);
272
+ const { $setOnInsert, ...restModifier } = modifier;
273
+ if (item == null)
274
+ return [];
275
+ previousItems.push(item);
281
276
  const modifiedItem = modify(deepClone.default(item), restModifier);
282
277
  if (item.id !== modifiedItem.id) {
283
278
  const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
284
279
  if (existingItems.length > 0) {
285
- throw new Error(`Item with id ${modifiedItem.id} already exists`);
280
+ return new Error(`Item with id ${modifiedItem.id} already exists`);
286
281
  }
287
282
  }
288
- return modifiedItem;
283
+ return [modifiedItem];
289
284
  }));
290
- await storageAdapter.replace(changedItems);
291
- await this.checkQueryUpdates(collectionName, changedItems);
292
- return changedItems;
285
+ const modifiedItems = compact(result.filter((item) => !(item instanceof Error)).flat());
286
+ if (modifiedItems.length > 0) {
287
+ await storageAdapter.replace(modifiedItems);
288
+ await this.checkQueryUpdates(collectionName, [...modifiedItems, ...previousItems]);
289
+ }
290
+ return result;
293
291
  };
294
- replaceOne = async (collectionName, selector, replacement) => {
292
+ updateMany = async (collectionName, parameters) => {
295
293
  const storageAdapter = this.storageAdapters.get(collectionName);
296
294
  if (!storageAdapter)
297
295
  throw new Error(`No persistence adapter for collection ${collectionName}`);
298
- const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then((items) => items[0] ?? null);
299
- if (item == null)
300
- return [];
301
- const modifiedItem = {
302
- ...replacement,
303
- id: replacement.id ?? item.id
304
- };
305
- if (item.id !== modifiedItem.id) {
306
- const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
307
- if (existingItems.length > 0) {
308
- throw new Error(`Item with id ${modifiedItem.id} already exists`);
296
+ const previousItems = [];
297
+ const result = await Promise.all(parameters.map(async ([selector, modifier]) => {
298
+ const items = await this.executeQuery(collectionName, selector);
299
+ if (items.length === 0)
300
+ return [];
301
+ const { $setOnInsert, ...restModifier } = modifier;
302
+ try {
303
+ const changedItems = await Promise.all(items.map(async (item) => {
304
+ const modifiedItem = modify(deepClone.default(item), restModifier);
305
+ if (item.id !== modifiedItem.id) {
306
+ const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
307
+ if (existingItems.length > 0) {
308
+ throw new Error(`Item with id ${modifiedItem.id} already exists`);
309
+ }
310
+ }
311
+ previousItems.push(item);
312
+ return modifiedItem;
313
+ }));
314
+ return changedItems;
315
+ } catch (error) {
316
+ return error;
309
317
  }
318
+ }));
319
+ const modifiedItems = compact(result.filter((item) => !(item instanceof Error)).flat());
320
+ if (modifiedItems.length > 0) {
321
+ await storageAdapter.replace(modifiedItems);
322
+ await this.checkQueryUpdates(collectionName, [...modifiedItems, ...previousItems]);
310
323
  }
311
- await storageAdapter.replace([modifiedItem]);
312
- await this.checkQueryUpdates(collectionName, [modifiedItem]);
313
- return [modifiedItem];
324
+ return result;
314
325
  };
315
- removeOne = async (collectionName, selector) => {
326
+ replaceOne = async (collectionName, parameters) => {
316
327
  const storageAdapter = this.storageAdapters.get(collectionName);
317
328
  if (!storageAdapter)
318
329
  throw new Error(`No persistence adapter for collection ${collectionName}`);
319
- const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then((items) => items[0] ?? null);
320
- if (item == null)
321
- return [];
322
- await storageAdapter.remove([item]);
323
- await this.checkQueryUpdates(collectionName, [item]);
324
- return [item];
330
+ const previousItems = [];
331
+ const result = await Promise.all(parameters.map(async ([selector, replacement]) => {
332
+ const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then((items) => items[0] ?? null);
333
+ if (item == null)
334
+ return [];
335
+ previousItems.push(item);
336
+ const modifiedItem = {
337
+ ...replacement,
338
+ id: replacement.id ?? item.id
339
+ };
340
+ if (item.id !== modifiedItem.id) {
341
+ const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
342
+ if (existingItems.length > 0) {
343
+ return new Error(`Item with id ${modifiedItem.id} already exists`);
344
+ }
345
+ }
346
+ return [modifiedItem];
347
+ }));
348
+ const modifiedItems = compact(result.filter((item) => !(item instanceof Error)).flat());
349
+ if (modifiedItems.length > 0) {
350
+ await storageAdapter.replace(modifiedItems);
351
+ await this.checkQueryUpdates(collectionName, [...modifiedItems, ...previousItems]);
352
+ }
353
+ return result;
325
354
  };
326
- removeMany = async (collectionName, selector) => {
355
+ removeOne = async (collectionName, selectors) => {
327
356
  const storageAdapter = this.storageAdapters.get(collectionName);
328
357
  if (!storageAdapter)
329
358
  throw new Error(`No persistence adapter for collection ${collectionName}`);
330
- const items = await this.executeQuery(collectionName, selector);
331
- if (items.length === 0)
332
- return [];
333
- await storageAdapter.remove(items);
334
- await this.checkQueryUpdates(collectionName, items);
335
- return items;
359
+ const result = await Promise.all(selectors.map(async ([selector]) => {
360
+ const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then((items2) => items2[0] ?? null);
361
+ if (item == null)
362
+ return [];
363
+ return [item];
364
+ }));
365
+ const items = result.flat();
366
+ if (items.length > 0) {
367
+ await storageAdapter.remove(items);
368
+ await this.checkQueryUpdates(collectionName, items);
369
+ }
370
+ return result;
371
+ };
372
+ removeMany = async (collectionName, selectors) => {
373
+ const storageAdapter = this.storageAdapters.get(collectionName);
374
+ if (!storageAdapter)
375
+ throw new Error(`No persistence adapter for collection ${collectionName}`);
376
+ const result = await Promise.all(selectors.map(async ([selector]) => this.executeQuery(collectionName, selector)));
377
+ const items = result.flat();
378
+ if (items.length > 0) {
379
+ await storageAdapter.remove(items);
380
+ await this.checkQueryUpdates(collectionName, items);
381
+ }
382
+ return result;
336
383
  };
337
384
  isReady = async (collectionName) => {
338
385
  return this.storageAdapterReady.get(collectionName);