@signaldb/core 2.0.0-beta.0 → 2.0.0-beta.2
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 +24 -11
- package/dist/AsyncDataAdapter.d.ts +1 -1
- package/dist/AutoFetchDataAdapter.d.ts +1 -2
- package/dist/Collection/Cursor.d.ts +3 -2
- package/dist/Collection/index.d.ts +17 -12
- package/dist/Collection/types.d.ts +1 -0
- package/dist/DataAdapter.d.ts +9 -7
- package/dist/DefaultDataAdapter.d.ts +2 -1
- package/dist/WorkerDataAdapter.d.ts +5 -2
- package/dist/WorkerDataAdapterHost.d.ts +9 -6
- package/dist/index.cjs12.js +35 -21
- package/dist/index.cjs13.js +27 -15
- package/dist/index.cjs14.js +72 -56
- package/dist/index.cjs15.js +122 -75
- package/dist/index.cjs16.js +45 -36
- package/dist/index.cjs17.js +4 -2
- package/dist/index.cjs19.js +0 -1
- package/dist/index.cjs2.js +6 -2
- package/dist/index.cjs20.js +14 -102
- package/dist/index.cjs21.js +93 -118
- package/dist/index.cjs22.js +127 -5
- package/dist/index.cjs23.js +5 -25
- package/dist/index.cjs24.js +25 -5
- package/dist/index.cjs27.js +44 -3
- package/dist/index.cjs28.js +6 -5
- package/dist/index.cjs29.js +5 -27
- package/dist/index.cjs3.js +41 -22
- package/dist/index.cjs31.js +27 -7
- package/dist/index.cjs32.js +9 -0
- package/dist/index.cjs33.js +5 -0
- package/dist/index.d.ts +2 -1
- package/dist/index12.mjs +35 -21
- package/dist/index13.mjs +27 -15
- package/dist/index14.mjs +72 -56
- package/dist/index15.mjs +122 -75
- package/dist/index16.mjs +45 -36
- package/dist/index17.mjs +4 -2
- package/dist/index19.mjs +0 -1
- package/dist/index2.mjs +6 -2
- package/dist/index20.mjs +14 -102
- package/dist/index21.mjs +93 -117
- package/dist/index22.mjs +126 -5
- package/dist/index23.mjs +5 -25
- package/dist/index24.mjs +25 -5
- package/dist/index27.mjs +44 -3
- package/dist/index28.mjs +6 -5
- package/dist/index29.mjs +5 -27
- package/dist/index3.mjs +41 -22
- package/dist/index31.mjs +27 -7
- package/dist/index32.mjs +10 -0
- package/dist/index33.mjs +6 -0
- package/dist/utils/batchOnNextTick.d.ts +16 -0
- package/dist/utils/deepClone.d.ts +1 -1
- package/package.json +3 -3
package/dist/index.cjs14.js
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const queryId = require("./index.
|
|
2
|
+
const queryId = require("./index.cjs20.js");
|
|
3
3
|
const randomId = require("./index.cjs8.js");
|
|
4
|
+
const batchOnNextTick = require("./index.cjs27.js");
|
|
4
5
|
class WorkerDataAdapter {
|
|
5
6
|
worker;
|
|
6
7
|
options;
|
|
7
8
|
id;
|
|
8
9
|
isDisposed = false;
|
|
9
10
|
workerReady;
|
|
11
|
+
log = () => {
|
|
12
|
+
};
|
|
10
13
|
collectionReady = /* @__PURE__ */ new Map();
|
|
14
|
+
batchExecutionHelpers = /* @__PURE__ */ new Map();
|
|
11
15
|
queries = {};
|
|
12
16
|
constructor(worker, options) {
|
|
13
17
|
this.worker = worker;
|
|
14
18
|
this.options = options;
|
|
15
19
|
this.id = this.options.id || "default-worker-data-adapter";
|
|
20
|
+
if (this.options.log)
|
|
21
|
+
this.log = this.options.log;
|
|
16
22
|
this.workerReady = new Promise((resolve, reject) => {
|
|
17
23
|
const timeoutId = setTimeout(() => {
|
|
18
24
|
reject(new Error("WorkerDataAdapter initialization timed out"));
|
|
@@ -51,6 +57,7 @@ class WorkerDataAdapter {
|
|
|
51
57
|
return;
|
|
52
58
|
if (id !== messageId)
|
|
53
59
|
return;
|
|
60
|
+
this.log(method, "result", data ?? error);
|
|
54
61
|
if (error) {
|
|
55
62
|
reject(error);
|
|
56
63
|
} else {
|
|
@@ -67,88 +74,59 @@ class WorkerDataAdapter {
|
|
|
67
74
|
});
|
|
68
75
|
});
|
|
69
76
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const collectionQueries = this.queries[collectionName];
|
|
76
|
-
if (!collectionQueries)
|
|
77
|
-
return 0;
|
|
78
|
-
const existing = collectionQueries.get(id);
|
|
79
|
-
return existing?.listeners || 0;
|
|
77
|
+
enqueueBatched(collectionName, method, args) {
|
|
78
|
+
const helper = this.batchExecutionHelpers.get(collectionName);
|
|
79
|
+
if (!helper)
|
|
80
|
+
throw new Error(`Collection "${collectionName}" is not registered in WorkerDataAdapter`);
|
|
81
|
+
return helper.enqueue(method, args);
|
|
80
82
|
}
|
|
83
|
+
// ---------- end batching integration ----------
|
|
81
84
|
updateQuery(collectionName, query, update) {
|
|
82
85
|
const id = queryId(query.selector, query.options);
|
|
83
86
|
const collectionQueries = this.queries[collectionName];
|
|
84
87
|
if (!collectionQueries)
|
|
85
88
|
return;
|
|
86
89
|
const existing = collectionQueries.get(id);
|
|
87
|
-
|
|
88
|
-
listeners: 0,
|
|
90
|
+
const newState = {
|
|
89
91
|
state: "active",
|
|
90
92
|
error: null,
|
|
91
93
|
items: [],
|
|
94
|
+
stateChangeCallbacks: [],
|
|
95
|
+
eventHandler: existing?.eventHandler,
|
|
92
96
|
...existing,
|
|
93
97
|
...update
|
|
94
|
-
}
|
|
98
|
+
};
|
|
99
|
+
collectionQueries.set(id, newState);
|
|
95
100
|
this.queries[collectionName] = collectionQueries;
|
|
96
101
|
}
|
|
97
|
-
createCollectionBackend(collection, indices
|
|
102
|
+
createCollectionBackend(collection, indices) {
|
|
98
103
|
this.queries[collection.name] = /* @__PURE__ */ new Map();
|
|
99
104
|
void this.exec("registerCollection", collection.name, indices);
|
|
100
105
|
this.collectionReady.set(collection.name, this.exec("isReady", collection.name));
|
|
106
|
+
this.batchExecutionHelpers.set(collection.name, batchOnNextTick(async (method, args) => this.exec(method, collection.name, args)));
|
|
101
107
|
return {
|
|
102
108
|
insert: async (item) => {
|
|
103
|
-
return this.
|
|
109
|
+
return this.enqueueBatched(collection.name, "insert", [item]);
|
|
104
110
|
},
|
|
105
111
|
updateOne: async (selector, modifier) => {
|
|
106
|
-
return this.
|
|
112
|
+
return this.enqueueBatched(collection.name, "updateOne", [selector, modifier]);
|
|
107
113
|
},
|
|
108
114
|
updateMany: async (selector, modifier) => {
|
|
109
|
-
return this.
|
|
115
|
+
return this.enqueueBatched(collection.name, "updateMany", [selector, modifier]);
|
|
110
116
|
},
|
|
111
117
|
replaceOne: async (selector, replacement) => {
|
|
112
|
-
return this.
|
|
118
|
+
return this.enqueueBatched(collection.name, "replaceOne", [selector, replacement]);
|
|
113
119
|
},
|
|
114
120
|
removeOne: async (selector) => {
|
|
115
|
-
return this.
|
|
121
|
+
return this.enqueueBatched(collection.name, "removeOne", [selector]);
|
|
116
122
|
},
|
|
117
123
|
removeMany: async (selector) => {
|
|
118
|
-
return this.
|
|
124
|
+
return this.enqueueBatched(collection.name, "removeMany", [selector]);
|
|
119
125
|
},
|
|
120
126
|
// methods for registering and unregistering queries that will be called from the collection during find/findOne
|
|
121
127
|
registerQuery: (selector, options) => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
this.updateQuery(collection.name, { selector, options }, { state: "active", error: null, items: [] });
|
|
125
|
-
void this.exec("registerQuery", collection.name, selector, options);
|
|
126
|
-
}
|
|
127
|
-
this.queryListeners(collection.name, { selector, options }, listeners + 1);
|
|
128
|
-
},
|
|
129
|
-
unregisterQuery: (selector, options) => {
|
|
130
|
-
setTimeout(() => {
|
|
131
|
-
const listeners = this.queryListeners(collection.name, { selector, options });
|
|
132
|
-
const newListeners = Math.max(0, listeners - 1);
|
|
133
|
-
if (newListeners === 0) {
|
|
134
|
-
this.queries[collection.name]?.delete(queryId(selector, options));
|
|
135
|
-
void this.exec("unregisterQuery", collection.name, selector, options);
|
|
136
|
-
}
|
|
137
|
-
}, 0);
|
|
138
|
-
},
|
|
139
|
-
getQueryState: (selector, options) => {
|
|
140
|
-
const query = this.queries[collection.name]?.get(queryId(selector, options));
|
|
141
|
-
return query?.state || "active";
|
|
142
|
-
},
|
|
143
|
-
getQueryError: (selector, options) => {
|
|
144
|
-
const query = this.queries[collection.name]?.get(queryId(selector, options));
|
|
145
|
-
return query?.error || null;
|
|
146
|
-
},
|
|
147
|
-
getQueryResult: (selector, options) => {
|
|
148
|
-
const query = this.queries[collection.name]?.get(queryId(selector, options));
|
|
149
|
-
return query?.items || [];
|
|
150
|
-
},
|
|
151
|
-
onQueryStateChange: (selector, options, callback) => {
|
|
128
|
+
this.updateQuery(collection.name, { selector, options }, { state: "active", error: null, items: [] });
|
|
129
|
+
void this.exec("registerQuery", collection.name, selector, options);
|
|
152
130
|
const handler = (event) => {
|
|
153
131
|
const { type, data, workerId, error } = event.data;
|
|
154
132
|
if (type !== "queryUpdate")
|
|
@@ -160,21 +138,59 @@ class WorkerDataAdapter {
|
|
|
160
138
|
return;
|
|
161
139
|
if (collectionName !== collection.name)
|
|
162
140
|
return;
|
|
163
|
-
if (
|
|
164
|
-
return;
|
|
165
|
-
if (JSON.stringify(responseOptions) !== JSON.stringify(options))
|
|
141
|
+
if (queryId(responseSelector, responseOptions) !== queryId(selector, options))
|
|
166
142
|
return;
|
|
143
|
+
this.log("queryUpdate", responseSelector, responseOptions, state, data ?? error);
|
|
167
144
|
this.updateQuery(collection.name, {
|
|
168
145
|
selector: responseSelector,
|
|
169
146
|
options: responseOptions
|
|
170
147
|
}, { state, error, items });
|
|
171
|
-
|
|
148
|
+
const query = this.queries[collection.name]?.get(queryId(selector, options));
|
|
149
|
+
if (!query)
|
|
150
|
+
return;
|
|
151
|
+
query.stateChangeCallbacks.forEach((callback) => callback(state));
|
|
172
152
|
};
|
|
173
153
|
this.worker.addEventListener("message", handler);
|
|
154
|
+
this.updateQuery(collection.name, { selector, options }, { eventHandler: handler });
|
|
155
|
+
},
|
|
156
|
+
unregisterQuery: (selector, options) => {
|
|
157
|
+
const qid = queryId(selector, options);
|
|
158
|
+
const query = this.queries[collection.name]?.get(qid);
|
|
159
|
+
if (query?.eventHandler) {
|
|
160
|
+
this.worker.removeEventListener("message", query.eventHandler);
|
|
161
|
+
}
|
|
162
|
+
this.queries[collection.name]?.delete(qid);
|
|
163
|
+
void this.exec("unregisterQuery", collection.name, selector, options);
|
|
164
|
+
},
|
|
165
|
+
getQueryState: (selector, options) => {
|
|
166
|
+
const query = this.queries[collection.name]?.get(queryId(selector, options));
|
|
167
|
+
return query?.state || "active";
|
|
168
|
+
},
|
|
169
|
+
getQueryError: (selector, options) => {
|
|
170
|
+
const query = this.queries[collection.name]?.get(queryId(selector, options));
|
|
171
|
+
return query?.error || null;
|
|
172
|
+
},
|
|
173
|
+
getQueryResult: (selector, options) => {
|
|
174
|
+
const query = this.queries[collection.name]?.get(queryId(selector, options));
|
|
175
|
+
return query?.items || [];
|
|
176
|
+
},
|
|
177
|
+
onQueryStateChange: (selector, options, callback) => {
|
|
178
|
+
this.updateQuery(collection.name, { selector, options }, {
|
|
179
|
+
stateChangeCallbacks: [
|
|
180
|
+
...this.queries[collection.name]?.get(queryId(selector, options))?.stateChangeCallbacks || [],
|
|
181
|
+
callback
|
|
182
|
+
]
|
|
183
|
+
});
|
|
174
184
|
return () => {
|
|
175
|
-
this.
|
|
185
|
+
const currentCallbacks = this.queries[collection.name]?.get(queryId(selector, options))?.stateChangeCallbacks;
|
|
186
|
+
if (!currentCallbacks)
|
|
187
|
+
throw new Error("State change callbacks are not defined!");
|
|
188
|
+
this.updateQuery(collection.name, { selector, options }, {
|
|
189
|
+
stateChangeCallbacks: currentCallbacks.filter((existingCallback) => existingCallback !== callback)
|
|
190
|
+
});
|
|
176
191
|
};
|
|
177
192
|
},
|
|
193
|
+
executeQuery: (selector, options) => this.exec("executeQuery", collection.name, selector, options),
|
|
178
194
|
// lifecycle methods
|
|
179
195
|
dispose: async () => {
|
|
180
196
|
await this.exec("unregisterCollection", collection.name);
|
package/dist/index.cjs15.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const deepClone = require("./index.cjs19.js");
|
|
3
|
-
const match = require("./index.
|
|
3
|
+
const match = require("./index.cjs23.js");
|
|
4
4
|
const modify = require("./index.cjs7.js");
|
|
5
|
-
const queryId = require("./index.
|
|
5
|
+
const queryId = require("./index.cjs20.js");
|
|
6
6
|
const isEqual = require("./index.cjs6.js");
|
|
7
|
-
const getIndexInfo = require("./index.
|
|
7
|
+
const getIndexInfo = require("./index.cjs22.js");
|
|
8
8
|
const getMatchingKeys = require("./index.cjs26.js");
|
|
9
9
|
const sortItems = require("./index.cjs25.js");
|
|
10
|
-
const project = require("./index.
|
|
10
|
+
const project = require("./index.cjs24.js");
|
|
11
|
+
const compact = require("./index.cjs28.js");
|
|
11
12
|
class WorkerDataAdapterHost {
|
|
12
13
|
workerContext;
|
|
13
14
|
options;
|
|
14
15
|
id;
|
|
16
|
+
log = () => {
|
|
17
|
+
};
|
|
15
18
|
storageAdapters = /* @__PURE__ */ new Map();
|
|
16
19
|
storageAdapterReady = /* @__PURE__ */ new Map();
|
|
17
20
|
collectionIndices = /* @__PURE__ */ new Map();
|
|
@@ -26,6 +29,8 @@ class WorkerDataAdapterHost {
|
|
|
26
29
|
if (this.options.onError) {
|
|
27
30
|
this.onError = this.options.onError;
|
|
28
31
|
}
|
|
32
|
+
if (this.options.log)
|
|
33
|
+
this.log = this.options.log;
|
|
29
34
|
if (typeof addEventListener === "undefined" || typeof postMessage === "undefined") {
|
|
30
35
|
throw new TypeError("WorkerDataAdapterHost can only be used in a Web Worker context");
|
|
31
36
|
}
|
|
@@ -50,6 +55,8 @@ class WorkerDataAdapterHost {
|
|
|
50
55
|
this.respond(id, null, new Error(`Method ${method} not found`));
|
|
51
56
|
return;
|
|
52
57
|
}
|
|
58
|
+
this.log(method, ...args);
|
|
59
|
+
await this.isReady(args[0]);
|
|
53
60
|
try {
|
|
54
61
|
const result = await fn.apply(this, args);
|
|
55
62
|
this.respond(id, result);
|
|
@@ -64,7 +71,7 @@ class WorkerDataAdapterHost {
|
|
|
64
71
|
if (selector != null && Object.keys(selector).length === 1 && "id" in selector && typeof selector.id !== "object") {
|
|
65
72
|
return {
|
|
66
73
|
matched: true,
|
|
67
|
-
ids: [selector.id],
|
|
74
|
+
ids: compact([selector.id]),
|
|
68
75
|
optimizedSelector: {}
|
|
69
76
|
};
|
|
70
77
|
}
|
|
@@ -149,6 +156,8 @@ class WorkerDataAdapterHost {
|
|
|
149
156
|
}
|
|
150
157
|
}
|
|
151
158
|
async executeQuery(collectionName, selector, options) {
|
|
159
|
+
if (selector === null)
|
|
160
|
+
return [];
|
|
152
161
|
const items = await this.queryItems(collectionName, selector || {});
|
|
153
162
|
const { sort, skip, limit, fields } = options || {};
|
|
154
163
|
const sorted = sort ? sortItems(items, sort) : items;
|
|
@@ -214,10 +223,7 @@ class WorkerDataAdapterHost {
|
|
|
214
223
|
if (!storageAdapter)
|
|
215
224
|
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
216
225
|
const setupPromise = (async () => {
|
|
217
|
-
await Promise.all(
|
|
218
|
-
storageAdapter.createIndex("id"),
|
|
219
|
-
...indices.map((index) => storageAdapter.createIndex(index))
|
|
220
|
-
]);
|
|
226
|
+
await Promise.all(indices.map((index) => storageAdapter.createIndex(index)));
|
|
221
227
|
await storageAdapter.setup();
|
|
222
228
|
})();
|
|
223
229
|
this.storageAdapterReady.set(collectionName, setupPromise);
|
|
@@ -238,101 +244,142 @@ class WorkerDataAdapterHost {
|
|
|
238
244
|
throw new Error(`Collection ${collectionName} not initialized!`);
|
|
239
245
|
this.queries.get(collectionName)?.delete(id);
|
|
240
246
|
};
|
|
241
|
-
insert = async (collectionName,
|
|
247
|
+
insert = async (collectionName, input) => {
|
|
242
248
|
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
243
249
|
if (!storageAdapter)
|
|
244
250
|
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
245
|
-
const existingItems = await this.executeQuery(collectionName, { id:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
return newItem;
|
|
252
|
-
};
|
|
253
|
-
updateOne = async (collectionName, selector, modifier) => {
|
|
254
|
-
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
255
|
-
if (!storageAdapter)
|
|
256
|
-
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
257
|
-
const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then((items) => items[0] ?? null);
|
|
258
|
-
const { $setOnInsert, ...restModifier } = modifier;
|
|
259
|
-
if (item == null)
|
|
260
|
-
return [];
|
|
261
|
-
const modifiedItem = modify(deepClone.default(item), restModifier);
|
|
262
|
-
if (item.id !== modifiedItem.id) {
|
|
263
|
-
const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
|
|
264
|
-
if (existingItems.length > 0) {
|
|
265
|
-
throw new Error(`Item with id ${modifiedItem.id} already exists`);
|
|
251
|
+
const existingItems = await this.executeQuery(collectionName, { id: { $in: input.map((i) => i[0].id) } });
|
|
252
|
+
const result = input.map(([item]) => {
|
|
253
|
+
if (item.id == null)
|
|
254
|
+
return new Error("Item must have an id");
|
|
255
|
+
if (existingItems.some((existing) => existing.id === item.id)) {
|
|
256
|
+
return new Error(`Item with id ${item.id} already exists`);
|
|
266
257
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
258
|
+
return item;
|
|
259
|
+
});
|
|
260
|
+
const newItems = result.filter((item) => !(item instanceof Error));
|
|
261
|
+
await storageAdapter.insert(newItems);
|
|
262
|
+
await this.checkQueryUpdates(collectionName, newItems);
|
|
263
|
+
return result;
|
|
271
264
|
};
|
|
272
|
-
|
|
265
|
+
updateOne = async (collectionName, parameters) => {
|
|
273
266
|
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
274
267
|
if (!storageAdapter)
|
|
275
268
|
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
269
|
+
const previousItems = [];
|
|
270
|
+
const result = await Promise.all(parameters.map(async ([selector, modifier]) => {
|
|
271
|
+
const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then((items) => items[0] ?? null);
|
|
272
|
+
const { $setOnInsert, ...restModifier } = modifier;
|
|
273
|
+
if (item == null)
|
|
274
|
+
return [];
|
|
275
|
+
previousItems.push(item);
|
|
281
276
|
const modifiedItem = modify(deepClone.default(item), restModifier);
|
|
282
277
|
if (item.id !== modifiedItem.id) {
|
|
283
278
|
const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
|
|
284
279
|
if (existingItems.length > 0) {
|
|
285
|
-
|
|
280
|
+
return new Error(`Item with id ${modifiedItem.id} already exists`);
|
|
286
281
|
}
|
|
287
282
|
}
|
|
288
|
-
return modifiedItem;
|
|
283
|
+
return [modifiedItem];
|
|
289
284
|
}));
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
285
|
+
const modifiedItems = compact(result.filter((item) => !(item instanceof Error)).flat());
|
|
286
|
+
if (modifiedItems.length > 0) {
|
|
287
|
+
await storageAdapter.replace(modifiedItems);
|
|
288
|
+
await this.checkQueryUpdates(collectionName, [...modifiedItems, ...previousItems]);
|
|
289
|
+
}
|
|
290
|
+
return result;
|
|
293
291
|
};
|
|
294
|
-
|
|
292
|
+
updateMany = async (collectionName, parameters) => {
|
|
295
293
|
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
296
294
|
if (!storageAdapter)
|
|
297
295
|
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
296
|
+
const previousItems = [];
|
|
297
|
+
const result = await Promise.all(parameters.map(async ([selector, modifier]) => {
|
|
298
|
+
const items = await this.executeQuery(collectionName, selector);
|
|
299
|
+
if (items.length === 0)
|
|
300
|
+
return [];
|
|
301
|
+
const { $setOnInsert, ...restModifier } = modifier;
|
|
302
|
+
try {
|
|
303
|
+
const changedItems = await Promise.all(items.map(async (item) => {
|
|
304
|
+
const modifiedItem = modify(deepClone.default(item), restModifier);
|
|
305
|
+
if (item.id !== modifiedItem.id) {
|
|
306
|
+
const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
|
|
307
|
+
if (existingItems.length > 0) {
|
|
308
|
+
throw new Error(`Item with id ${modifiedItem.id} already exists`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
previousItems.push(item);
|
|
312
|
+
return modifiedItem;
|
|
313
|
+
}));
|
|
314
|
+
return changedItems;
|
|
315
|
+
} catch (error) {
|
|
316
|
+
return error;
|
|
309
317
|
}
|
|
318
|
+
}));
|
|
319
|
+
const modifiedItems = compact(result.filter((item) => !(item instanceof Error)).flat());
|
|
320
|
+
if (modifiedItems.length > 0) {
|
|
321
|
+
await storageAdapter.replace(modifiedItems);
|
|
322
|
+
await this.checkQueryUpdates(collectionName, [...modifiedItems, ...previousItems]);
|
|
310
323
|
}
|
|
311
|
-
|
|
312
|
-
await this.checkQueryUpdates(collectionName, [modifiedItem]);
|
|
313
|
-
return [modifiedItem];
|
|
324
|
+
return result;
|
|
314
325
|
};
|
|
315
|
-
|
|
326
|
+
replaceOne = async (collectionName, parameters) => {
|
|
316
327
|
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
317
328
|
if (!storageAdapter)
|
|
318
329
|
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
330
|
+
const previousItems = [];
|
|
331
|
+
const result = await Promise.all(parameters.map(async ([selector, replacement]) => {
|
|
332
|
+
const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then((items) => items[0] ?? null);
|
|
333
|
+
if (item == null)
|
|
334
|
+
return [];
|
|
335
|
+
previousItems.push(item);
|
|
336
|
+
const modifiedItem = {
|
|
337
|
+
...replacement,
|
|
338
|
+
id: replacement.id ?? item.id
|
|
339
|
+
};
|
|
340
|
+
if (item.id !== modifiedItem.id) {
|
|
341
|
+
const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
|
|
342
|
+
if (existingItems.length > 0) {
|
|
343
|
+
return new Error(`Item with id ${modifiedItem.id} already exists`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return [modifiedItem];
|
|
347
|
+
}));
|
|
348
|
+
const modifiedItems = compact(result.filter((item) => !(item instanceof Error)).flat());
|
|
349
|
+
if (modifiedItems.length > 0) {
|
|
350
|
+
await storageAdapter.replace(modifiedItems);
|
|
351
|
+
await this.checkQueryUpdates(collectionName, [...modifiedItems, ...previousItems]);
|
|
352
|
+
}
|
|
353
|
+
return result;
|
|
325
354
|
};
|
|
326
|
-
|
|
355
|
+
removeOne = async (collectionName, selectors) => {
|
|
327
356
|
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
328
357
|
if (!storageAdapter)
|
|
329
358
|
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
359
|
+
const result = await Promise.all(selectors.map(async ([selector]) => {
|
|
360
|
+
const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then((items2) => items2[0] ?? null);
|
|
361
|
+
if (item == null)
|
|
362
|
+
return [];
|
|
363
|
+
return [item];
|
|
364
|
+
}));
|
|
365
|
+
const items = result.flat();
|
|
366
|
+
if (items.length > 0) {
|
|
367
|
+
await storageAdapter.remove(items);
|
|
368
|
+
await this.checkQueryUpdates(collectionName, items);
|
|
369
|
+
}
|
|
370
|
+
return result;
|
|
371
|
+
};
|
|
372
|
+
removeMany = async (collectionName, selectors) => {
|
|
373
|
+
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
374
|
+
if (!storageAdapter)
|
|
375
|
+
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
376
|
+
const result = await Promise.all(selectors.map(async ([selector]) => this.executeQuery(collectionName, selector)));
|
|
377
|
+
const items = result.flat();
|
|
378
|
+
if (items.length > 0) {
|
|
379
|
+
await storageAdapter.remove(items);
|
|
380
|
+
await this.checkQueryUpdates(collectionName, items);
|
|
381
|
+
}
|
|
382
|
+
return result;
|
|
336
383
|
};
|
|
337
384
|
isReady = async (collectionName) => {
|
|
338
385
|
return this.storageAdapterReady.get(collectionName);
|