@signaldb/core 2.0.0-beta.18 → 2.0.0-beta.19
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 +39 -17
- package/dist/index.cjs.js +9 -9
- package/dist/index.mjs +9 -9
- package/dist/index17.cjs.js +7 -2
- package/dist/index17.mjs +7 -2
- package/dist/index27.cjs.js +36 -337
- package/dist/index27.mjs +36 -337
- package/dist/index28.cjs.js +318 -573
- package/dist/index28.mjs +318 -573
- package/dist/index29.cjs.js +599 -8
- package/dist/index29.mjs +599 -8
- package/dist/index30.cjs.js +6 -6
- package/dist/index30.mjs +6 -6
- package/dist/index31.cjs.js +7 -86
- package/dist/index31.mjs +7 -85
- package/dist/index32.cjs.js +76 -465
- package/dist/index32.mjs +75 -465
- package/dist/index33.cjs.js +45 -64
- package/dist/index33.mjs +45 -64
- package/dist/index34.cjs.js +403 -530
- package/dist/index34.mjs +405 -532
- package/dist/index35.cjs.js +68 -17
- package/dist/index35.mjs +68 -17
- package/dist/index36.cjs.js +535 -344
- package/dist/index36.mjs +537 -346
- package/dist/index37.cjs.js +14 -532
- package/dist/index37.mjs +14 -532
- package/dist/index38.cjs.js +363 -0
- package/dist/index38.mjs +363 -0
- package/dist/index39.cjs.js +513 -0
- package/dist/index39.mjs +513 -0
- package/dist/types/StorageAdapter.d.ts +9 -1
- package/dist/utils/idIndexQuery.d.ts +20 -0
- package/dist/utils/storageIndexQuery.d.ts +20 -0
- package/package.json +1 -1
package/dist/index28.mjs
CHANGED
|
@@ -1,602 +1,347 @@
|
|
|
1
|
-
import
|
|
1
|
+
import isEqual from "./index2.mjs";
|
|
2
|
+
import { callWithDelta, diffQueryResults, isEmptyQueryDelta } from "./index4.mjs";
|
|
2
3
|
import EventEmitter from "./index7.mjs";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import "./
|
|
4
|
+
import serializeValue from "./index13.mjs";
|
|
5
|
+
import createIndex from "./index15.mjs";
|
|
6
|
+
import getIndexInfo from "./index17.mjs";
|
|
6
7
|
import deepClone from "./index18.mjs";
|
|
8
|
+
import match from "./index19.mjs";
|
|
7
9
|
import modify from "./index20.mjs";
|
|
10
|
+
import projectItems from "./index23.mjs";
|
|
11
|
+
import sortItems from "./index24.mjs";
|
|
12
|
+
import incrementalQueryUpdate from "./index25.mjs";
|
|
8
13
|
import queryId from "./index26.mjs";
|
|
9
|
-
import
|
|
10
|
-
//#region src/
|
|
14
|
+
import idIndexQuery from "./index27.mjs";
|
|
15
|
+
//#region src/DefaultDataAdapter.ts
|
|
11
16
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* @
|
|
16
|
-
* @template I - The type of the unique identifier for the items.
|
|
17
|
-
* @template U - The transformed item type after applying transformations (default is T).
|
|
17
|
+
* Checks if there are any pending updates in the given changeset.
|
|
18
|
+
* @template T - The type of the items in the changeset.
|
|
19
|
+
* @param pendingUpdates - The changeset to check for pending updates.
|
|
20
|
+
* @returns `true` if there are pending updates, otherwise `false`.
|
|
18
21
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
collection.setDebugMode(true);
|
|
61
|
-
});
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Enables field tracking for all collections.
|
|
65
|
-
* @param enable - A boolean indicating whether to enable field tracking.
|
|
66
|
-
*/
|
|
67
|
-
static setFieldTracking = (enable) => {
|
|
68
|
-
Collection.fieldTracking = enable;
|
|
69
|
-
Collection.collections.forEach((collection) => {
|
|
70
|
-
collection.setFieldTracking(enable);
|
|
22
|
+
function hasPendingUpdates(pendingUpdates) {
|
|
23
|
+
return pendingUpdates.added.length > 0 || pendingUpdates.modified.length > 0 || pendingUpdates.removed.length > 0;
|
|
24
|
+
}
|
|
25
|
+
var DefaultDataAdapter = class {
|
|
26
|
+
items = /* @__PURE__ */ new Map();
|
|
27
|
+
options;
|
|
28
|
+
storageAdapters = /* @__PURE__ */ new Map();
|
|
29
|
+
collections = /* @__PURE__ */ new Set();
|
|
30
|
+
indices = /* @__PURE__ */ new Map();
|
|
31
|
+
activeQueries = /* @__PURE__ */ new Map();
|
|
32
|
+
queryEmitters = /* @__PURE__ */ new Map();
|
|
33
|
+
queuedQueryUpdates = /* @__PURE__ */ new Map();
|
|
34
|
+
cachedQueryResults = /* @__PURE__ */ new Map();
|
|
35
|
+
constructor(options) {
|
|
36
|
+
this.options = options || {};
|
|
37
|
+
}
|
|
38
|
+
ensureStorageAdapter(name) {
|
|
39
|
+
if (this.storageAdapters.get(name)) return;
|
|
40
|
+
if (!this.options.storage) return;
|
|
41
|
+
const adapter = this.options.storage(name);
|
|
42
|
+
if (!adapter) return;
|
|
43
|
+
this.storageAdapters.set(name, adapter);
|
|
44
|
+
}
|
|
45
|
+
rebuildIndices(collection) {
|
|
46
|
+
const items = this.items.get(collection.name);
|
|
47
|
+
if (!items) throw new Error(`Items not found for collection ${collection.name}`);
|
|
48
|
+
const indices = this.indices.get(collection.name);
|
|
49
|
+
if (!indices) throw new Error(`Indices not found for collection ${collection.name}`);
|
|
50
|
+
indices.forEach((index) => index.rebuild([...items.values()]));
|
|
51
|
+
}
|
|
52
|
+
async setupStorageAdapter(collection) {
|
|
53
|
+
const storageAdapter = this.storageAdapters.get(collection.name);
|
|
54
|
+
if (!storageAdapter) return;
|
|
55
|
+
return storageAdapter.setup().then(async () => {
|
|
56
|
+
await this.fetchItemsFromStorage(collection);
|
|
57
|
+
}).catch((error) => {
|
|
58
|
+
if (!this.options.onError) {
|
|
59
|
+
console.error(`Error during data persistence operation in collection ${collection.name}`, error);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.options.onError(collection.name, error instanceof Error ? error : new Error(error));
|
|
71
63
|
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
64
|
+
}
|
|
65
|
+
getIndexInfo(collection, selector) {
|
|
66
|
+
if (selector != null && Object.keys(selector).length === 1 && "id" in selector) {
|
|
67
|
+
const idResult = idIndexQuery(selector);
|
|
68
|
+
if (idResult.matched) return {
|
|
69
|
+
matched: true,
|
|
70
|
+
ids: idResult.ids.map((id) => serializeValue(id)),
|
|
71
|
+
optimizedSelector: {}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (selector == null) return {
|
|
75
|
+
matched: false,
|
|
76
|
+
ids: [],
|
|
77
|
+
optimizedSelector: {}
|
|
84
78
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
79
|
+
return getIndexInfo((this.indices.get(collection.name) ?? []).map((i) => i.query.bind(i)), selector);
|
|
80
|
+
}
|
|
81
|
+
applyIndexDeltas(collection, changes) {
|
|
82
|
+
const indices = this.indices.get(collection.name) ?? [];
|
|
83
|
+
for (const index of indices) {
|
|
84
|
+
if (changes.modified) index.update(changes.modified);
|
|
85
|
+
if (changes.added && changes.added.length > 0) index.insert(changes.added);
|
|
86
|
+
if (changes.removed && changes.removed.length > 0) index.remove(changes.removed);
|
|
91
87
|
}
|
|
92
|
-
if (maybePromise && typeof maybePromise.then === "function") return maybePromise.then(() => afterBatch(), (error) => {
|
|
93
|
-
afterBatch();
|
|
94
|
-
throw error;
|
|
95
|
-
});
|
|
96
|
-
else afterBatch();
|
|
97
|
-
}
|
|
98
|
-
name;
|
|
99
|
-
backend;
|
|
100
|
-
options;
|
|
101
|
-
isPullingSignal;
|
|
102
|
-
isPushingSignal;
|
|
103
|
-
readySignal;
|
|
104
|
-
debugMode;
|
|
105
|
-
batchOperationInProgress = false;
|
|
106
|
-
isDisposed = false;
|
|
107
|
-
postBatchCallbacks = /* @__PURE__ */ new Set();
|
|
108
|
-
fieldTracking = false;
|
|
109
|
-
queryListenersMap = /* @__PURE__ */ new Map();
|
|
110
|
-
settledQueriesSet = /* @__PURE__ */ new Set();
|
|
111
|
-
constructor(nameOrOptions, maybeDataAdapter, maybeOptions) {
|
|
112
|
-
super();
|
|
113
|
-
const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions?.name || `${this.constructor.name}-${randomId()}`;
|
|
114
|
-
const options = typeof nameOrOptions === "string" ? maybeOptions || {} : nameOrOptions || {};
|
|
115
|
-
const persistence = options.persistence;
|
|
116
|
-
const dataAdapter = maybeDataAdapter || new DefaultDataAdapter({ ...persistence ? { storage: () => persistence } : {} });
|
|
117
|
-
Collection.collections.push(this);
|
|
118
|
-
this.name = name;
|
|
119
|
-
this.options = { ...options };
|
|
120
|
-
this.fieldTracking = this.options.fieldTracking ?? Collection.fieldTracking;
|
|
121
|
-
this.debugMode = this.options.enableDebugMode ?? Collection.debugMode;
|
|
122
|
-
this.isPullingSignal = createSignal(this.options.reactivity, false);
|
|
123
|
-
this.isPushingSignal = createSignal(this.options.reactivity, false);
|
|
124
|
-
this.readySignal = createSignal(this.options.reactivity, false);
|
|
125
|
-
this.backend = dataAdapter.createCollectionBackend(this, this.options.indices ?? []);
|
|
126
|
-
this.backend.isReady().then(() => {
|
|
127
|
-
this.readySignal.set(true);
|
|
128
|
-
}).catch(() => {});
|
|
129
|
-
Collection.onCreationCallbacks.forEach((callback) => callback(this));
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Reports a live query the first time its result is found to be larger than
|
|
133
|
-
* the configured threshold. Once per query, because it re-runs on every
|
|
134
|
-
* write and a warning per write would be its own performance problem.
|
|
135
|
-
* @param selector - The query's selector.
|
|
136
|
-
* @param options - The query's options.
|
|
137
|
-
* @param registrationStack - Where the query was registered, if captured.
|
|
138
|
-
*/
|
|
139
|
-
reportIfLargeQuery(selector, options, registrationStack) {
|
|
140
|
-
const threshold = Collection.largeQueryWarningThreshold;
|
|
141
|
-
if (threshold == null) return;
|
|
142
|
-
const id = `${this.name}:${queryId(selector, options)}`;
|
|
143
|
-
if (Collection.reportedLargeQueries.has(id)) return;
|
|
144
|
-
const rows = this.backend.getQueryResult(selector, options || {}).length;
|
|
145
|
-
if (rows <= threshold) return;
|
|
146
|
-
Collection.reportedLargeQueries.add(id);
|
|
147
|
-
const keys = selector && typeof selector === "object" ? Object.keys(selector) : [];
|
|
148
|
-
console.warn(`[SignalDB] Live query on "${this.name}" holds ${rows} rows with selector {${keys.join(", ")}}. It is re-evaluated on every write to this collection, for as long as it stays registered. ${registrationStack ?? ""}`);
|
|
149
|
-
}
|
|
150
|
-
isBatchOperationInProgress() {
|
|
151
|
-
return Collection.batchOperationInProgress || this.batchOperationInProgress;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Checks whether the collection is currently performing a pull operation
|
|
155
|
-
* ⚡️ this function is reactive!
|
|
156
|
-
* (loading data from the persistence adapter).
|
|
157
|
-
* @returns A boolean indicating if the collection is in the process of pulling data.
|
|
158
|
-
*/
|
|
159
|
-
isPulling() {
|
|
160
|
-
return this.isPullingSignal.get() ?? false;
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Checks whether the collection is currently performing a push operation
|
|
164
|
-
* ⚡️ this function is reactive!
|
|
165
|
-
* (saving data to the persistence adapter).
|
|
166
|
-
* @returns A boolean indicating if the collection is in the process of pushing data.
|
|
167
|
-
*/
|
|
168
|
-
isPushing() {
|
|
169
|
-
return this.isPushingSignal.get() ?? false;
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Checks whether the collection is currently performing either a pull or push operation,
|
|
173
|
-
* ⚡️ this function is reactive!
|
|
174
|
-
* indicating that it is loading or saving data.
|
|
175
|
-
* @returns A boolean indicating if the collection is in the process of loading or saving data.
|
|
176
|
-
*/
|
|
177
|
-
isLoading() {
|
|
178
|
-
const isPulling = this.isPulling();
|
|
179
|
-
const isPushing = this.isPushing();
|
|
180
|
-
return isPulling || isPushing;
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Retrieves the current debug mode status of the collection.
|
|
184
|
-
* @returns A boolean indicating whether debug mode is enabled for the collection.
|
|
185
|
-
*/
|
|
186
|
-
getDebugMode() {
|
|
187
|
-
return this.debugMode;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Enables or disables debug mode for the collection.
|
|
191
|
-
* When debug mode is enabled, additional debugging information and events are emitted.
|
|
192
|
-
* @param enable - A boolean indicating whether to enable (`true`) or disable (`false`) debug mode.
|
|
193
|
-
*/
|
|
194
|
-
setDebugMode(enable) {
|
|
195
|
-
this.debugMode = enable;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Enables or disables field tracking for the collection.
|
|
199
|
-
* @param enable - A boolean indicating whether to enable (`true`) or disable (`false`) field tracking.
|
|
200
|
-
*/
|
|
201
|
-
setFieldTracking(enable) {
|
|
202
|
-
this.fieldTracking = enable;
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Resolves when the persistence adapter finished initializing
|
|
206
|
-
* and the collection is ready to be used.
|
|
207
|
-
* @returns A promise that resolves when the collection is ready.
|
|
208
|
-
* @example
|
|
209
|
-
* ```ts
|
|
210
|
-
* const collection = new Collection({
|
|
211
|
-
* persistence: // ...
|
|
212
|
-
* })
|
|
213
|
-
* await collection.isReady()
|
|
214
|
-
*
|
|
215
|
-
* collection.insert({ name: 'Item 1' })
|
|
216
|
-
*/
|
|
217
|
-
async ready() {
|
|
218
|
-
return this.backend.isReady();
|
|
219
88
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const handleProfileEnd = (result) => {
|
|
232
|
-
measureFunction(performance.now() - startTime);
|
|
233
|
-
return result;
|
|
89
|
+
getItem(collection, selector) {
|
|
90
|
+
const memory = this.items.get(collection.name) ?? /* @__PURE__ */ new Map();
|
|
91
|
+
const indexInfo = this.getIndexInfo(collection, selector);
|
|
92
|
+
return (indexInfo.matched ? indexInfo.ids.map((id) => memory.get(serializeValue(id))).filter((i) => i != null) : [...memory.values()]).find((document) => match(document, selector));
|
|
93
|
+
}
|
|
94
|
+
queryItems(collection, selector) {
|
|
95
|
+
const indexInfo = this.getIndexInfo(collection, selector);
|
|
96
|
+
const matchItems = (item) => {
|
|
97
|
+
if (indexInfo.optimizedSelector == null) return true;
|
|
98
|
+
if (Object.keys(indexInfo.optimizedSelector).length <= 0) return true;
|
|
99
|
+
return match(item, indexInfo.optimizedSelector);
|
|
234
100
|
};
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
101
|
+
const items = this.items.get(collection.name);
|
|
102
|
+
if (!indexInfo.matched) {
|
|
103
|
+
if (isEqual(selector, {})) return [...items.values()];
|
|
104
|
+
return [...items.values()].filter(matchItems);
|
|
105
|
+
}
|
|
106
|
+
const foundItems = indexInfo.ids.map((ids) => items.get(serializeValue(ids))).filter((i) => i != null);
|
|
107
|
+
if (isEqual(indexInfo.optimizedSelector, {})) return foundItems;
|
|
108
|
+
return foundItems.filter(matchItems);
|
|
109
|
+
}
|
|
110
|
+
executeQuery(collection, selector, options) {
|
|
111
|
+
const items = this.queryItems(collection, selector || {});
|
|
112
|
+
const { sort, skip, limit, fields } = options || {};
|
|
113
|
+
const sorted = sort ? sortItems(items, sort) : items;
|
|
114
|
+
const skipped = skip ? sorted.slice(skip) : sorted;
|
|
115
|
+
return projectItems(limit ? skipped.slice(0, limit) : skipped, fields);
|
|
116
|
+
}
|
|
117
|
+
flushQueuedQueryUpdates(collection) {
|
|
118
|
+
if (!this.queuedQueryUpdates.get(collection.name)) return;
|
|
119
|
+
const changes = this.queuedQueryUpdates.get(collection.name);
|
|
120
|
+
if (!changes || !hasPendingUpdates(changes)) return;
|
|
121
|
+
this.queuedQueryUpdates.set(collection.name, {
|
|
122
|
+
added: [],
|
|
123
|
+
modified: [],
|
|
124
|
+
removed: []
|
|
254
125
|
});
|
|
255
|
-
|
|
256
|
-
|
|
126
|
+
const changeset = {
|
|
127
|
+
upserts: [...changes.added, ...changes.modified],
|
|
128
|
+
deletes: changes.removed.map((item) => item.id)
|
|
129
|
+
};
|
|
130
|
+
const flatItems = [
|
|
131
|
+
...changes.added,
|
|
132
|
+
...changes.modified,
|
|
133
|
+
...changes.removed
|
|
134
|
+
];
|
|
135
|
+
const itemIds = new Set(flatItems.map((i) => i.id));
|
|
136
|
+
[...this.activeQueries.get(collection.name)?.values() ?? []].filter(({ selector, options }) => {
|
|
137
|
+
if ((this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options))?.map((i) => i.id) ?? []).some((id) => itemIds.has(id))) return true;
|
|
138
|
+
return flatItems.some((item) => match(item, selector));
|
|
139
|
+
}).forEach(({ selector, options }) => {
|
|
140
|
+
this.executeAndCacheQuery(collection, selector, options, changeset);
|
|
257
141
|
});
|
|
258
|
-
return itemsOrPromise[0];
|
|
259
|
-
}
|
|
260
|
-
getItems(selector, options) {
|
|
261
|
-
this.emit("getItems", selector);
|
|
262
|
-
return this.profile(() => {
|
|
263
|
-
if (!options?.async) return this.backend.getQueryResult(selector, options);
|
|
264
|
-
this.isPullingSignal.set(true);
|
|
265
|
-
return this.backend.executeQuery(selector, options).finally(() => {
|
|
266
|
-
this.isPullingSignal.set(false);
|
|
267
|
-
});
|
|
268
|
-
}, (measuredTime) => this.executeInDebugMode((callstack) => this.emit("_debug.getItems", callstack, selector, measuredTime)));
|
|
269
|
-
}
|
|
270
|
-
async withPushState(asyncFunction) {
|
|
271
|
-
this.isPushingSignal.set(true);
|
|
272
|
-
try {
|
|
273
|
-
return await asyncFunction();
|
|
274
|
-
} finally {
|
|
275
|
-
this.isPushingSignal.set(false);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
queryListeners(query, listeners) {
|
|
279
|
-
const id = queryId(query.selector, query.options);
|
|
280
|
-
if (listeners != null) return this.queryListenersMap.set(id, listeners);
|
|
281
|
-
return this.queryListenersMap.get(id) ?? 0;
|
|
282
142
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
143
|
+
executeAndCacheQuery(collection, selector, options, changes) {
|
|
144
|
+
const cached = this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options));
|
|
145
|
+
const result = (changes && cached ? incrementalQueryUpdate(cached, selector, options, changes) : null) ?? this.executeQuery(collection, selector, options);
|
|
146
|
+
const delta = cached ? diffQueryResults(cached, result) : void 0;
|
|
147
|
+
this.cachedQueryResults.set(collection.name, this.cachedQueryResults.get(collection.name) || /* @__PURE__ */ new Map());
|
|
148
|
+
this.cachedQueryResults.get(collection.name)?.set(queryId(selector, options), result);
|
|
149
|
+
const emitter = this.queryEmitters.get(collection.name);
|
|
150
|
+
if (!emitter) return;
|
|
151
|
+
if (delta && isEmptyQueryDelta(delta)) return;
|
|
152
|
+
emitter.emit("change", selector, options, "complete", delta);
|
|
153
|
+
}
|
|
154
|
+
updateQueries(collection, changes) {
|
|
155
|
+
this.queuedQueryUpdates.set(collection.name, this.queuedQueryUpdates.get(collection.name) || {
|
|
156
|
+
added: [],
|
|
157
|
+
modified: [],
|
|
158
|
+
removed: []
|
|
159
|
+
});
|
|
160
|
+
this.queuedQueryUpdates.get(collection.name)?.added.push(...changes.added);
|
|
161
|
+
this.queuedQueryUpdates.get(collection.name)?.modified.push(...changes.modified);
|
|
162
|
+
this.queuedQueryUpdates.get(collection.name)?.removed.push(...changes.removed);
|
|
163
|
+
this.flushQueuedQueryUpdates(collection);
|
|
164
|
+
}
|
|
165
|
+
createCollectionBackend(collection, indices) {
|
|
166
|
+
this.collections.add(collection);
|
|
167
|
+
this.ensureStorageAdapter(collection.name);
|
|
168
|
+
this.items.set(collection.name, this.items.get(collection.name) ?? /* @__PURE__ */ new Map());
|
|
169
|
+
this.queryEmitters.set(collection.name, this.queryEmitters.get(collection.name) ?? new EventEmitter());
|
|
170
|
+
this.queryEmitters.get(collection.name)?.setMaxListeners(Infinity);
|
|
171
|
+
this.activeQueries.set(collection.name, this.activeQueries.get(collection.name) || /* @__PURE__ */ new Map());
|
|
172
|
+
this.indices.set(collection.name, indices.map((field) => createIndex(field)));
|
|
173
|
+
this.rebuildIndices(collection);
|
|
174
|
+
const persistenceReadyPromise = this.setupStorageAdapter(collection);
|
|
175
|
+
const backend = {
|
|
176
|
+
insert: async (newItem) => {
|
|
177
|
+
const items = this.items.get(collection.name);
|
|
178
|
+
if (!items) throw new Error(`Items not found for collection ${collection.name}`);
|
|
179
|
+
if (items.has(serializeValue(newItem.id))) throw new Error(`Item with id '${newItem.id}' already exists`);
|
|
180
|
+
this.items.get(collection.name)?.set(serializeValue(newItem.id), newItem);
|
|
181
|
+
await this.storageAdapters.get(collection.name)?.insert([newItem]);
|
|
182
|
+
this.applyIndexDeltas(collection, { added: [newItem] });
|
|
183
|
+
this.updateQueries(collection, {
|
|
184
|
+
added: [],
|
|
185
|
+
modified: [newItem],
|
|
186
|
+
removed: []
|
|
187
|
+
});
|
|
188
|
+
return newItem;
|
|
189
|
+
},
|
|
190
|
+
updateOne: async (selector, modifier) => {
|
|
191
|
+
const { $setOnInsert, ...restModifier } = modifier;
|
|
192
|
+
const item = this.getItem(collection, selector);
|
|
193
|
+
if (item == null) return [];
|
|
194
|
+
const modifiedItem = modify(deepClone(item), restModifier);
|
|
195
|
+
if (item.id !== modifiedItem.id && this.getItem(collection, { id: modifiedItem.id }) != null) throw new Error(`Item with id '${modifiedItem.id}' already exists`);
|
|
196
|
+
this.items.get(collection.name)?.set(serializeValue(modifiedItem.id), modifiedItem);
|
|
197
|
+
await this.storageAdapters.get(collection.name)?.replace([modifiedItem]);
|
|
198
|
+
this.applyIndexDeltas(collection, { modified: [{
|
|
199
|
+
oldItem: item,
|
|
200
|
+
newItem: modifiedItem
|
|
201
|
+
}] });
|
|
202
|
+
this.updateQueries(collection, {
|
|
203
|
+
added: [],
|
|
204
|
+
modified: [modifiedItem],
|
|
205
|
+
removed: []
|
|
206
|
+
});
|
|
207
|
+
return [modifiedItem];
|
|
208
|
+
},
|
|
209
|
+
updateMany: async (selector, modifier) => {
|
|
210
|
+
const { $setOnInsert, ...restModifier } = modifier;
|
|
211
|
+
const items = this.executeQuery(collection, selector, {});
|
|
212
|
+
const changedItems = items.map((item) => {
|
|
213
|
+
const modifiedItem = modify(deepClone(item), restModifier);
|
|
214
|
+
if (item.id !== modifiedItem.id && this.getItem(collection, { id: modifiedItem.id }) != null) throw new Error(`Item with id '${modifiedItem.id}' already exists`);
|
|
215
|
+
return modifiedItem;
|
|
216
|
+
});
|
|
217
|
+
changedItems.forEach((item) => {
|
|
218
|
+
this.items.get(collection.name)?.set(serializeValue(item.id), item);
|
|
219
|
+
});
|
|
220
|
+
await this.storageAdapters.get(collection.name)?.replace(changedItems);
|
|
221
|
+
const pairs = items.map((oldItem, index) => ({
|
|
222
|
+
oldItem,
|
|
223
|
+
newItem: changedItems[index]
|
|
224
|
+
}));
|
|
225
|
+
this.applyIndexDeltas(collection, { modified: pairs });
|
|
226
|
+
this.updateQueries(collection, {
|
|
227
|
+
added: [],
|
|
228
|
+
modified: changedItems,
|
|
229
|
+
removed: []
|
|
230
|
+
});
|
|
231
|
+
return changedItems;
|
|
322
232
|
},
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
233
|
+
replaceOne: async (selector, replacement) => {
|
|
234
|
+
const item = this.getItem(collection, selector);
|
|
235
|
+
if (item == null) return [];
|
|
236
|
+
if (item.id !== replacement.id && replacement.id != null && this.getItem(collection, { id: replacement.id }) != null) throw new Error(`Item with id '${replacement.id}' already exists`);
|
|
237
|
+
const modifiedItem = {
|
|
238
|
+
id: item.id,
|
|
239
|
+
...replacement
|
|
330
240
|
};
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
241
|
+
this.items.get(collection.name)?.set(serializeValue(modifiedItem.id), modifiedItem);
|
|
242
|
+
await this.storageAdapters.get(collection.name)?.replace([modifiedItem]);
|
|
243
|
+
this.applyIndexDeltas(collection, { modified: [{
|
|
244
|
+
oldItem: item,
|
|
245
|
+
newItem: modifiedItem
|
|
246
|
+
}] });
|
|
247
|
+
this.updateQueries(collection, {
|
|
248
|
+
added: [],
|
|
249
|
+
modified: [modifiedItem],
|
|
250
|
+
removed: []
|
|
251
|
+
});
|
|
252
|
+
return [modifiedItem];
|
|
253
|
+
},
|
|
254
|
+
removeOne: async (selector) => {
|
|
255
|
+
const item = this.getItem(collection, selector);
|
|
256
|
+
if (item == null) return [];
|
|
257
|
+
this.items.get(collection.name)?.delete(serializeValue(item.id));
|
|
258
|
+
await this.storageAdapters.get(collection.name)?.remove([item]);
|
|
259
|
+
this.applyIndexDeltas(collection, { removed: [item] });
|
|
260
|
+
this.updateQueries(collection, {
|
|
261
|
+
added: [],
|
|
262
|
+
modified: [],
|
|
263
|
+
removed: [item]
|
|
264
|
+
});
|
|
265
|
+
return [item];
|
|
266
|
+
},
|
|
267
|
+
removeMany: async (selector) => {
|
|
268
|
+
const items = backend.getQueryResult(selector, {});
|
|
269
|
+
items.forEach((item) => {
|
|
270
|
+
this.items.get(collection.name)?.delete(serializeValue(item.id));
|
|
335
271
|
});
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
this.
|
|
272
|
+
await this.storageAdapters.get(collection.name)?.remove(items);
|
|
273
|
+
this.applyIndexDeltas(collection, { removed: items });
|
|
274
|
+
this.updateQueries(collection, {
|
|
275
|
+
added: [],
|
|
276
|
+
modified: [],
|
|
277
|
+
removed: items
|
|
278
|
+
});
|
|
279
|
+
return items;
|
|
280
|
+
},
|
|
281
|
+
registerQuery: (selector, options) => {
|
|
282
|
+
this.activeQueries.set(collection.name, this.activeQueries.get(collection.name) || /* @__PURE__ */ new Map());
|
|
283
|
+
this.activeQueries.get(collection.name)?.set(queryId(selector, options), {
|
|
339
284
|
selector,
|
|
340
285
|
options
|
|
341
|
-
}, listeners + 1);
|
|
342
|
-
const registrationStack = didRegister && Collection.largeQueryWarningThreshold != null ? (/* @__PURE__ */ new Error("query registered here")).stack : void 0;
|
|
343
|
-
if (didRegister) this.reportIfLargeQuery(selector, options, registrationStack);
|
|
344
|
-
const queryStateChangeCleanup = this.backend.onQueryStateChange(selector, options || {}, (state, delta) => {
|
|
345
|
-
if (state === "error") {
|
|
346
|
-
const queryError = this.backend.getQueryError(selector, options || {}) || /* @__PURE__ */ new Error(`Query on "${this.name}" failed`);
|
|
347
|
-
this.emit("query.error", queryError, selector, options);
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
if (state !== "complete") return;
|
|
351
|
-
this.reportIfLargeQuery(selector, options, registrationStack);
|
|
352
|
-
if (delta != null && canApplyDeltas && !this.batchOperationInProgress) {
|
|
353
|
-
applyDelta(delta);
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
handleRequery();
|
|
357
286
|
});
|
|
358
|
-
this.
|
|
287
|
+
this.executeAndCacheQuery(collection, selector, options);
|
|
288
|
+
},
|
|
289
|
+
unregisterQuery: (selector, options) => {
|
|
290
|
+
if (!this.activeQueries.get(collection.name)) return;
|
|
291
|
+
this.activeQueries.get(collection.name)?.delete(queryId(selector, options));
|
|
292
|
+
},
|
|
293
|
+
getQueryState: () => "complete",
|
|
294
|
+
onQueryStateChange: (selector, options, callback) => {
|
|
295
|
+
const emitter = this.queryEmitters.get(collection.name);
|
|
296
|
+
if (!emitter) throw new Error(`Query emitter not found for collection ${collection.name}`);
|
|
297
|
+
const handler = (querySelector, queryOptions, state, delta) => {
|
|
298
|
+
if (queryId(querySelector, queryOptions) !== queryId(selector, options)) return;
|
|
299
|
+
callWithDelta(callback, state, delta);
|
|
300
|
+
};
|
|
301
|
+
emitter.on("change", handler);
|
|
359
302
|
return () => {
|
|
360
|
-
|
|
361
|
-
const newListeners = Math.max(0, this.queryListeners({
|
|
362
|
-
selector,
|
|
363
|
-
options
|
|
364
|
-
}) - 1);
|
|
365
|
-
if (newListeners === 0 && didRegister) {
|
|
366
|
-
this.backend.unregisterQuery(selector, options || {});
|
|
367
|
-
this.settledQueriesSet.delete(queryId(selector, options));
|
|
368
|
-
}
|
|
369
|
-
this.queryListeners({
|
|
370
|
-
selector,
|
|
371
|
-
options
|
|
372
|
-
}, newListeners);
|
|
373
|
-
queryStateChangeCleanup();
|
|
374
|
-
this.emit("observer.disposed", selector, options);
|
|
375
|
-
});
|
|
303
|
+
emitter.off("change", handler);
|
|
376
304
|
};
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
this.batchOperationInProgress = true;
|
|
401
|
-
const afterBatch = () => {
|
|
402
|
-
this.batchOperationInProgress = false;
|
|
403
|
-
this.postBatchCallbacks.forEach((callback_) => callback_());
|
|
404
|
-
this.postBatchCallbacks.clear();
|
|
305
|
+
},
|
|
306
|
+
getQueryError: () => null,
|
|
307
|
+
getQueryResult: (selector, options) => {
|
|
308
|
+
if (this.activeQueries.get(collection.name)?.has(queryId(selector, options))) {
|
|
309
|
+
const results = this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options));
|
|
310
|
+
if (!results) throw new Error("Cached query results are not defined!");
|
|
311
|
+
return results;
|
|
312
|
+
}
|
|
313
|
+
return this.executeQuery(collection, selector, options);
|
|
314
|
+
},
|
|
315
|
+
executeQuery: (selector, options) => Promise.resolve(this.executeQuery(collection, selector, options)),
|
|
316
|
+
dispose: async () => {
|
|
317
|
+
const adapter = this.storageAdapters.get(collection.name);
|
|
318
|
+
if (adapter?.teardown) await adapter.teardown();
|
|
319
|
+
this.storageAdapters.delete(collection.name);
|
|
320
|
+
this.items.delete(collection.name);
|
|
321
|
+
this.indices.delete(collection.name);
|
|
322
|
+
this.activeQueries.delete(collection.name);
|
|
323
|
+
this.queryEmitters.delete(collection.name);
|
|
324
|
+
this.queuedQueryUpdates.delete(collection.name);
|
|
325
|
+
this.cachedQueryResults.delete(collection.name);
|
|
326
|
+
},
|
|
327
|
+
isReady: () => persistenceReadyPromise
|
|
405
328
|
};
|
|
406
|
-
|
|
407
|
-
try {
|
|
408
|
-
maybePromise = callback();
|
|
409
|
-
} catch (error) {
|
|
410
|
-
afterBatch();
|
|
411
|
-
throw error;
|
|
412
|
-
}
|
|
413
|
-
if (maybePromise && typeof maybePromise.then === "function") return maybePromise.then(() => afterBatch(), (error) => {
|
|
414
|
-
afterBatch();
|
|
415
|
-
throw error;
|
|
416
|
-
});
|
|
417
|
-
else afterBatch();
|
|
329
|
+
return backend;
|
|
418
330
|
}
|
|
419
|
-
|
|
420
|
-
if (
|
|
421
|
-
|
|
422
|
-
this.postBatchCallbacks.add(callback);
|
|
331
|
+
async fetchItemsFromStorage(collection) {
|
|
332
|
+
if (!collection) {
|
|
333
|
+
await Promise.all([...this.collections].map((currentCollection) => this.fetchItemsFromStorage(currentCollection)));
|
|
423
334
|
return;
|
|
424
335
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
async insert(item) {
|
|
434
|
-
if (this.isDisposed) throw new Error("Collection is disposed");
|
|
435
|
-
if (!item) throw new Error("Invalid item");
|
|
436
|
-
const itemWithId = {
|
|
437
|
-
id: (this.options.primaryKeyGenerator ?? randomId)(item),
|
|
438
|
-
...item
|
|
439
|
-
};
|
|
440
|
-
this.emit("validate", itemWithId);
|
|
441
|
-
const newItem = await this.withPushState(() => this.backend.insert(itemWithId));
|
|
442
|
-
this.emit("added", newItem);
|
|
443
|
-
this.emit("insert", newItem);
|
|
444
|
-
this.executeInDebugMode((callstack) => this.emit("_debug.insert", callstack, newItem));
|
|
445
|
-
return newItem.id;
|
|
446
|
-
}
|
|
447
|
-
/**
|
|
448
|
-
* Inserts multiple items into the collection. Generates unique IDs for items if not provided.
|
|
449
|
-
* @param items - The items to insert.
|
|
450
|
-
* @returns An array of IDs of the inserted items.
|
|
451
|
-
* @throws {Error} If the collection is disposed or the items are invalid.
|
|
452
|
-
*/
|
|
453
|
-
async insertMany(items) {
|
|
454
|
-
if (this.isDisposed) throw new Error("Collection is disposed");
|
|
455
|
-
if (!items) throw new Error("Invalid items");
|
|
456
|
-
if (items.length === 0) return [];
|
|
457
|
-
const ids = [];
|
|
458
|
-
await this.batch(async () => {
|
|
459
|
-
await Promise.all(items.map(async (item) => {
|
|
460
|
-
ids.push(await this.insert(item));
|
|
461
|
-
}));
|
|
462
|
-
});
|
|
463
|
-
return ids;
|
|
464
|
-
}
|
|
465
|
-
/**
|
|
466
|
-
* Updates a single item in the collection that matches the given selector.
|
|
467
|
-
* @param selector - The criteria to select the item to update.
|
|
468
|
-
* @param modifier - The modifications to apply to the item.
|
|
469
|
-
* @param [options] - Optional settings for the update operation.
|
|
470
|
-
* @param [options.upsert] - If `true`, creates a new item if no item matches the selector.
|
|
471
|
-
* @returns The number of items updated (0 or 1).
|
|
472
|
-
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
473
|
-
*/
|
|
474
|
-
async updateOne(selector, modifier, options) {
|
|
475
|
-
if (this.isDisposed) throw new Error("Collection is disposed");
|
|
476
|
-
if (!selector) throw new Error("Invalid selector");
|
|
477
|
-
if (!modifier) throw new Error("Invalid modifier");
|
|
478
|
-
const { $setOnInsert, ...restModifier } = modifier;
|
|
479
|
-
if (this.listenerCount("validate") > 0) {
|
|
480
|
-
const item = await this.getItem(selector, { async: true });
|
|
481
|
-
if (item != null) this.emit("validate", modify(deepClone(item), restModifier));
|
|
482
|
-
}
|
|
483
|
-
const changes = await this.withPushState(() => this.backend.updateOne(selector, modifier));
|
|
484
|
-
if (changes.length === 0) {
|
|
485
|
-
if (!options?.upsert) return 0;
|
|
486
|
-
const newItem = modify({}, {
|
|
487
|
-
...restModifier,
|
|
488
|
-
$set: {
|
|
489
|
-
...$setOnInsert,
|
|
490
|
-
...restModifier.$set
|
|
491
|
-
}
|
|
492
|
-
});
|
|
493
|
-
await this.insert(newItem);
|
|
494
|
-
return 1;
|
|
495
|
-
}
|
|
496
|
-
changes.forEach((item) => this.emit("changed", item, restModifier));
|
|
497
|
-
this.emit("updateOne", selector, modifier);
|
|
498
|
-
this.executeInDebugMode((callstack) => this.emit("_debug.updateOne", callstack, selector, modifier));
|
|
499
|
-
return changes.length;
|
|
500
|
-
}
|
|
501
|
-
/**
|
|
502
|
-
* Updates multiple items in the collection that match the given selector.
|
|
503
|
-
* @param selector - The criteria to select the items to update.
|
|
504
|
-
* @param modifier - The modifications to apply to the items.
|
|
505
|
-
* @param [options] - Optional settings for the update operation.
|
|
506
|
-
* @param [options.upsert] - If `true`, creates new items if no items match the selector.
|
|
507
|
-
* @returns The number of items updated.
|
|
508
|
-
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
509
|
-
*/
|
|
510
|
-
async updateMany(selector, modifier, options) {
|
|
511
|
-
if (this.isDisposed) throw new Error("Collection is disposed");
|
|
512
|
-
if (!selector) throw new Error("Invalid selector");
|
|
513
|
-
if (!modifier) throw new Error("Invalid modifier");
|
|
514
|
-
const { $setOnInsert, ...restModifier } = modifier;
|
|
515
|
-
if (this.listenerCount("validate") > 0) (await this.getItems(selector, { async: true })).forEach((item) => {
|
|
516
|
-
this.emit("validate", modify(deepClone(item), restModifier));
|
|
517
|
-
});
|
|
518
|
-
const changes = await this.withPushState(() => this.backend.updateMany(selector, modifier));
|
|
519
|
-
if (changes.length === 0) {
|
|
520
|
-
if (!options?.upsert) return 0;
|
|
521
|
-
const newItem = modify({}, {
|
|
522
|
-
...restModifier,
|
|
523
|
-
$set: {
|
|
524
|
-
...$setOnInsert,
|
|
525
|
-
...restModifier.$set
|
|
526
|
-
}
|
|
527
|
-
});
|
|
528
|
-
await this.insert(newItem);
|
|
529
|
-
return 1;
|
|
530
|
-
}
|
|
531
|
-
changes.forEach((item) => {
|
|
532
|
-
this.emit("changed", item, restModifier);
|
|
533
|
-
});
|
|
534
|
-
this.emit("updateMany", selector, modifier);
|
|
535
|
-
this.executeInDebugMode((callstack) => this.emit("_debug.updateMany", callstack, selector, modifier));
|
|
536
|
-
return changes.length;
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Replaces a single item in the collection that matches the given selector.
|
|
540
|
-
* @param selector - The criteria to select the item to replace.
|
|
541
|
-
* @param replacement - The item to replace the selected item with.
|
|
542
|
-
* @param [options] - Optional settings for the replace operation.
|
|
543
|
-
* @param [options.upsert] - If `true`, creates a new item if no item matches the selector.
|
|
544
|
-
* @returns The number of items replaced (0 or 1).
|
|
545
|
-
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
546
|
-
*/
|
|
547
|
-
async replaceOne(selector, replacement, options) {
|
|
548
|
-
if (this.isDisposed) throw new Error("Collection is disposed");
|
|
549
|
-
if (!selector) throw new Error("Invalid selector");
|
|
550
|
-
if (this.listenerCount("validate") > 0) {
|
|
551
|
-
const item = await this.getItem(selector, { async: true });
|
|
552
|
-
if (item != null) this.emit("validate", {
|
|
553
|
-
id: item.id,
|
|
554
|
-
...replacement
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
const changes = await this.withPushState(() => this.backend.replaceOne(selector, replacement));
|
|
558
|
-
if (changes.length === 0) {
|
|
559
|
-
if (!options?.upsert) return 0;
|
|
560
|
-
await this.insert(replacement);
|
|
561
|
-
return 1;
|
|
562
|
-
}
|
|
563
|
-
changes.forEach((item) => this.emit("changed", item, replacement));
|
|
564
|
-
this.emit("replaceOne", selector, replacement);
|
|
565
|
-
this.executeInDebugMode((callstack) => this.emit("_debug.replaceOne", callstack, selector, replacement));
|
|
566
|
-
return changes.length;
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Removes a single item from the collection that matches the given selector.
|
|
570
|
-
* @param selector - The criteria to select the item to remove.
|
|
571
|
-
* @returns The number of items removed (0 or 1).
|
|
572
|
-
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
573
|
-
*/
|
|
574
|
-
async removeOne(selector) {
|
|
575
|
-
if (this.isDisposed) throw new Error("Collection is disposed");
|
|
576
|
-
if (!selector) throw new Error("Invalid selector");
|
|
577
|
-
const removedItems = await this.withPushState(() => this.backend.removeOne(selector));
|
|
578
|
-
this.emit("removed", removedItems[0]);
|
|
579
|
-
this.emit("removeOne", selector);
|
|
580
|
-
this.executeInDebugMode((callstack) => this.emit("_debug.removeOne", callstack, selector));
|
|
581
|
-
return removedItems.length;
|
|
582
|
-
}
|
|
583
|
-
/**
|
|
584
|
-
* Removes multiple items from the collection that match the given selector.
|
|
585
|
-
* @param selector - The criteria to select the items to remove.
|
|
586
|
-
* @returns The number of items removed.
|
|
587
|
-
* @throws {Error} If the collection is disposed or invalid arguments are provided.
|
|
588
|
-
*/
|
|
589
|
-
async removeMany(selector) {
|
|
590
|
-
if (this.isDisposed) throw new Error("Collection is disposed");
|
|
591
|
-
if (!selector) throw new Error("Invalid selector");
|
|
592
|
-
const removedItems = await this.withPushState(() => this.backend.removeMany(selector));
|
|
593
|
-
removedItems.forEach((item) => {
|
|
594
|
-
this.emit("removed", item);
|
|
595
|
-
});
|
|
596
|
-
this.emit("removeMany", selector);
|
|
597
|
-
this.executeInDebugMode((callstack) => this.emit("_debug.removeMany", callstack, selector));
|
|
598
|
-
return removedItems.length;
|
|
336
|
+
const storageAdapter = this.storageAdapters.get(collection.name);
|
|
337
|
+
if (!storageAdapter) return;
|
|
338
|
+
const items = await storageAdapter.readAll();
|
|
339
|
+
this.items.set(collection.name, items.reduce((map, item) => {
|
|
340
|
+
map.set(serializeValue(item.id), item);
|
|
341
|
+
return map;
|
|
342
|
+
}, /* @__PURE__ */ new Map()));
|
|
343
|
+
this.rebuildIndices(collection);
|
|
599
344
|
}
|
|
600
345
|
};
|
|
601
346
|
//#endregion
|
|
602
|
-
export {
|
|
347
|
+
export { DefaultDataAdapter as default };
|