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