@signaldb/core 1.7.1 → 2.0.0-beta.0
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 +125 -82
- package/dist/AsyncDataAdapter.d.ts +64 -0
- package/dist/AutoFetchDataAdapter.d.ts +113 -0
- package/dist/Collection/Cursor.d.ts +9 -9
- package/dist/Collection/Observer.d.ts +3 -2
- package/dist/Collection/index.d.ts +52 -46
- package/dist/Collection/types.d.ts +4 -9
- package/dist/DataAdapter.d.ts +33 -0
- package/dist/DefaultDataAdapter.d.ts +32 -0
- package/dist/WorkerDataAdapter.d.ts +22 -0
- package/dist/WorkerDataAdapterHost.d.ts +59 -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 +337 -3
- package/dist/index.cjs13.js +384 -110
- package/dist/index.cjs14.js +183 -67
- package/dist/index.cjs15.js +339 -8
- package/dist/index.cjs16.js +563 -20
- package/dist/index.cjs17.js +12 -4
- package/dist/index.cjs18.js +24 -5
- package/dist/index.cjs2.js +24 -30
- package/dist/index.cjs20.js +102 -13
- package/dist/index.cjs21.js +124 -21
- package/dist/index.cjs22.js +5 -77
- package/dist/index.cjs23.js +22 -79
- package/dist/index.cjs24.js +5 -16
- package/dist/index.cjs25.js +8 -27
- package/dist/index.cjs26.js +27 -7
- package/dist/index.cjs27.js +3 -5
- package/dist/index.cjs28.js +5 -27
- package/dist/index.cjs29.js +27 -40
- package/dist/index.cjs3.js +191 -441
- package/dist/index.cjs30.js +42 -0
- package/dist/index.cjs31.js +9 -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 +10 -8
- package/dist/index.mjs +15 -11
- package/dist/index10.mjs +15 -26
- package/dist/index11.mjs +13 -10
- package/dist/index12.mjs +337 -3
- package/dist/index13.mjs +384 -110
- package/dist/index14.mjs +183 -66
- package/dist/index15.mjs +339 -8
- package/dist/index16.mjs +563 -20
- package/dist/index17.mjs +12 -4
- package/dist/index18.mjs +24 -5
- package/dist/index2.mjs +24 -30
- package/dist/index20.mjs +102 -13
- package/dist/index21.mjs +123 -21
- package/dist/index22.mjs +5 -76
- package/dist/index23.mjs +22 -78
- package/dist/index24.mjs +5 -16
- package/dist/index25.mjs +8 -27
- package/dist/index26.mjs +27 -7
- package/dist/index27.mjs +3 -5
- package/dist/index28.mjs +5 -27
- package/dist/index29.mjs +27 -40
- package/dist/index3.mjs +191 -442
- package/dist/index30.mjs +43 -0
- package/dist/index31.mjs +10 -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/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,12 @@
|
|
|
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 serializeValue = require("./index.cjs20.js");
|
|
10
|
-
const createSignal = require("./index.cjs21.js");
|
|
11
9
|
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
10
|
class Collection extends EventEmitter {
|
|
37
11
|
static collections = [];
|
|
38
12
|
static debugMode = false;
|
|
@@ -68,210 +42,58 @@ class Collection extends EventEmitter {
|
|
|
68
42
|
collection.setFieldTracking(enable);
|
|
69
43
|
});
|
|
70
44
|
};
|
|
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
45
|
static batch(callback) {
|
|
79
46
|
Collection.batchOperationInProgress = true;
|
|
80
|
-
Collection.collections.reduce((memo, collection) => () =>
|
|
81
|
-
|
|
47
|
+
const execute = () => Collection.collections.reduce((memo, collection) => () => {
|
|
48
|
+
return collection.batch(memo);
|
|
49
|
+
}, callback)();
|
|
50
|
+
const maybePromise = execute();
|
|
51
|
+
const afterBatch = () => {
|
|
52
|
+
Collection.batchOperationInProgress = false;
|
|
53
|
+
};
|
|
54
|
+
if (maybePromise && typeof maybePromise.then === "function") {
|
|
55
|
+
return maybePromise.then(() => afterBatch());
|
|
56
|
+
} else {
|
|
57
|
+
afterBatch();
|
|
58
|
+
}
|
|
82
59
|
}
|
|
83
60
|
name;
|
|
61
|
+
backend;
|
|
84
62
|
options;
|
|
85
|
-
persistenceAdapter = null;
|
|
86
63
|
isPullingSignal;
|
|
87
64
|
isPushingSignal;
|
|
88
|
-
|
|
89
|
-
indicesOutdated = false;
|
|
90
|
-
idIndex = /* @__PURE__ */ new Map();
|
|
65
|
+
readySignal;
|
|
91
66
|
debugMode;
|
|
92
67
|
batchOperationInProgress = false;
|
|
93
68
|
isDisposed = false;
|
|
94
69
|
postBatchCallbacks = /* @__PURE__ */ new Set();
|
|
95
70
|
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) {
|
|
71
|
+
constructor(nameOrOptions, maybeDataAdapter, maybeOptions) {
|
|
114
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
|
+
});
|
|
115
79
|
Collection.collections.push(this);
|
|
116
|
-
this.name =
|
|
117
|
-
this.options = {
|
|
118
|
-
memory: [],
|
|
119
|
-
...options
|
|
120
|
-
};
|
|
80
|
+
this.name = name;
|
|
81
|
+
this.options = { ...options };
|
|
121
82
|
this.fieldTracking = this.options.fieldTracking ?? Collection.fieldTracking;
|
|
122
83
|
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);
|
|
84
|
+
this.isPullingSignal = createSignal(this.options.reactivity, false);
|
|
129
85
|
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);
|
|
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(() => {
|
|
272
91
|
});
|
|
273
92
|
Collection.onCreationCallbacks.forEach((callback) => callback(this));
|
|
274
93
|
}
|
|
94
|
+
isBatchOperationInProgress() {
|
|
95
|
+
return Collection.batchOperationInProgress || this.batchOperationInProgress;
|
|
96
|
+
}
|
|
275
97
|
/**
|
|
276
98
|
* Checks whether the collection is currently performing a pull operation
|
|
277
99
|
* ⚡️ this function is reactive!
|
|
@@ -336,17 +158,28 @@ class Collection extends EventEmitter {
|
|
|
336
158
|
*
|
|
337
159
|
* collection.insert({ name: 'Item 1' })
|
|
338
160
|
*/
|
|
339
|
-
async
|
|
340
|
-
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;
|
|
341
171
|
}
|
|
342
172
|
profile(fn, measureFunction) {
|
|
343
173
|
if (!this.debugMode)
|
|
344
174
|
return fn();
|
|
345
175
|
const startTime = performance.now();
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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);
|
|
350
183
|
}
|
|
351
184
|
executeInDebugMode(fn) {
|
|
352
185
|
if (!this.debugMode)
|
|
@@ -354,114 +187,58 @@ class Collection extends EventEmitter {
|
|
|
354
187
|
const callstack = new Error().stack || "";
|
|
355
188
|
fn(callstack);
|
|
356
189
|
}
|
|
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
190
|
transform(item) {
|
|
425
191
|
if (!this.options.transform)
|
|
426
192
|
return item;
|
|
427
193
|
return this.options.transform(item);
|
|
428
194
|
}
|
|
429
|
-
|
|
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);
|
|
430
206
|
return this.profile(() => {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
return items;
|
|
450
|
-
return items.filter(matchItems);
|
|
207
|
+
if (!options?.async)
|
|
208
|
+
return this.backend.getQueryResult(selector, options);
|
|
209
|
+
return new Promise((resolve, reject) => {
|
|
210
|
+
this.isPullingSignal.set(true);
|
|
211
|
+
const cleanup = this.backend.onQueryStateChange(selector, options, (state) => {
|
|
212
|
+
if (state === "error") {
|
|
213
|
+
cleanup();
|
|
214
|
+
reject(this.backend.getQueryError(selector, options) || new Error("Unknown error"));
|
|
215
|
+
} else if (state === "complete") {
|
|
216
|
+
cleanup();
|
|
217
|
+
resolve(this.backend.getQueryResult(selector, options) || []);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
this.backend.registerQuery(selector, options);
|
|
221
|
+
}).finally(() => {
|
|
222
|
+
this.isPullingSignal.set(false);
|
|
223
|
+
this.backend.unregisterQuery(selector, options);
|
|
224
|
+
});
|
|
451
225
|
}, (measuredTime) => this.executeInDebugMode((callstack) => this.emit("_debug.getItems", callstack, selector, measuredTime)));
|
|
452
226
|
}
|
|
227
|
+
async withPushState(asyncFunction) {
|
|
228
|
+
this.isPushingSignal.set(true);
|
|
229
|
+
try {
|
|
230
|
+
return await asyncFunction();
|
|
231
|
+
} finally {
|
|
232
|
+
this.isPushingSignal.set(false);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
453
235
|
/**
|
|
454
236
|
* Disposes the collection, unregisters persistence adapters, clears memory, and
|
|
455
237
|
* cleans up all resources used by the collection.
|
|
456
238
|
* @returns A promise that resolves when the collection is disposed.
|
|
457
239
|
*/
|
|
458
240
|
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 = [];
|
|
241
|
+
await this.backend.dispose();
|
|
465
242
|
this.isDisposed = true;
|
|
466
243
|
this.removeAllListeners();
|
|
467
244
|
Collection.collections = Collection.collections.filter((collection) => collection !== this);
|
|
@@ -475,12 +252,12 @@ class Collection extends EventEmitter {
|
|
|
475
252
|
* @param [options] - Options for the find operation, such as limit and sort.
|
|
476
253
|
* @returns A cursor to fetch and observe the matching items.
|
|
477
254
|
*/
|
|
478
|
-
find(selector, options) {
|
|
255
|
+
find(selector = {}, options) {
|
|
479
256
|
if (this.isDisposed)
|
|
480
257
|
throw new Error("Collection is disposed");
|
|
481
258
|
if (selector !== void 0 && (!selector || typeof selector !== "object"))
|
|
482
259
|
throw new Error("Invalid selector");
|
|
483
|
-
const cursor = new Cursor.default(() => this.getItems(selector), {
|
|
260
|
+
const cursor = new Cursor.default((() => this.getItems(selector, options || {})), {
|
|
484
261
|
reactive: this.options.reactivity,
|
|
485
262
|
fieldTracking: this.fieldTracking,
|
|
486
263
|
...options,
|
|
@@ -493,16 +270,16 @@ class Collection extends EventEmitter {
|
|
|
493
270
|
}
|
|
494
271
|
requery();
|
|
495
272
|
};
|
|
496
|
-
this.
|
|
497
|
-
this.
|
|
498
|
-
|
|
499
|
-
|
|
273
|
+
this.backend.registerQuery(selector, options);
|
|
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
|
-
this.
|
|
503
|
-
|
|
504
|
-
this.removeListener("changed", handleRequery);
|
|
505
|
-
this.removeListener("removed", handleRequery);
|
|
281
|
+
this.backend.unregisterQuery(selector, options);
|
|
282
|
+
queryStateChangeCleanup();
|
|
506
283
|
this.emit("observer.disposed", selector, options);
|
|
507
284
|
};
|
|
508
285
|
}
|
|
@@ -515,6 +292,7 @@ class Collection extends EventEmitter {
|
|
|
515
292
|
* Finds a single item in the collection based on a selector and optional options.
|
|
516
293
|
* ⚡️ this function is reactive!
|
|
517
294
|
* Returns the found item or undefined if no item matches.
|
|
295
|
+
* @template Async - Whether to perform the operation asynchronously.
|
|
518
296
|
* @template O - The options type for the find operation.
|
|
519
297
|
* @param selector - The criteria to select the item.
|
|
520
298
|
* @param [options] - Options for the find operation, such as projection.
|
|
@@ -527,23 +305,39 @@ class Collection extends EventEmitter {
|
|
|
527
305
|
limit: 1,
|
|
528
306
|
...options
|
|
529
307
|
});
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
308
|
+
const handleItems = (items) => {
|
|
309
|
+
const returnValue = items[0] || void 0;
|
|
310
|
+
this.emit("findOne", selector, options, returnValue);
|
|
311
|
+
this.executeInDebugMode((callstack) => this.emit("_debug.findOne", callstack, selector, options, returnValue));
|
|
312
|
+
return returnValue;
|
|
313
|
+
};
|
|
314
|
+
const maybePromise = cursor.fetch();
|
|
315
|
+
return maybePromise instanceof Promise ? maybePromise.then(handleItems) : handleItems(maybePromise);
|
|
534
316
|
}
|
|
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
317
|
batch(callback) {
|
|
318
|
+
if (this.batchOperationInProgress)
|
|
319
|
+
return callback();
|
|
541
320
|
this.batchOperationInProgress = true;
|
|
542
|
-
callback();
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
321
|
+
const maybePromise = callback();
|
|
322
|
+
const afterBatch = () => {
|
|
323
|
+
this.batchOperationInProgress = false;
|
|
324
|
+
this.postBatchCallbacks.forEach((callback_) => callback_());
|
|
325
|
+
this.postBatchCallbacks.clear();
|
|
326
|
+
};
|
|
327
|
+
if (maybePromise && typeof maybePromise.then === "function") {
|
|
328
|
+
return maybePromise.then(() => afterBatch());
|
|
329
|
+
} else {
|
|
330
|
+
afterBatch();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
onPostBatch(callback) {
|
|
334
|
+
if (this.isDisposed)
|
|
335
|
+
throw new Error("Collection is disposed");
|
|
336
|
+
if (this.batchOperationInProgress) {
|
|
337
|
+
this.postBatchCallbacks.add(callback);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
return callback();
|
|
547
341
|
}
|
|
548
342
|
/**
|
|
549
343
|
* Inserts a single item into the collection. Generates a unique ID if not provided.
|
|
@@ -551,20 +345,18 @@ class Collection extends EventEmitter {
|
|
|
551
345
|
* @returns The ID of the inserted item.
|
|
552
346
|
* @throws {Error} If the collection is disposed or the item has an invalid ID.
|
|
553
347
|
*/
|
|
554
|
-
insert(item) {
|
|
348
|
+
async insert(item) {
|
|
555
349
|
if (this.isDisposed)
|
|
556
350
|
throw new Error("Collection is disposed");
|
|
557
351
|
if (!item)
|
|
558
352
|
throw new Error("Invalid item");
|
|
559
353
|
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();
|
|
354
|
+
const itemWithId = {
|
|
355
|
+
id: primaryKeyGenerator(item),
|
|
356
|
+
...item
|
|
357
|
+
};
|
|
358
|
+
this.emit("validate", itemWithId);
|
|
359
|
+
const newItem = await this.withPushState(() => this.backend.insert(itemWithId));
|
|
568
360
|
this.emit("added", newItem);
|
|
569
361
|
this.emit("insert", newItem);
|
|
570
362
|
this.executeInDebugMode((callstack) => this.emit("_debug.insert", callstack, newItem));
|
|
@@ -576,7 +368,7 @@ class Collection extends EventEmitter {
|
|
|
576
368
|
* @returns An array of IDs of the inserted items.
|
|
577
369
|
* @throws {Error} If the collection is disposed or the items are invalid.
|
|
578
370
|
*/
|
|
579
|
-
insertMany(items) {
|
|
371
|
+
async insertMany(items) {
|
|
580
372
|
if (this.isDisposed)
|
|
581
373
|
throw new Error("Collection is disposed");
|
|
582
374
|
if (!items)
|
|
@@ -585,10 +377,10 @@ class Collection extends EventEmitter {
|
|
|
585
377
|
return [];
|
|
586
378
|
}
|
|
587
379
|
const ids = [];
|
|
588
|
-
this.batch(() => {
|
|
589
|
-
items.
|
|
590
|
-
ids.push(this.insert(item));
|
|
591
|
-
});
|
|
380
|
+
await this.batch(async () => {
|
|
381
|
+
await Promise.all(items.map(async (item) => {
|
|
382
|
+
ids.push(await this.insert(item));
|
|
383
|
+
}));
|
|
592
384
|
});
|
|
593
385
|
return ids;
|
|
594
386
|
}
|
|
@@ -601,7 +393,7 @@ class Collection extends EventEmitter {
|
|
|
601
393
|
* @returns The number of items updated (0 or 1).
|
|
602
394
|
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
603
395
|
*/
|
|
604
|
-
updateOne(selector, modifier, options) {
|
|
396
|
+
async updateOne(selector, modifier, options) {
|
|
605
397
|
if (this.isDisposed)
|
|
606
398
|
throw new Error("Collection is disposed");
|
|
607
399
|
if (!selector)
|
|
@@ -609,7 +401,7 @@ class Collection extends EventEmitter {
|
|
|
609
401
|
if (!modifier)
|
|
610
402
|
throw new Error("Invalid modifier");
|
|
611
403
|
const { $setOnInsert, ...restModifier } = modifier;
|
|
612
|
-
const
|
|
404
|
+
const item = await this.getItem(selector, { async: true });
|
|
613
405
|
if (item == null) {
|
|
614
406
|
if (options?.upsert) {
|
|
615
407
|
const newItem = modify({}, {
|
|
@@ -619,26 +411,18 @@ class Collection extends EventEmitter {
|
|
|
619
411
|
...restModifier.$set
|
|
620
412
|
}
|
|
621
413
|
});
|
|
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");
|
|
414
|
+
await this.insert(newItem);
|
|
415
|
+
return 1;
|
|
631
416
|
}
|
|
632
|
-
|
|
633
|
-
this.memory().splice(index, 1, modifiedItem);
|
|
634
|
-
this.rebuildIndices();
|
|
635
|
-
this.emit("changed", modifiedItem, restModifier);
|
|
417
|
+
return 0;
|
|
636
418
|
}
|
|
419
|
+
const modifiedItem = modify(deepClone.default(item), restModifier);
|
|
420
|
+
this.emit("validate", modifiedItem);
|
|
421
|
+
const changes = await this.withPushState(() => this.backend.updateOne(selector, modifier));
|
|
422
|
+
this.emit("changed", modifiedItem, restModifier);
|
|
637
423
|
this.emit("updateOne", selector, modifier);
|
|
638
424
|
this.executeInDebugMode((callstack) => this.emit("_debug.updateOne", callstack, selector, modifier));
|
|
639
|
-
|
|
640
|
-
return 0;
|
|
641
|
-
return 1;
|
|
425
|
+
return changes.length;
|
|
642
426
|
}
|
|
643
427
|
/**
|
|
644
428
|
* Updates multiple items in the collection that match the given selector.
|
|
@@ -649,7 +433,7 @@ class Collection extends EventEmitter {
|
|
|
649
433
|
* @returns The number of items updated.
|
|
650
434
|
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
651
435
|
*/
|
|
652
|
-
updateMany(selector, modifier, options) {
|
|
436
|
+
async updateMany(selector, modifier, options) {
|
|
653
437
|
if (this.isDisposed)
|
|
654
438
|
throw new Error("Collection is disposed");
|
|
655
439
|
if (!selector)
|
|
@@ -657,44 +441,32 @@ class Collection extends EventEmitter {
|
|
|
657
441
|
if (!modifier)
|
|
658
442
|
throw new Error("Invalid modifier");
|
|
659
443
|
const { $setOnInsert, ...restModifier } = modifier;
|
|
660
|
-
const items = this.getItems(selector);
|
|
661
|
-
if (items.length === 0
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
444
|
+
const items = await this.getItems(selector, { async: true });
|
|
445
|
+
if (items.length === 0) {
|
|
446
|
+
if (options?.upsert) {
|
|
447
|
+
const newItem = modify({}, {
|
|
448
|
+
...restModifier,
|
|
449
|
+
$set: {
|
|
450
|
+
...$setOnInsert,
|
|
451
|
+
...restModifier.$set
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
await this.insert(newItem);
|
|
455
|
+
return 1;
|
|
671
456
|
}
|
|
672
|
-
|
|
457
|
+
return 0;
|
|
673
458
|
}
|
|
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}'`);
|
|
459
|
+
items.forEach((item) => {
|
|
678
460
|
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
461
|
this.emit("validate", modifiedItem);
|
|
683
|
-
return {
|
|
684
|
-
item: modifiedItem,
|
|
685
|
-
index
|
|
686
|
-
};
|
|
687
|
-
});
|
|
688
|
-
changes.forEach(({ item, index }) => {
|
|
689
|
-
this.memory().splice(index, 1, item);
|
|
690
462
|
});
|
|
691
|
-
this.
|
|
692
|
-
changes.forEach((
|
|
463
|
+
const changes = await this.withPushState(() => this.backend.updateMany(selector, modifier));
|
|
464
|
+
changes.forEach((item) => {
|
|
693
465
|
this.emit("changed", item, restModifier);
|
|
694
466
|
});
|
|
695
467
|
this.emit("updateMany", selector, modifier);
|
|
696
468
|
this.executeInDebugMode((callstack) => this.emit("_debug.updateMany", callstack, selector, modifier));
|
|
697
|
-
return changes.length
|
|
469
|
+
return changes.length;
|
|
698
470
|
}
|
|
699
471
|
/**
|
|
700
472
|
* Replaces a single item in the collection that matches the given selector.
|
|
@@ -705,34 +477,26 @@ class Collection extends EventEmitter {
|
|
|
705
477
|
* @returns The number of items replaced (0 or 1).
|
|
706
478
|
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
707
479
|
*/
|
|
708
|
-
replaceOne(selector, replacement, options) {
|
|
480
|
+
async replaceOne(selector, replacement, options) {
|
|
709
481
|
if (this.isDisposed)
|
|
710
482
|
throw new Error("Collection is disposed");
|
|
711
483
|
if (!selector)
|
|
712
484
|
throw new Error("Invalid selector");
|
|
713
|
-
const
|
|
485
|
+
const item = await this.getItem(selector, { async: true });
|
|
714
486
|
if (item == null) {
|
|
715
487
|
if (options?.upsert) {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
}
|
|
719
|
-
this.insert(replacement);
|
|
720
|
-
}
|
|
721
|
-
} else {
|
|
722
|
-
if (item.id !== replacement.id && this.getItemAndIndex({ id: replacement.id }).item != null) {
|
|
723
|
-
throw new Error("Item with same id already exists");
|
|
488
|
+
await this.insert(replacement);
|
|
489
|
+
return 1;
|
|
724
490
|
}
|
|
725
|
-
|
|
726
|
-
this.emit("validate", modifiedItem);
|
|
727
|
-
this.memory().splice(index, 1, modifiedItem);
|
|
728
|
-
this.rebuildIndices();
|
|
729
|
-
this.emit("changed", modifiedItem, replacement);
|
|
491
|
+
return 0;
|
|
730
492
|
}
|
|
493
|
+
const modifiedItem = { id: item.id, ...replacement };
|
|
494
|
+
this.emit("validate", modifiedItem);
|
|
495
|
+
const changes = await this.withPushState(() => this.backend.replaceOne(selector, replacement));
|
|
496
|
+
this.emit("changed", modifiedItem, replacement);
|
|
731
497
|
this.emit("replaceOne", selector, replacement);
|
|
732
498
|
this.executeInDebugMode((callstack) => this.emit("_debug.replaceOne", callstack, selector, replacement));
|
|
733
|
-
|
|
734
|
-
return 0;
|
|
735
|
-
return 1;
|
|
499
|
+
return changes.length;
|
|
736
500
|
}
|
|
737
501
|
/**
|
|
738
502
|
* Removes a single item from the collection that matches the given selector.
|
|
@@ -740,21 +504,16 @@ class Collection extends EventEmitter {
|
|
|
740
504
|
* @returns The number of items removed (0 or 1).
|
|
741
505
|
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
742
506
|
*/
|
|
743
|
-
removeOne(selector) {
|
|
507
|
+
async removeOne(selector) {
|
|
744
508
|
if (this.isDisposed)
|
|
745
509
|
throw new Error("Collection is disposed");
|
|
746
510
|
if (!selector)
|
|
747
511
|
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
|
-
}
|
|
512
|
+
const removedItems = await this.withPushState(() => this.backend.removeOne(selector));
|
|
513
|
+
this.emit("removed", removedItems[0]);
|
|
755
514
|
this.emit("removeOne", selector);
|
|
756
515
|
this.executeInDebugMode((callstack) => this.emit("_debug.removeOne", callstack, selector));
|
|
757
|
-
return
|
|
516
|
+
return removedItems.length;
|
|
758
517
|
}
|
|
759
518
|
/**
|
|
760
519
|
* Removes multiple items from the collection that match the given selector.
|
|
@@ -762,27 +521,18 @@ class Collection extends EventEmitter {
|
|
|
762
521
|
* @returns The number of items removed.
|
|
763
522
|
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
764
523
|
*/
|
|
765
|
-
removeMany(selector) {
|
|
524
|
+
async removeMany(selector) {
|
|
766
525
|
if (this.isDisposed)
|
|
767
526
|
throw new Error("Collection is disposed");
|
|
768
527
|
if (!selector)
|
|
769
528
|
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) => {
|
|
529
|
+
const removedItems = await this.withPushState(() => this.backend.removeMany(selector));
|
|
530
|
+
removedItems.forEach((item) => {
|
|
780
531
|
this.emit("removed", item);
|
|
781
532
|
});
|
|
782
533
|
this.emit("removeMany", selector);
|
|
783
534
|
this.executeInDebugMode((callstack) => this.emit("_debug.removeMany", callstack, selector));
|
|
784
|
-
return
|
|
535
|
+
return removedItems.length;
|
|
785
536
|
}
|
|
786
537
|
}
|
|
787
|
-
exports.createIndex = createIndex.default;
|
|
788
538
|
exports.default = Collection;
|