@signaldb/core 1.7.1 → 2.0.0-beta.1
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/.vite/manifest.json +138 -82
- package/dist/AsyncDataAdapter.d.ts +64 -0
- package/dist/AutoFetchDataAdapter.d.ts +112 -0
- package/dist/Collection/Cursor.d.ts +9 -9
- package/dist/Collection/Observer.d.ts +3 -2
- package/dist/Collection/index.d.ts +54 -46
- package/dist/Collection/types.d.ts +4 -9
- package/dist/DataAdapter.d.ts +34 -0
- package/dist/DefaultDataAdapter.d.ts +33 -0
- package/dist/WorkerDataAdapter.d.ts +25 -0
- package/dist/WorkerDataAdapterHost.d.ts +62 -0
- package/dist/createIndex.d.ts +7 -0
- package/dist/createStorageAdapter.d.ts +9 -0
- package/dist/{Collection/getIndexInfo.d.ts → getIndexInfo.d.ts} +17 -19
- package/dist/index.cjs.js +21 -17
- package/dist/index.cjs10.js +15 -26
- package/dist/index.cjs11.js +13 -10
- package/dist/index.cjs12.js +348 -3
- package/dist/index.cjs13.js +396 -110
- package/dist/index.cjs14.js +178 -68
- package/dist/index.cjs15.js +384 -8
- package/dist/index.cjs16.js +572 -20
- package/dist/index.cjs17.js +12 -4
- package/dist/index.cjs18.js +24 -5
- package/dist/index.cjs2.js +29 -32
- package/dist/index.cjs20.js +5 -13
- package/dist/index.cjs21.js +99 -21
- package/dist/index.cjs22.js +108 -58
- package/dist/index.cjs23.js +5 -82
- package/dist/index.cjs24.js +23 -14
- package/dist/index.cjs25.js +8 -27
- package/dist/index.cjs26.js +27 -7
- package/dist/index.cjs27.js +44 -5
- package/dist/index.cjs28.js +6 -27
- package/dist/index.cjs29.js +7 -40
- package/dist/index.cjs3.js +198 -444
- package/dist/index.cjs30.js +5 -0
- package/dist/index.cjs31.js +7 -0
- package/dist/index.cjs32.js +29 -0
- package/dist/index.cjs33.js +42 -0
- package/dist/index.cjs4.js +3 -165
- package/dist/index.cjs5.js +3 -66
- package/dist/index.cjs6.js +27 -3
- package/dist/index.cjs7.js +10 -3
- package/dist/index.cjs8.js +3 -3
- package/dist/index.cjs9.js +131 -3
- package/dist/index.d.ts +11 -8
- package/dist/index.mjs +15 -11
- package/dist/index10.mjs +15 -26
- package/dist/index11.mjs +13 -10
- package/dist/index12.mjs +348 -3
- package/dist/index13.mjs +396 -110
- package/dist/index14.mjs +178 -67
- package/dist/index15.mjs +384 -8
- package/dist/index16.mjs +572 -20
- package/dist/index17.mjs +12 -4
- package/dist/index18.mjs +24 -5
- package/dist/index2.mjs +29 -32
- package/dist/index20.mjs +5 -13
- package/dist/index21.mjs +99 -21
- package/dist/index22.mjs +108 -58
- package/dist/index23.mjs +5 -81
- package/dist/index24.mjs +23 -14
- package/dist/index25.mjs +8 -27
- package/dist/index26.mjs +27 -7
- package/dist/index27.mjs +44 -5
- package/dist/index28.mjs +6 -27
- package/dist/index29.mjs +7 -40
- package/dist/index3.mjs +198 -445
- package/dist/index30.mjs +6 -0
- package/dist/index31.mjs +8 -0
- package/dist/index32.mjs +30 -0
- package/dist/index33.mjs +43 -0
- package/dist/index4.mjs +3 -165
- package/dist/index5.mjs +3 -65
- package/dist/index6.mjs +27 -3
- package/dist/index7.mjs +10 -3
- package/dist/index8.mjs +3 -3
- package/dist/index9.mjs +131 -3
- package/dist/types/IndexProvider.d.ts +12 -7
- package/dist/types/StorageAdapter.d.ts +20 -0
- package/dist/utils/batchOnNextTick.d.ts +16 -0
- package/dist/utils/objectId.d.ts +8 -0
- package/dist/utils/queryId.d.ts +9 -0
- package/package.json +1 -1
- package/dist/AutoFetchCollection.d.ts +0 -60
- package/dist/Collection/createIndex.d.ts +0 -15
- package/dist/ReplicatedCollection.d.ts +0 -60
- package/dist/createMemoryAdapter.d.ts +0 -7
- package/dist/persistence/combinePersistenceAdapters.d.ts +0 -32
- package/dist/persistence/createPersistenceAdapter.d.ts +0 -9
- package/dist/types/MemoryAdapter.d.ts +0 -15
- package/dist/types/PersistenceAdapter.d.ts +0 -20
package/dist/index3.mjs
CHANGED
|
@@ -1,37 +1,11 @@
|
|
|
1
|
-
import EventEmitter from "./
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import EventEmitter from "./index9.mjs";
|
|
2
|
+
import createSignal from "./index18.mjs";
|
|
3
|
+
import randomId from "./index8.mjs";
|
|
4
|
+
import DefaultDataAdapter from "./index12.mjs";
|
|
5
|
+
import modify from "./index7.mjs";
|
|
6
6
|
import deepClone from "./index19.mjs";
|
|
7
|
-
import
|
|
8
|
-
import createSignal from "./index21.mjs";
|
|
7
|
+
import queryId from "./index20.mjs";
|
|
9
8
|
import Cursor from "./index2.mjs";
|
|
10
|
-
import getIndexInfo from "./index22.mjs";
|
|
11
|
-
import { createExternalIndex } from "./index14.mjs";
|
|
12
|
-
import { default as default2 } from "./index14.mjs";
|
|
13
|
-
function hasPendingUpdates(pendingUpdates) {
|
|
14
|
-
return pendingUpdates.added.length > 0 || pendingUpdates.modified.length > 0 || pendingUpdates.removed.length > 0;
|
|
15
|
-
}
|
|
16
|
-
function applyUpdates(currentItems, { added, modified, removed }) {
|
|
17
|
-
const items = [...currentItems];
|
|
18
|
-
added.forEach((item) => {
|
|
19
|
-
items.push(item);
|
|
20
|
-
});
|
|
21
|
-
modified.forEach((item) => {
|
|
22
|
-
const index = items.findIndex(({ id }) => id === item.id);
|
|
23
|
-
if (index === -1)
|
|
24
|
-
return;
|
|
25
|
-
items[index] = item;
|
|
26
|
-
});
|
|
27
|
-
removed.forEach((item) => {
|
|
28
|
-
const index = items.findIndex(({ id }) => id === item.id);
|
|
29
|
-
if (index === -1)
|
|
30
|
-
return;
|
|
31
|
-
items.splice(index, 1);
|
|
32
|
-
});
|
|
33
|
-
return items;
|
|
34
|
-
}
|
|
35
9
|
class Collection extends EventEmitter {
|
|
36
10
|
static collections = [];
|
|
37
11
|
static debugMode = false;
|
|
@@ -67,210 +41,59 @@ class Collection extends EventEmitter {
|
|
|
67
41
|
collection.setFieldTracking(enable);
|
|
68
42
|
});
|
|
69
43
|
};
|
|
70
|
-
/**
|
|
71
|
-
* Executes a batch operation, allowing multiple modifications to the collection
|
|
72
|
-
* while deferring index rebuilding until all operations in the batch are completed.
|
|
73
|
-
* This improves performance by avoiding repetitive index recalculations and
|
|
74
|
-
* provides atomicity for the batch of operations.
|
|
75
|
-
* @param callback - The batch operation to execute.
|
|
76
|
-
*/
|
|
77
44
|
static batch(callback) {
|
|
78
45
|
Collection.batchOperationInProgress = true;
|
|
79
|
-
Collection.collections.reduce((memo, collection) => () =>
|
|
80
|
-
|
|
46
|
+
const execute = () => Collection.collections.reduce((memo, collection) => () => {
|
|
47
|
+
return collection.batch(memo);
|
|
48
|
+
}, callback)();
|
|
49
|
+
const maybePromise = execute();
|
|
50
|
+
const afterBatch = () => {
|
|
51
|
+
Collection.batchOperationInProgress = false;
|
|
52
|
+
};
|
|
53
|
+
if (maybePromise && typeof maybePromise.then === "function") {
|
|
54
|
+
return maybePromise.then(() => afterBatch());
|
|
55
|
+
} else {
|
|
56
|
+
afterBatch();
|
|
57
|
+
}
|
|
81
58
|
}
|
|
82
59
|
name;
|
|
60
|
+
backend;
|
|
83
61
|
options;
|
|
84
|
-
persistenceAdapter = null;
|
|
85
62
|
isPullingSignal;
|
|
86
63
|
isPushingSignal;
|
|
87
|
-
|
|
88
|
-
indicesOutdated = false;
|
|
89
|
-
idIndex = /* @__PURE__ */ new Map();
|
|
64
|
+
readySignal;
|
|
90
65
|
debugMode;
|
|
91
66
|
batchOperationInProgress = false;
|
|
92
67
|
isDisposed = false;
|
|
93
68
|
postBatchCallbacks = /* @__PURE__ */ new Set();
|
|
94
69
|
fieldTracking = false;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
* Initializes a new instance of the `Collection` class with optional configuration.
|
|
98
|
-
* Sets up memory, persistence, reactivity, and indices as specified in the options.
|
|
99
|
-
* @template T - The type of the items stored in the collection.
|
|
100
|
-
* @template I - The type of the unique identifier for the items.
|
|
101
|
-
* @template U - The transformed item type after applying transformations (default is T).
|
|
102
|
-
* @param options - Optional configuration for the collection.
|
|
103
|
-
* @param options.name - An optional name for the collection.
|
|
104
|
-
* @param options.memory - The in-memory adapter for storing items.
|
|
105
|
-
* @param options.reactivity - The reactivity adapter for observing changes in the collection.
|
|
106
|
-
* @param options.transform - A transformation function to apply to items when retrieving them.
|
|
107
|
-
* @param options.persistence - The persistence adapter for saving and loading items.
|
|
108
|
-
* @param options.indices - An array of index providers for optimized querying.
|
|
109
|
-
* @param options.enableDebugMode - A boolean to enable or disable debug mode.
|
|
110
|
-
* @param options.fieldTracking - A boolean to enable or disable field tracking by default.
|
|
111
|
-
*/
|
|
112
|
-
constructor(options) {
|
|
70
|
+
queryListenersMap = /* @__PURE__ */ new Map();
|
|
71
|
+
constructor(nameOrOptions, maybeDataAdapter, maybeOptions) {
|
|
113
72
|
super();
|
|
73
|
+
const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions?.name || `${this.constructor.name}-${randomId()}`;
|
|
74
|
+
const options = typeof nameOrOptions === "string" ? maybeOptions || {} : nameOrOptions || {};
|
|
75
|
+
const persistence = options.persistence;
|
|
76
|
+
const dataAdapter = maybeDataAdapter || new DefaultDataAdapter({
|
|
77
|
+
...persistence ? { storage: () => persistence } : {}
|
|
78
|
+
});
|
|
114
79
|
Collection.collections.push(this);
|
|
115
|
-
this.name =
|
|
116
|
-
this.options = {
|
|
117
|
-
memory: [],
|
|
118
|
-
...options
|
|
119
|
-
};
|
|
80
|
+
this.name = name;
|
|
81
|
+
this.options = { ...options };
|
|
120
82
|
this.fieldTracking = this.options.fieldTracking ?? Collection.fieldTracking;
|
|
121
83
|
this.debugMode = this.options.enableDebugMode ?? Collection.debugMode;
|
|
122
|
-
this.
|
|
123
|
-
createExternalIndex("id", this.idIndex),
|
|
124
|
-
...this.options.indices || []
|
|
125
|
-
];
|
|
126
|
-
this.rebuildIndices();
|
|
127
|
-
this.isPullingSignal = createSignal(this.options.reactivity, !!options?.persistence);
|
|
84
|
+
this.isPullingSignal = createSignal(this.options.reactivity, false);
|
|
128
85
|
this.isPushingSignal = createSignal(this.options.reactivity, false);
|
|
129
|
-
this.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
});
|
|
135
|
-
this.on("persistence.pushStarted", () => {
|
|
136
|
-
this.isPushingSignal.set(true);
|
|
137
|
-
});
|
|
138
|
-
this.on("persistence.pushCompleted", () => {
|
|
139
|
-
this.isPushingSignal.set(false);
|
|
140
|
-
});
|
|
141
|
-
this.persistenceAdapter = this.options.persistence ?? null;
|
|
142
|
-
if (this.persistenceAdapter) {
|
|
143
|
-
let ongoingSaves = 0;
|
|
144
|
-
let isInitialized = false;
|
|
145
|
-
const pendingUpdates = { added: [], modified: [], removed: [] };
|
|
146
|
-
const loadPersistentData = async (data) => {
|
|
147
|
-
if (!this.persistenceAdapter)
|
|
148
|
-
throw new Error("Persistence adapter not found");
|
|
149
|
-
this.emit("persistence.pullStarted");
|
|
150
|
-
const { items, changes } = data ?? await this.persistenceAdapter.load();
|
|
151
|
-
if (items) {
|
|
152
|
-
if (ongoingSaves > 0)
|
|
153
|
-
return;
|
|
154
|
-
this.memory().splice(0, this.memoryArray().length, ...items);
|
|
155
|
-
this.idIndex.clear();
|
|
156
|
-
this.memory().map((item, index) => {
|
|
157
|
-
this.idIndex.set(serializeValue(item.id), /* @__PURE__ */ new Set([index]));
|
|
158
|
-
});
|
|
159
|
-
} else if (changes) {
|
|
160
|
-
changes.added.forEach((item) => {
|
|
161
|
-
const index = this.memory().findIndex((document) => document.id === item.id);
|
|
162
|
-
if (index !== -1) {
|
|
163
|
-
this.memory().splice(index, 1, item);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
this.memory().push(item);
|
|
167
|
-
const itemIndex = this.memory().findIndex((document) => document === item);
|
|
168
|
-
this.idIndex.set(serializeValue(item.id), /* @__PURE__ */ new Set([itemIndex]));
|
|
169
|
-
});
|
|
170
|
-
changes.modified.forEach((item) => {
|
|
171
|
-
const index = this.memory().findIndex((document) => document.id === item.id);
|
|
172
|
-
if (index === -1)
|
|
173
|
-
throw new Error("Cannot resolve index for item");
|
|
174
|
-
this.memory().splice(index, 1, item);
|
|
175
|
-
});
|
|
176
|
-
changes.removed.forEach((item) => {
|
|
177
|
-
const index = this.memory().findIndex((document) => document.id === item.id);
|
|
178
|
-
if (index === -1)
|
|
179
|
-
throw new Error("Cannot resolve index for item");
|
|
180
|
-
this.memory().splice(index, 1);
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
this.rebuildIndices();
|
|
184
|
-
this.emit("persistence.received");
|
|
185
|
-
setTimeout(() => this.emit("persistence.pullCompleted"), 0);
|
|
186
|
-
};
|
|
187
|
-
const saveQueue = {
|
|
188
|
-
added: [],
|
|
189
|
-
modified: [],
|
|
190
|
-
removed: []
|
|
191
|
-
};
|
|
192
|
-
let isFlushing = false;
|
|
193
|
-
const flushQueue = () => {
|
|
194
|
-
if (!this.persistenceAdapter)
|
|
195
|
-
throw new Error("Persistence adapter not found");
|
|
196
|
-
if (ongoingSaves <= 0)
|
|
197
|
-
this.emit("persistence.pushStarted");
|
|
198
|
-
if (isFlushing)
|
|
199
|
-
return;
|
|
200
|
-
if (!hasPendingUpdates(saveQueue))
|
|
201
|
-
return;
|
|
202
|
-
isFlushing = true;
|
|
203
|
-
ongoingSaves += 1;
|
|
204
|
-
const currentItems = this.memoryArray();
|
|
205
|
-
const changes = { ...saveQueue };
|
|
206
|
-
saveQueue.added = [];
|
|
207
|
-
saveQueue.modified = [];
|
|
208
|
-
saveQueue.removed = [];
|
|
209
|
-
this.persistenceAdapter.save(currentItems, changes).then(() => {
|
|
210
|
-
this.emit("persistence.transmitted");
|
|
211
|
-
}).catch((error) => {
|
|
212
|
-
this.emit("persistence.error", error instanceof Error ? error : new Error(error));
|
|
213
|
-
}).finally(() => {
|
|
214
|
-
ongoingSaves -= 1;
|
|
215
|
-
isFlushing = false;
|
|
216
|
-
flushQueue();
|
|
217
|
-
if (ongoingSaves <= 0)
|
|
218
|
-
this.emit("persistence.pushCompleted");
|
|
219
|
-
});
|
|
220
|
-
};
|
|
221
|
-
this.on("added", (item) => {
|
|
222
|
-
if (!isInitialized) {
|
|
223
|
-
pendingUpdates.added.push(item);
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
saveQueue.added.push(item);
|
|
227
|
-
flushQueue();
|
|
228
|
-
});
|
|
229
|
-
this.on("changed", (item) => {
|
|
230
|
-
if (!isInitialized) {
|
|
231
|
-
pendingUpdates.modified.push(item);
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
saveQueue.modified.push(item);
|
|
235
|
-
flushQueue();
|
|
236
|
-
});
|
|
237
|
-
this.on("removed", (item) => {
|
|
238
|
-
if (!isInitialized) {
|
|
239
|
-
pendingUpdates.removed.push(item);
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
saveQueue.removed.push(item);
|
|
243
|
-
flushQueue();
|
|
244
|
-
});
|
|
245
|
-
this.persistenceAdapter.register((data) => loadPersistentData(data)).then(async () => {
|
|
246
|
-
if (!this.persistenceAdapter)
|
|
247
|
-
throw new Error("Persistence adapter not found");
|
|
248
|
-
let currentItems = this.memoryArray();
|
|
249
|
-
await loadPersistentData();
|
|
250
|
-
while (hasPendingUpdates(pendingUpdates)) {
|
|
251
|
-
const added = pendingUpdates.added.splice(0);
|
|
252
|
-
const modified = pendingUpdates.modified.splice(0);
|
|
253
|
-
const removed = pendingUpdates.removed.splice(0);
|
|
254
|
-
currentItems = applyUpdates(this.memoryArray(), { added, modified, removed });
|
|
255
|
-
await this.persistenceAdapter.save(currentItems, { added, modified, removed }).then(() => {
|
|
256
|
-
this.emit("persistence.transmitted");
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
await loadPersistentData();
|
|
260
|
-
isInitialized = true;
|
|
261
|
-
setTimeout(() => this.emit("persistence.init"), 0);
|
|
262
|
-
}).catch((error) => {
|
|
263
|
-
this.emit("persistence.error", error instanceof Error ? error : new Error(error));
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
this.persistenceReadyPromise = new Promise((resolve, reject) => {
|
|
267
|
-
if (!this.persistenceAdapter)
|
|
268
|
-
return resolve();
|
|
269
|
-
this.once("persistence.init", resolve);
|
|
270
|
-
this.once("persistence.error", reject);
|
|
86
|
+
this.readySignal = createSignal(this.options.reactivity, false);
|
|
87
|
+
this.backend = dataAdapter.createCollectionBackend(this, this.options.indices ?? []);
|
|
88
|
+
void this.backend.isReady().then(() => {
|
|
89
|
+
this.readySignal.set(true);
|
|
90
|
+
}).catch(() => {
|
|
271
91
|
});
|
|
272
92
|
Collection.onCreationCallbacks.forEach((callback) => callback(this));
|
|
273
93
|
}
|
|
94
|
+
isBatchOperationInProgress() {
|
|
95
|
+
return Collection.batchOperationInProgress || this.batchOperationInProgress;
|
|
96
|
+
}
|
|
274
97
|
/**
|
|
275
98
|
* Checks whether the collection is currently performing a pull operation
|
|
276
99
|
* ⚡️ this function is reactive!
|
|
@@ -335,17 +158,28 @@ class Collection extends EventEmitter {
|
|
|
335
158
|
*
|
|
336
159
|
* collection.insert({ name: 'Item 1' })
|
|
337
160
|
*/
|
|
338
|
-
async
|
|
339
|
-
return this.
|
|
161
|
+
async ready() {
|
|
162
|
+
return this.backend.isReady();
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Checks if the collection is ready.
|
|
166
|
+
* ⚡️ this function is reactive!
|
|
167
|
+
* @returns A boolean indicating whether the collection is ready.
|
|
168
|
+
*/
|
|
169
|
+
isReady() {
|
|
170
|
+
return this.readySignal.get() ?? false;
|
|
340
171
|
}
|
|
341
172
|
profile(fn, measureFunction) {
|
|
342
173
|
if (!this.debugMode)
|
|
343
174
|
return fn();
|
|
344
175
|
const startTime = performance.now();
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
176
|
+
const handleProfileEnd = (result) => {
|
|
177
|
+
const endTime = performance.now();
|
|
178
|
+
measureFunction(endTime - startTime);
|
|
179
|
+
return result;
|
|
180
|
+
};
|
|
181
|
+
const maybePromise = fn();
|
|
182
|
+
return maybePromise instanceof Promise ? maybePromise.then(handleProfileEnd) : handleProfileEnd(maybePromise);
|
|
349
183
|
}
|
|
350
184
|
executeInDebugMode(fn) {
|
|
351
185
|
if (!this.debugMode)
|
|
@@ -353,114 +187,53 @@ class Collection extends EventEmitter {
|
|
|
353
187
|
const callstack = new Error().stack || "";
|
|
354
188
|
fn(callstack);
|
|
355
189
|
}
|
|
356
|
-
rebuildIndices() {
|
|
357
|
-
this.indicesOutdated = true;
|
|
358
|
-
if (this.batchOperationInProgress)
|
|
359
|
-
return;
|
|
360
|
-
this.rebuildAllIndices();
|
|
361
|
-
}
|
|
362
|
-
rebuildAllIndices() {
|
|
363
|
-
this.idIndex.clear();
|
|
364
|
-
this.memory().map((item, index) => {
|
|
365
|
-
this.idIndex.set(serializeValue(item.id), /* @__PURE__ */ new Set([index]));
|
|
366
|
-
});
|
|
367
|
-
this.indexProviders.forEach((index) => index.rebuild(this.memoryArray()));
|
|
368
|
-
this.indicesOutdated = false;
|
|
369
|
-
}
|
|
370
|
-
getIndexInfo(selector) {
|
|
371
|
-
if (selector != null && Object.keys(selector).length === 1 && "id" in selector && typeof selector.id !== "object") {
|
|
372
|
-
return {
|
|
373
|
-
matched: true,
|
|
374
|
-
positions: [...this.idIndex.get(serializeValue(selector.id)) || []],
|
|
375
|
-
optimizedSelector: {}
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
if (selector == null) {
|
|
379
|
-
return {
|
|
380
|
-
matched: false,
|
|
381
|
-
positions: [],
|
|
382
|
-
optimizedSelector: {}
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
if (this.indicesOutdated) {
|
|
386
|
-
return {
|
|
387
|
-
matched: false,
|
|
388
|
-
positions: [],
|
|
389
|
-
optimizedSelector: selector
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
return getIndexInfo(this.indexProviders, selector);
|
|
393
|
-
}
|
|
394
|
-
getItemAndIndex(selector) {
|
|
395
|
-
const memory = this.memoryArray();
|
|
396
|
-
const indexInfo = this.getIndexInfo(selector);
|
|
397
|
-
const items = indexInfo.matched ? indexInfo.positions.map((index2) => memory[index2]) : memory;
|
|
398
|
-
const item = items.find((document) => match(document, selector));
|
|
399
|
-
const foundInIndex = indexInfo.matched && indexInfo.positions.find((itemIndex) => memory[itemIndex] === item);
|
|
400
|
-
const index = foundInIndex || memory.findIndex((document) => document === item);
|
|
401
|
-
if (item == null)
|
|
402
|
-
return { item: null, index: -1 };
|
|
403
|
-
if (index === -1)
|
|
404
|
-
throw new Error("Cannot resolve index for item");
|
|
405
|
-
return { item, index };
|
|
406
|
-
}
|
|
407
|
-
deleteFromIdIndex(id, index) {
|
|
408
|
-
this.idIndex.delete(serializeValue(id));
|
|
409
|
-
if (!this.batchOperationInProgress)
|
|
410
|
-
return;
|
|
411
|
-
this.idIndex.forEach(([currenIndex], key) => {
|
|
412
|
-
if (currenIndex > index) {
|
|
413
|
-
this.idIndex.set(key, /* @__PURE__ */ new Set([currenIndex - 1]));
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
memory() {
|
|
418
|
-
return this.options.memory;
|
|
419
|
-
}
|
|
420
|
-
memoryArray() {
|
|
421
|
-
return this.memory().map((item) => item);
|
|
422
|
-
}
|
|
423
190
|
transform(item) {
|
|
424
191
|
if (!this.options.transform)
|
|
425
192
|
return item;
|
|
426
193
|
return this.options.transform(item);
|
|
427
194
|
}
|
|
428
|
-
|
|
195
|
+
getItem(selector, options) {
|
|
196
|
+
const itemsOrPromise = this.getItems(selector, { ...options, limit: 1 });
|
|
197
|
+
if (itemsOrPromise instanceof Promise) {
|
|
198
|
+
return itemsOrPromise.then((items) => {
|
|
199
|
+
return items[0] || void 0;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return itemsOrPromise[0];
|
|
203
|
+
}
|
|
204
|
+
getItems(selector, options) {
|
|
205
|
+
this.emit("getItems", selector);
|
|
429
206
|
return this.profile(() => {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
const matches = match(item, indexInfo.optimizedSelector);
|
|
437
|
-
return matches;
|
|
438
|
-
};
|
|
439
|
-
this.emit("getItems", selector);
|
|
440
|
-
const memory = this.memoryArray();
|
|
441
|
-
if (!indexInfo.matched) {
|
|
442
|
-
if (isEqual(selector, {}))
|
|
443
|
-
return memory;
|
|
444
|
-
return memory.filter(matchItems);
|
|
445
|
-
}
|
|
446
|
-
const items = indexInfo.positions.map((index) => memory[index]);
|
|
447
|
-
if (isEqual(indexInfo.optimizedSelector, {}))
|
|
448
|
-
return items;
|
|
449
|
-
return items.filter(matchItems);
|
|
207
|
+
if (!options?.async)
|
|
208
|
+
return this.backend.getQueryResult(selector, options);
|
|
209
|
+
this.isPullingSignal.set(true);
|
|
210
|
+
return this.backend.executeQuery(selector, options).finally(() => {
|
|
211
|
+
this.isPullingSignal.set(false);
|
|
212
|
+
});
|
|
450
213
|
}, (measuredTime) => this.executeInDebugMode((callstack) => this.emit("_debug.getItems", callstack, selector, measuredTime)));
|
|
451
214
|
}
|
|
215
|
+
async withPushState(asyncFunction) {
|
|
216
|
+
this.isPushingSignal.set(true);
|
|
217
|
+
try {
|
|
218
|
+
return await asyncFunction();
|
|
219
|
+
} finally {
|
|
220
|
+
this.isPushingSignal.set(false);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
queryListeners(query, listeners) {
|
|
224
|
+
const id = queryId(query.selector, query.options);
|
|
225
|
+
if (listeners != null) {
|
|
226
|
+
return this.queryListenersMap.set(id, listeners);
|
|
227
|
+
}
|
|
228
|
+
return this.queryListenersMap.get(id) ?? 0;
|
|
229
|
+
}
|
|
452
230
|
/**
|
|
453
231
|
* Disposes the collection, unregisters persistence adapters, clears memory, and
|
|
454
232
|
* cleans up all resources used by the collection.
|
|
455
233
|
* @returns A promise that resolves when the collection is disposed.
|
|
456
234
|
*/
|
|
457
235
|
async dispose() {
|
|
458
|
-
|
|
459
|
-
await this.persistenceAdapter.unregister();
|
|
460
|
-
this.persistenceAdapter = null;
|
|
461
|
-
this.memory().map(() => this.memory().pop());
|
|
462
|
-
this.idIndex.clear();
|
|
463
|
-
this.indexProviders = [];
|
|
236
|
+
await this.backend.dispose();
|
|
464
237
|
this.isDisposed = true;
|
|
465
238
|
this.removeAllListeners();
|
|
466
239
|
Collection.collections = Collection.collections.filter((collection) => collection !== this);
|
|
@@ -474,12 +247,12 @@ class Collection extends EventEmitter {
|
|
|
474
247
|
* @param [options] - Options for the find operation, such as limit and sort.
|
|
475
248
|
* @returns A cursor to fetch and observe the matching items.
|
|
476
249
|
*/
|
|
477
|
-
find(selector, options) {
|
|
250
|
+
find(selector = {}, options) {
|
|
478
251
|
if (this.isDisposed)
|
|
479
252
|
throw new Error("Collection is disposed");
|
|
480
253
|
if (selector !== void 0 && (!selector || typeof selector !== "object"))
|
|
481
254
|
throw new Error("Invalid selector");
|
|
482
|
-
const cursor = new Cursor(() => this.getItems(selector), {
|
|
255
|
+
const cursor = new Cursor((() => this.getItems(selector, options || {})), {
|
|
483
256
|
reactive: this.options.reactivity,
|
|
484
257
|
fieldTracking: this.fieldTracking,
|
|
485
258
|
...options,
|
|
@@ -492,17 +265,25 @@ class Collection extends EventEmitter {
|
|
|
492
265
|
}
|
|
493
266
|
requery();
|
|
494
267
|
};
|
|
495
|
-
this.
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
this.
|
|
268
|
+
const listeners = this.queryListeners({ selector, options });
|
|
269
|
+
if (listeners === 0)
|
|
270
|
+
this.backend.registerQuery(selector, options || {});
|
|
271
|
+
this.queryListeners({ selector, options }, listeners + 1);
|
|
272
|
+
const queryStateChangeCleanup = this.backend.onQueryStateChange(selector, options || {}, (state) => {
|
|
273
|
+
if (state !== "complete")
|
|
274
|
+
return;
|
|
275
|
+
handleRequery();
|
|
276
|
+
});
|
|
499
277
|
this.emit("observer.created", selector, options);
|
|
500
278
|
return () => {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
279
|
+
setTimeout(() => {
|
|
280
|
+
const newListeners = Math.max(0, this.queryListeners({ selector, options }) - 1);
|
|
281
|
+
if (newListeners === 0)
|
|
282
|
+
this.backend.unregisterQuery(selector, options || {});
|
|
283
|
+
this.queryListeners({ selector, options }, newListeners);
|
|
284
|
+
queryStateChangeCleanup();
|
|
285
|
+
this.emit("observer.disposed", selector, options);
|
|
286
|
+
}, 0);
|
|
506
287
|
};
|
|
507
288
|
}
|
|
508
289
|
});
|
|
@@ -514,6 +295,7 @@ class Collection extends EventEmitter {
|
|
|
514
295
|
* Finds a single item in the collection based on a selector and optional options.
|
|
515
296
|
* ⚡️ this function is reactive!
|
|
516
297
|
* Returns the found item or undefined if no item matches.
|
|
298
|
+
* @template Async - Whether to perform the operation asynchronously.
|
|
517
299
|
* @template O - The options type for the find operation.
|
|
518
300
|
* @param selector - The criteria to select the item.
|
|
519
301
|
* @param [options] - Options for the find operation, such as projection.
|
|
@@ -526,23 +308,39 @@ class Collection extends EventEmitter {
|
|
|
526
308
|
limit: 1,
|
|
527
309
|
...options
|
|
528
310
|
});
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
311
|
+
const handleItems = (items) => {
|
|
312
|
+
const returnValue = items[0] || void 0;
|
|
313
|
+
this.emit("findOne", selector, options, returnValue);
|
|
314
|
+
this.executeInDebugMode((callstack) => this.emit("_debug.findOne", callstack, selector, options, returnValue));
|
|
315
|
+
return returnValue;
|
|
316
|
+
};
|
|
317
|
+
const maybePromise = cursor.fetch();
|
|
318
|
+
return maybePromise instanceof Promise ? maybePromise.then(handleItems) : handleItems(maybePromise);
|
|
533
319
|
}
|
|
534
|
-
/**
|
|
535
|
-
* Performs a batch operation, deferring index rebuilds and allowing multiple
|
|
536
|
-
* modifications to be made atomically. Executes any post-batch callbacks afterwards.
|
|
537
|
-
* @param callback - The batch operation to execute.
|
|
538
|
-
*/
|
|
539
320
|
batch(callback) {
|
|
321
|
+
if (this.batchOperationInProgress)
|
|
322
|
+
return callback();
|
|
540
323
|
this.batchOperationInProgress = true;
|
|
541
|
-
callback();
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
324
|
+
const maybePromise = callback();
|
|
325
|
+
const afterBatch = () => {
|
|
326
|
+
this.batchOperationInProgress = false;
|
|
327
|
+
this.postBatchCallbacks.forEach((callback_) => callback_());
|
|
328
|
+
this.postBatchCallbacks.clear();
|
|
329
|
+
};
|
|
330
|
+
if (maybePromise && typeof maybePromise.then === "function") {
|
|
331
|
+
return maybePromise.then(() => afterBatch());
|
|
332
|
+
} else {
|
|
333
|
+
afterBatch();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
onPostBatch(callback) {
|
|
337
|
+
if (this.isDisposed)
|
|
338
|
+
throw new Error("Collection is disposed");
|
|
339
|
+
if (this.batchOperationInProgress) {
|
|
340
|
+
this.postBatchCallbacks.add(callback);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
return callback();
|
|
546
344
|
}
|
|
547
345
|
/**
|
|
548
346
|
* Inserts a single item into the collection. Generates a unique ID if not provided.
|
|
@@ -550,20 +348,18 @@ class Collection extends EventEmitter {
|
|
|
550
348
|
* @returns The ID of the inserted item.
|
|
551
349
|
* @throws {Error} If the collection is disposed or the item has an invalid ID.
|
|
552
350
|
*/
|
|
553
|
-
insert(item) {
|
|
351
|
+
async insert(item) {
|
|
554
352
|
if (this.isDisposed)
|
|
555
353
|
throw new Error("Collection is disposed");
|
|
556
354
|
if (!item)
|
|
557
355
|
throw new Error("Invalid item");
|
|
558
356
|
const primaryKeyGenerator = this.options.primaryKeyGenerator ?? randomId;
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
this.
|
|
564
|
-
const
|
|
565
|
-
this.idIndex.set(serializeValue(newItem.id), /* @__PURE__ */ new Set([itemIndex]));
|
|
566
|
-
this.rebuildIndices();
|
|
357
|
+
const itemWithId = {
|
|
358
|
+
id: primaryKeyGenerator(item),
|
|
359
|
+
...item
|
|
360
|
+
};
|
|
361
|
+
this.emit("validate", itemWithId);
|
|
362
|
+
const newItem = await this.withPushState(() => this.backend.insert(itemWithId));
|
|
567
363
|
this.emit("added", newItem);
|
|
568
364
|
this.emit("insert", newItem);
|
|
569
365
|
this.executeInDebugMode((callstack) => this.emit("_debug.insert", callstack, newItem));
|
|
@@ -575,19 +371,18 @@ class Collection extends EventEmitter {
|
|
|
575
371
|
* @returns An array of IDs of the inserted items.
|
|
576
372
|
* @throws {Error} If the collection is disposed or the items are invalid.
|
|
577
373
|
*/
|
|
578
|
-
insertMany(items) {
|
|
374
|
+
async insertMany(items) {
|
|
579
375
|
if (this.isDisposed)
|
|
580
376
|
throw new Error("Collection is disposed");
|
|
581
377
|
if (!items)
|
|
582
378
|
throw new Error("Invalid items");
|
|
583
|
-
if (items.length === 0)
|
|
379
|
+
if (items.length === 0)
|
|
584
380
|
return [];
|
|
585
|
-
}
|
|
586
381
|
const ids = [];
|
|
587
|
-
this.batch(() => {
|
|
588
|
-
items.
|
|
589
|
-
ids.push(this.insert(item));
|
|
590
|
-
});
|
|
382
|
+
await this.batch(async () => {
|
|
383
|
+
await Promise.all(items.map(async (item) => {
|
|
384
|
+
ids.push(await this.insert(item));
|
|
385
|
+
}));
|
|
591
386
|
});
|
|
592
387
|
return ids;
|
|
593
388
|
}
|
|
@@ -600,7 +395,7 @@ class Collection extends EventEmitter {
|
|
|
600
395
|
* @returns The number of items updated (0 or 1).
|
|
601
396
|
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
602
397
|
*/
|
|
603
|
-
updateOne(selector, modifier, options) {
|
|
398
|
+
async updateOne(selector, modifier, options) {
|
|
604
399
|
if (this.isDisposed)
|
|
605
400
|
throw new Error("Collection is disposed");
|
|
606
401
|
if (!selector)
|
|
@@ -608,7 +403,7 @@ class Collection extends EventEmitter {
|
|
|
608
403
|
if (!modifier)
|
|
609
404
|
throw new Error("Invalid modifier");
|
|
610
405
|
const { $setOnInsert, ...restModifier } = modifier;
|
|
611
|
-
const
|
|
406
|
+
const item = await this.getItem(selector, { async: true });
|
|
612
407
|
if (item == null) {
|
|
613
408
|
if (options?.upsert) {
|
|
614
409
|
const newItem = modify({}, {
|
|
@@ -618,26 +413,18 @@ class Collection extends EventEmitter {
|
|
|
618
413
|
...restModifier.$set
|
|
619
414
|
}
|
|
620
415
|
});
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
}
|
|
624
|
-
this.insert(newItem);
|
|
625
|
-
}
|
|
626
|
-
} else {
|
|
627
|
-
const modifiedItem = modify(deepClone(item), restModifier);
|
|
628
|
-
if (item.id !== modifiedItem.id && this.getItemAndIndex({ id: modifiedItem.id }).item != null) {
|
|
629
|
-
throw new Error("Item with same id already exists");
|
|
416
|
+
await this.insert(newItem);
|
|
417
|
+
return 1;
|
|
630
418
|
}
|
|
631
|
-
|
|
632
|
-
this.memory().splice(index, 1, modifiedItem);
|
|
633
|
-
this.rebuildIndices();
|
|
634
|
-
this.emit("changed", modifiedItem, restModifier);
|
|
419
|
+
return 0;
|
|
635
420
|
}
|
|
421
|
+
const modifiedItem = modify(deepClone(item), restModifier);
|
|
422
|
+
this.emit("validate", modifiedItem);
|
|
423
|
+
const changes = await this.withPushState(() => this.backend.updateOne(selector, modifier));
|
|
424
|
+
this.emit("changed", modifiedItem, restModifier);
|
|
636
425
|
this.emit("updateOne", selector, modifier);
|
|
637
426
|
this.executeInDebugMode((callstack) => this.emit("_debug.updateOne", callstack, selector, modifier));
|
|
638
|
-
|
|
639
|
-
return 0;
|
|
640
|
-
return 1;
|
|
427
|
+
return changes.length;
|
|
641
428
|
}
|
|
642
429
|
/**
|
|
643
430
|
* Updates multiple items in the collection that match the given selector.
|
|
@@ -648,7 +435,7 @@ class Collection extends EventEmitter {
|
|
|
648
435
|
* @returns The number of items updated.
|
|
649
436
|
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
650
437
|
*/
|
|
651
|
-
updateMany(selector, modifier, options) {
|
|
438
|
+
async updateMany(selector, modifier, options) {
|
|
652
439
|
if (this.isDisposed)
|
|
653
440
|
throw new Error("Collection is disposed");
|
|
654
441
|
if (!selector)
|
|
@@ -656,44 +443,32 @@ class Collection extends EventEmitter {
|
|
|
656
443
|
if (!modifier)
|
|
657
444
|
throw new Error("Invalid modifier");
|
|
658
445
|
const { $setOnInsert, ...restModifier } = modifier;
|
|
659
|
-
const items = this.getItems(selector);
|
|
660
|
-
if (items.length === 0
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
446
|
+
const items = await this.getItems(selector, { async: true });
|
|
447
|
+
if (items.length === 0) {
|
|
448
|
+
if (options?.upsert) {
|
|
449
|
+
const newItem = modify({}, {
|
|
450
|
+
...restModifier,
|
|
451
|
+
$set: {
|
|
452
|
+
...$setOnInsert,
|
|
453
|
+
...restModifier.$set
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
await this.insert(newItem);
|
|
457
|
+
return 1;
|
|
670
458
|
}
|
|
671
|
-
|
|
459
|
+
return 0;
|
|
672
460
|
}
|
|
673
|
-
|
|
674
|
-
const { index } = this.getItemAndIndex({ id: item.id });
|
|
675
|
-
if (index === -1)
|
|
676
|
-
throw new Error(`Cannot resolve index for item with id '${item.id}'`);
|
|
461
|
+
items.forEach((item) => {
|
|
677
462
|
const modifiedItem = modify(deepClone(item), restModifier);
|
|
678
|
-
if (item.id !== modifiedItem.id && this.getItemAndIndex({ id: modifiedItem.id }).item != null) {
|
|
679
|
-
throw new Error(`Item with same id '${modifiedItem.id}' already exists`);
|
|
680
|
-
}
|
|
681
463
|
this.emit("validate", modifiedItem);
|
|
682
|
-
return {
|
|
683
|
-
item: modifiedItem,
|
|
684
|
-
index
|
|
685
|
-
};
|
|
686
464
|
});
|
|
687
|
-
changes.
|
|
688
|
-
|
|
689
|
-
});
|
|
690
|
-
this.rebuildIndices();
|
|
691
|
-
changes.forEach(({ item }) => {
|
|
465
|
+
const changes = await this.withPushState(() => this.backend.updateMany(selector, modifier));
|
|
466
|
+
changes.forEach((item) => {
|
|
692
467
|
this.emit("changed", item, restModifier);
|
|
693
468
|
});
|
|
694
469
|
this.emit("updateMany", selector, modifier);
|
|
695
470
|
this.executeInDebugMode((callstack) => this.emit("_debug.updateMany", callstack, selector, modifier));
|
|
696
|
-
return changes.length
|
|
471
|
+
return changes.length;
|
|
697
472
|
}
|
|
698
473
|
/**
|
|
699
474
|
* Replaces a single item in the collection that matches the given selector.
|
|
@@ -704,34 +479,26 @@ class Collection extends EventEmitter {
|
|
|
704
479
|
* @returns The number of items replaced (0 or 1).
|
|
705
480
|
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
706
481
|
*/
|
|
707
|
-
replaceOne(selector, replacement, options) {
|
|
482
|
+
async replaceOne(selector, replacement, options) {
|
|
708
483
|
if (this.isDisposed)
|
|
709
484
|
throw new Error("Collection is disposed");
|
|
710
485
|
if (!selector)
|
|
711
486
|
throw new Error("Invalid selector");
|
|
712
|
-
const
|
|
487
|
+
const item = await this.getItem(selector, { async: true });
|
|
713
488
|
if (item == null) {
|
|
714
489
|
if (options?.upsert) {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
}
|
|
718
|
-
this.insert(replacement);
|
|
490
|
+
await this.insert(replacement);
|
|
491
|
+
return 1;
|
|
719
492
|
}
|
|
720
|
-
|
|
721
|
-
if (item.id !== replacement.id && this.getItemAndIndex({ id: replacement.id }).item != null) {
|
|
722
|
-
throw new Error("Item with same id already exists");
|
|
723
|
-
}
|
|
724
|
-
const modifiedItem = { id: item.id, ...replacement };
|
|
725
|
-
this.emit("validate", modifiedItem);
|
|
726
|
-
this.memory().splice(index, 1, modifiedItem);
|
|
727
|
-
this.rebuildIndices();
|
|
728
|
-
this.emit("changed", modifiedItem, replacement);
|
|
493
|
+
return 0;
|
|
729
494
|
}
|
|
495
|
+
const modifiedItem = { id: item.id, ...replacement };
|
|
496
|
+
this.emit("validate", modifiedItem);
|
|
497
|
+
const changes = await this.withPushState(() => this.backend.replaceOne(selector, replacement));
|
|
498
|
+
this.emit("changed", modifiedItem, replacement);
|
|
730
499
|
this.emit("replaceOne", selector, replacement);
|
|
731
500
|
this.executeInDebugMode((callstack) => this.emit("_debug.replaceOne", callstack, selector, replacement));
|
|
732
|
-
|
|
733
|
-
return 0;
|
|
734
|
-
return 1;
|
|
501
|
+
return changes.length;
|
|
735
502
|
}
|
|
736
503
|
/**
|
|
737
504
|
* Removes a single item from the collection that matches the given selector.
|
|
@@ -739,21 +506,16 @@ class Collection extends EventEmitter {
|
|
|
739
506
|
* @returns The number of items removed (0 or 1).
|
|
740
507
|
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
741
508
|
*/
|
|
742
|
-
removeOne(selector) {
|
|
509
|
+
async removeOne(selector) {
|
|
743
510
|
if (this.isDisposed)
|
|
744
511
|
throw new Error("Collection is disposed");
|
|
745
512
|
if (!selector)
|
|
746
513
|
throw new Error("Invalid selector");
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
this.memory().splice(index, 1);
|
|
750
|
-
this.deleteFromIdIndex(item.id, index);
|
|
751
|
-
this.rebuildIndices();
|
|
752
|
-
this.emit("removed", item);
|
|
753
|
-
}
|
|
514
|
+
const removedItems = await this.withPushState(() => this.backend.removeOne(selector));
|
|
515
|
+
this.emit("removed", removedItems[0]);
|
|
754
516
|
this.emit("removeOne", selector);
|
|
755
517
|
this.executeInDebugMode((callstack) => this.emit("_debug.removeOne", callstack, selector));
|
|
756
|
-
return
|
|
518
|
+
return removedItems.length;
|
|
757
519
|
}
|
|
758
520
|
/**
|
|
759
521
|
* Removes multiple items from the collection that match the given selector.
|
|
@@ -761,29 +523,20 @@ class Collection extends EventEmitter {
|
|
|
761
523
|
* @returns The number of items removed.
|
|
762
524
|
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
763
525
|
*/
|
|
764
|
-
removeMany(selector) {
|
|
526
|
+
async removeMany(selector) {
|
|
765
527
|
if (this.isDisposed)
|
|
766
528
|
throw new Error("Collection is disposed");
|
|
767
529
|
if (!selector)
|
|
768
530
|
throw new Error("Invalid selector");
|
|
769
|
-
const
|
|
770
|
-
|
|
771
|
-
const index = this.memory().findIndex((document) => document === item);
|
|
772
|
-
if (index === -1)
|
|
773
|
-
throw new Error("Cannot resolve index for item");
|
|
774
|
-
this.memory().splice(index, 1);
|
|
775
|
-
this.deleteFromIdIndex(item.id, index);
|
|
776
|
-
this.rebuildIndices();
|
|
777
|
-
});
|
|
778
|
-
items.forEach((item) => {
|
|
531
|
+
const removedItems = await this.withPushState(() => this.backend.removeMany(selector));
|
|
532
|
+
removedItems.forEach((item) => {
|
|
779
533
|
this.emit("removed", item);
|
|
780
534
|
});
|
|
781
535
|
this.emit("removeMany", selector);
|
|
782
536
|
this.executeInDebugMode((callstack) => this.emit("_debug.removeMany", callstack, selector));
|
|
783
|
-
return
|
|
537
|
+
return removedItems.length;
|
|
784
538
|
}
|
|
785
539
|
}
|
|
786
540
|
export {
|
|
787
|
-
default2 as createIndex,
|
|
788
541
|
Collection as default
|
|
789
542
|
};
|