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