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