@signaldb/core 2.0.0-beta.11 → 2.0.0-beta.13
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 +19 -4
- package/dist/Collection/Cursor.d.ts +42 -0
- package/dist/Collection/index.d.ts +2 -1
- package/dist/WorkerDataAdapter.d.ts +20 -0
- package/dist/index.cjs.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index25.cjs.js +17 -1
- package/dist/index25.mjs +17 -1
- package/dist/index29.cjs.js +2 -1
- package/dist/index29.mjs +2 -1
- package/dist/index31.cjs.js +29 -188
- package/dist/index31.mjs +29 -188
- package/dist/index32.cjs.js +310 -20
- package/dist/index32.mjs +310 -20
- package/dist/index33.cjs.js +20 -334
- package/dist/index33.mjs +20 -334
- package/dist/index34.cjs.js +237 -441
- package/dist/index34.mjs +237 -441
- package/dist/index35.cjs.js +539 -0
- package/dist/index35.mjs +539 -0
- package/dist/index5.cjs.js +35 -1
- package/dist/index5.mjs +35 -1
- package/dist/utils/applyQueryOptions.d.ts +15 -0
- package/package.json +1 -1
package/dist/index31.mjs
CHANGED
|
@@ -1,191 +1,32 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
//#region src/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const { type, workerId } = event.data;
|
|
26
|
-
if (workerId !== this.id) return;
|
|
27
|
-
if (type === "ready") {
|
|
28
|
-
resolve();
|
|
29
|
-
clearTimeout(timeoutId);
|
|
30
|
-
this.worker.removeEventListener("message", handleMessage);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
this.worker.addEventListener("message", handleMessage);
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
async exec(method, collectionName, ...args) {
|
|
37
|
-
await this.workerReady;
|
|
38
|
-
if (method !== "isReady") {
|
|
39
|
-
const collectionReady = this.collectionReady.get(collectionName);
|
|
40
|
-
if (!collectionReady) throw new Error(`Collection "${collectionName}" is not registered in WorkerDataAdapter`);
|
|
41
|
-
await collectionReady;
|
|
42
|
-
}
|
|
43
|
-
if (this.isDisposed) throw new Error("WorkerDataAdapter is disposed");
|
|
44
|
-
return new Promise((resolve, reject) => {
|
|
45
|
-
const messageId = randomId();
|
|
46
|
-
const handleMessage = (event) => {
|
|
47
|
-
const { id, workerId, type, data, error } = event.data;
|
|
48
|
-
if (workerId !== this.id) return;
|
|
49
|
-
if (type !== "response") return;
|
|
50
|
-
if (id !== messageId) return;
|
|
51
|
-
this.log(method, "result", data ?? error);
|
|
52
|
-
if (error) reject(error);
|
|
53
|
-
else resolve(data);
|
|
54
|
-
this.worker.removeEventListener("message", handleMessage);
|
|
55
|
-
};
|
|
56
|
-
this.worker.addEventListener("message", handleMessage);
|
|
57
|
-
this.worker.postMessage({
|
|
58
|
-
id: messageId,
|
|
59
|
-
workerId: this.id,
|
|
60
|
-
method,
|
|
61
|
-
args: [collectionName, ...args]
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
enqueueBatched(collectionName, method, args) {
|
|
66
|
-
const helper = this.batchExecutionHelpers.get(collectionName);
|
|
67
|
-
if (!helper) throw new Error(`Collection "${collectionName}" is not registered in WorkerDataAdapter`);
|
|
68
|
-
return helper.enqueue(method, args);
|
|
69
|
-
}
|
|
70
|
-
updateQuery(collectionName, query, update) {
|
|
71
|
-
const id = queryId(query.selector, query.options);
|
|
72
|
-
const collectionQueries = this.queries[collectionName];
|
|
73
|
-
if (!collectionQueries) return;
|
|
74
|
-
const existing = collectionQueries.get(id);
|
|
75
|
-
const newState = {
|
|
76
|
-
state: "active",
|
|
77
|
-
error: null,
|
|
78
|
-
items: [],
|
|
79
|
-
stateChangeCallbacks: [],
|
|
80
|
-
eventHandler: existing?.eventHandler,
|
|
81
|
-
...existing,
|
|
82
|
-
...update
|
|
83
|
-
};
|
|
84
|
-
collectionQueries.set(id, newState);
|
|
85
|
-
this.queries[collectionName] = collectionQueries;
|
|
86
|
-
}
|
|
87
|
-
createCollectionBackend(collection, indices) {
|
|
88
|
-
this.queries[collection.name] = /* @__PURE__ */ new Map();
|
|
89
|
-
this.exec("registerCollection", collection.name, indices);
|
|
90
|
-
this.collectionReady.set(collection.name, this.exec("isReady", collection.name));
|
|
91
|
-
this.batchExecutionHelpers.set(collection.name, batchOnNextTick(async (method, args) => this.exec(method, collection.name, args)));
|
|
1
|
+
import match from "./index18.mjs";
|
|
2
|
+
import project from "./index21.mjs";
|
|
3
|
+
import sortItems from "./index23.mjs";
|
|
4
|
+
//#region src/utils/applyQueryOptions.ts
|
|
5
|
+
/**
|
|
6
|
+
* Filters, sorts, paginates and projects a plain in-memory array the same way
|
|
7
|
+
* DefaultDataAdapter and WorkerDataAdapterHost apply a selector/QueryOptions
|
|
8
|
+
* pair to their stored items. Used to re-derive a query's result locally after
|
|
9
|
+
* a write, without asking the backing store again.
|
|
10
|
+
* @template T - The type of the items.
|
|
11
|
+
* @param items - The items to filter, sort, paginate and project.
|
|
12
|
+
* @param selector - The selector to match items against.
|
|
13
|
+
* @param options - Sort, skip, limit and field projection options.
|
|
14
|
+
* @returns The resulting items.
|
|
15
|
+
*/
|
|
16
|
+
function applyQueryOptions(items, selector, options) {
|
|
17
|
+
const matched = selector == null ? [] : items.filter((item) => match(item, selector));
|
|
18
|
+
const { sort, skip, limit, fields } = options || {};
|
|
19
|
+
const sorted = sort ? sortItems(matched, sort) : matched;
|
|
20
|
+
const skipped = skip ? sorted.slice(skip) : sorted;
|
|
21
|
+
const limited = limit ? skipped.slice(0, limit) : skipped;
|
|
22
|
+
const idExcluded = fields && fields.id === 0;
|
|
23
|
+
return limited.map((item) => {
|
|
24
|
+
if (!fields) return item;
|
|
92
25
|
return {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
},
|
|
96
|
-
updateOne: async (selector, modifier) => {
|
|
97
|
-
return this.enqueueBatched(collection.name, "updateOne", [selector, modifier]);
|
|
98
|
-
},
|
|
99
|
-
updateMany: async (selector, modifier) => {
|
|
100
|
-
return this.enqueueBatched(collection.name, "updateMany", [selector, modifier]);
|
|
101
|
-
},
|
|
102
|
-
replaceOne: async (selector, replacement) => {
|
|
103
|
-
return this.enqueueBatched(collection.name, "replaceOne", [selector, replacement]);
|
|
104
|
-
},
|
|
105
|
-
removeOne: async (selector) => {
|
|
106
|
-
return this.enqueueBatched(collection.name, "removeOne", [selector]);
|
|
107
|
-
},
|
|
108
|
-
removeMany: async (selector) => {
|
|
109
|
-
return this.enqueueBatched(collection.name, "removeMany", [selector]);
|
|
110
|
-
},
|
|
111
|
-
registerQuery: (selector, options) => {
|
|
112
|
-
this.updateQuery(collection.name, {
|
|
113
|
-
selector,
|
|
114
|
-
options
|
|
115
|
-
}, {
|
|
116
|
-
state: "active",
|
|
117
|
-
error: null,
|
|
118
|
-
items: []
|
|
119
|
-
});
|
|
120
|
-
this.exec("registerQuery", collection.name, selector, options);
|
|
121
|
-
const handler = (event) => {
|
|
122
|
-
const { type, data, workerId, error } = event.data;
|
|
123
|
-
if (type !== "queryUpdate") return;
|
|
124
|
-
if (data == null) return;
|
|
125
|
-
const { collectionName, selector: responseSelector, options: responseOptions, state, items } = data;
|
|
126
|
-
if (workerId !== this.id) return;
|
|
127
|
-
if (collectionName !== collection.name) return;
|
|
128
|
-
if (queryId(responseSelector, responseOptions) !== queryId(selector, options)) return;
|
|
129
|
-
this.log("queryUpdate", responseSelector, responseOptions, state, data ?? error);
|
|
130
|
-
this.updateQuery(collection.name, {
|
|
131
|
-
selector: responseSelector,
|
|
132
|
-
options: responseOptions
|
|
133
|
-
}, {
|
|
134
|
-
state,
|
|
135
|
-
error,
|
|
136
|
-
items
|
|
137
|
-
});
|
|
138
|
-
const query = this.queries[collection.name]?.get(queryId(selector, options));
|
|
139
|
-
if (!query) return;
|
|
140
|
-
query.stateChangeCallbacks.forEach((callback) => callback(state));
|
|
141
|
-
};
|
|
142
|
-
this.worker.addEventListener("message", handler);
|
|
143
|
-
this.updateQuery(collection.name, {
|
|
144
|
-
selector,
|
|
145
|
-
options
|
|
146
|
-
}, { eventHandler: handler });
|
|
147
|
-
},
|
|
148
|
-
unregisterQuery: (selector, options) => {
|
|
149
|
-
const qid = queryId(selector, options);
|
|
150
|
-
const query = this.queries[collection.name]?.get(qid);
|
|
151
|
-
if (query?.eventHandler) this.worker.removeEventListener("message", query.eventHandler);
|
|
152
|
-
this.queries[collection.name]?.delete(qid);
|
|
153
|
-
this.exec("unregisterQuery", collection.name, selector, options);
|
|
154
|
-
},
|
|
155
|
-
getQueryState: (selector, options) => {
|
|
156
|
-
return (this.queries[collection.name]?.get(queryId(selector, options)))?.state || "active";
|
|
157
|
-
},
|
|
158
|
-
getQueryError: (selector, options) => {
|
|
159
|
-
return (this.queries[collection.name]?.get(queryId(selector, options)))?.error || null;
|
|
160
|
-
},
|
|
161
|
-
getQueryResult: (selector, options) => {
|
|
162
|
-
return (this.queries[collection.name]?.get(queryId(selector, options)))?.items || [];
|
|
163
|
-
},
|
|
164
|
-
onQueryStateChange: (selector, options, callback) => {
|
|
165
|
-
this.updateQuery(collection.name, {
|
|
166
|
-
selector,
|
|
167
|
-
options
|
|
168
|
-
}, { stateChangeCallbacks: [...this.queries[collection.name]?.get(queryId(selector, options))?.stateChangeCallbacks || [], callback] });
|
|
169
|
-
return () => {
|
|
170
|
-
const currentCallbacks = this.queries[collection.name]?.get(queryId(selector, options))?.stateChangeCallbacks;
|
|
171
|
-
if (!currentCallbacks) return;
|
|
172
|
-
this.updateQuery(collection.name, {
|
|
173
|
-
selector,
|
|
174
|
-
options
|
|
175
|
-
}, { stateChangeCallbacks: currentCallbacks.filter((existingCallback) => existingCallback !== callback) });
|
|
176
|
-
};
|
|
177
|
-
},
|
|
178
|
-
executeQuery: (selector, options) => this.exec("executeQuery", collection.name, selector, options),
|
|
179
|
-
dispose: async () => {
|
|
180
|
-
await this.exec("unregisterCollection", collection.name);
|
|
181
|
-
this.isDisposed = true;
|
|
182
|
-
this.worker.terminate?.();
|
|
183
|
-
},
|
|
184
|
-
isReady: async () => {
|
|
185
|
-
await this.exec("isReady", collection.name);
|
|
186
|
-
}
|
|
26
|
+
...idExcluded ? {} : { id: item.id },
|
|
27
|
+
...project(item, fields)
|
|
187
28
|
};
|
|
188
|
-
}
|
|
189
|
-
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
190
31
|
//#endregion
|
|
191
|
-
export {
|
|
32
|
+
export { applyQueryOptions as default };
|
package/dist/index32.cjs.js
CHANGED
|
@@ -1,21 +1,311 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
const require_randomId = require("./index8.cjs.js");
|
|
2
|
+
const require_deepClone = require("./index17.cjs.js");
|
|
3
|
+
const require_match = require("./index18.cjs.js");
|
|
4
|
+
const require_modify = require("./index19.cjs.js");
|
|
5
|
+
const require_queryId = require("./index22.cjs.js");
|
|
6
|
+
const require_batchOnNextTick = require("./index30.cjs.js");
|
|
7
|
+
const require_applyQueryOptions = require("./index31.cjs.js");
|
|
8
|
+
//#region src/WorkerDataAdapter.ts
|
|
9
|
+
var WorkerDataAdapter = class {
|
|
10
|
+
worker;
|
|
11
|
+
options;
|
|
12
|
+
id;
|
|
13
|
+
isDisposed = false;
|
|
14
|
+
workerReady;
|
|
15
|
+
log = () => {};
|
|
16
|
+
collectionReady = /* @__PURE__ */ new Map();
|
|
17
|
+
batchExecutionHelpers = /* @__PURE__ */ new Map();
|
|
18
|
+
queries = {};
|
|
19
|
+
pendingWrites = /* @__PURE__ */ new Map();
|
|
20
|
+
pendingWriteSeq = 0;
|
|
21
|
+
constructor(worker, options) {
|
|
22
|
+
this.worker = worker;
|
|
23
|
+
this.options = options;
|
|
24
|
+
this.id = this.options.id || "default-worker-data-adapter";
|
|
25
|
+
if (this.options.log) this.log = this.options.log;
|
|
26
|
+
this.workerReady = new Promise((resolve, reject) => {
|
|
27
|
+
const timeoutId = setTimeout(() => {
|
|
28
|
+
reject(/* @__PURE__ */ new Error("WorkerDataAdapter initialization timed out"));
|
|
29
|
+
}, 5e3);
|
|
30
|
+
const handleMessage = (event) => {
|
|
31
|
+
const { type, workerId } = event.data;
|
|
32
|
+
if (workerId !== this.id) return;
|
|
33
|
+
if (type === "ready") {
|
|
34
|
+
resolve();
|
|
35
|
+
clearTimeout(timeoutId);
|
|
36
|
+
this.worker.removeEventListener("message", handleMessage);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
this.worker.addEventListener("message", handleMessage);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async exec(method, collectionName, ...args) {
|
|
43
|
+
await this.workerReady;
|
|
44
|
+
if (method !== "isReady") {
|
|
45
|
+
const collectionReady = this.collectionReady.get(collectionName);
|
|
46
|
+
if (!collectionReady) throw new Error(`Collection "${collectionName}" is not registered in WorkerDataAdapter`);
|
|
47
|
+
await collectionReady;
|
|
48
|
+
}
|
|
49
|
+
if (this.isDisposed) throw new Error("WorkerDataAdapter is disposed");
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
const messageId = require_randomId.default();
|
|
52
|
+
const handleMessage = (event) => {
|
|
53
|
+
const { id, workerId, type, data, error } = event.data;
|
|
54
|
+
if (workerId !== this.id) return;
|
|
55
|
+
if (type !== "response") return;
|
|
56
|
+
if (id !== messageId) return;
|
|
57
|
+
this.log(method, "result", data ?? error);
|
|
58
|
+
if (error) reject(error);
|
|
59
|
+
else resolve(data);
|
|
60
|
+
this.worker.removeEventListener("message", handleMessage);
|
|
61
|
+
};
|
|
62
|
+
this.worker.addEventListener("message", handleMessage);
|
|
63
|
+
this.worker.postMessage({
|
|
64
|
+
id: messageId,
|
|
65
|
+
workerId: this.id,
|
|
66
|
+
method,
|
|
67
|
+
args: [collectionName, ...args]
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
observableItems(collectionName) {
|
|
72
|
+
const byId = /* @__PURE__ */ new Map();
|
|
73
|
+
this.queries[collectionName]?.forEach((query) => {
|
|
74
|
+
this.mergePendingWrites(collectionName, query.items).forEach((item) => {
|
|
75
|
+
byId.set(item.id, item);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
return [...byId.values()];
|
|
79
|
+
}
|
|
80
|
+
mergePendingWrites(collectionName, items) {
|
|
81
|
+
const pending = this.pendingWrites.get(collectionName);
|
|
82
|
+
if (!pending || pending.size === 0) return items;
|
|
83
|
+
const merged = new Map(items.map((item) => [item.id, item]));
|
|
84
|
+
[...pending.entries()].sort(([a], [b]) => a - b).forEach(([, write]) => {
|
|
85
|
+
write.upserts.forEach((item, id) => merged.set(id, item));
|
|
86
|
+
write.deletes.forEach((id) => merged.delete(id));
|
|
87
|
+
});
|
|
88
|
+
return [...merged.values()];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Registers a write's effect locally and notifies every active query it
|
|
92
|
+
* touches, then returns a function that drops it again once the write
|
|
93
|
+
* settles.
|
|
94
|
+
* @param collectionName - The collection the write targets.
|
|
95
|
+
* @param upserts - Items inserted or updated by the write.
|
|
96
|
+
* @param deletes - Ids removed by the write.
|
|
97
|
+
* @returns A function that drops the pending write and re-notifies.
|
|
98
|
+
*/
|
|
99
|
+
applyPendingWrite(collectionName, upserts, deletes) {
|
|
100
|
+
if (upserts.length === 0 && deletes.length === 0) return () => {};
|
|
101
|
+
const seq = this.pendingWriteSeq += 1;
|
|
102
|
+
const pending = this.pendingWrites.get(collectionName) ?? /* @__PURE__ */ new Map();
|
|
103
|
+
pending.set(seq, {
|
|
104
|
+
upserts: new Map(upserts.map((item) => [item.id, item])),
|
|
105
|
+
deletes: new Set(deletes)
|
|
106
|
+
});
|
|
107
|
+
this.pendingWrites.set(collectionName, pending);
|
|
108
|
+
const affectedIds = new Set([...upserts.map((item) => item.id), ...deletes]);
|
|
109
|
+
this.notifyAffectedQueries(collectionName, upserts, affectedIds);
|
|
110
|
+
return () => {
|
|
111
|
+
const current = this.pendingWrites.get(collectionName);
|
|
112
|
+
if (!current) return;
|
|
113
|
+
current.delete(seq);
|
|
114
|
+
if (current.size === 0) this.pendingWrites.delete(collectionName);
|
|
115
|
+
this.notifyAffectedQueries(collectionName, upserts, affectedIds);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
notifyAffectedQueries(collectionName, upserts, affectedIds) {
|
|
119
|
+
this.queries[collectionName]?.forEach((query) => {
|
|
120
|
+
const wasHolding = query.items.some((item) => affectedIds.has(item.id));
|
|
121
|
+
const nowMatches = upserts.some((item) => query.selector != null && require_match.default(item, query.selector));
|
|
122
|
+
if (!wasHolding && !nowMatches) return;
|
|
123
|
+
query.stateChangeCallbacks.forEach((callback) => callback(query.state));
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
matchObservableItems(collectionName, selector, onlyFirst) {
|
|
127
|
+
if (selector == null) return [];
|
|
128
|
+
const matches = this.observableItems(collectionName).filter((item) => require_match.default(item, selector));
|
|
129
|
+
return onlyFirst ? matches.slice(0, 1) : matches;
|
|
130
|
+
}
|
|
131
|
+
resolveUpdate(collectionName, selector, modifier, onlyFirst) {
|
|
132
|
+
const { $setOnInsert, ...restModifier } = modifier;
|
|
133
|
+
const upserts = [];
|
|
134
|
+
const deletes = [];
|
|
135
|
+
this.matchObservableItems(collectionName, selector, onlyFirst).forEach((item) => {
|
|
136
|
+
const modifiedItem = require_modify.default(require_deepClone.default(item), restModifier);
|
|
137
|
+
upserts.push(modifiedItem);
|
|
138
|
+
if (modifiedItem.id !== item.id) deletes.push(item.id);
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
upserts,
|
|
142
|
+
deletes
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
resolveRemoval(collectionName, selector, onlyFirst) {
|
|
146
|
+
return this.matchObservableItems(collectionName, selector, onlyFirst).map((item) => item.id);
|
|
147
|
+
}
|
|
148
|
+
resolveReplacement(item, replacement) {
|
|
149
|
+
const modifiedItem = {
|
|
150
|
+
...replacement,
|
|
151
|
+
id: replacement.id ?? item.id
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
upserts: [modifiedItem],
|
|
155
|
+
deletes: modifiedItem.id === item.id ? [] : [item.id]
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async withPendingWrite(collectionName, delta, run) {
|
|
159
|
+
const dropPendingWrite = this.applyPendingWrite(collectionName, delta.upserts, delta.deletes);
|
|
160
|
+
try {
|
|
161
|
+
return await run();
|
|
162
|
+
} finally {
|
|
163
|
+
dropPendingWrite();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
enqueueBatched(collectionName, method, args) {
|
|
167
|
+
const helper = this.batchExecutionHelpers.get(collectionName);
|
|
168
|
+
if (!helper) throw new Error(`Collection "${collectionName}" is not registered in WorkerDataAdapter`);
|
|
169
|
+
return helper.enqueue(method, args);
|
|
170
|
+
}
|
|
171
|
+
updateQuery(collectionName, query, update) {
|
|
172
|
+
const id = require_queryId.default(query.selector, query.options);
|
|
173
|
+
const collectionQueries = this.queries[collectionName];
|
|
174
|
+
if (!collectionQueries) return;
|
|
175
|
+
const existing = collectionQueries.get(id);
|
|
176
|
+
const newState = {
|
|
177
|
+
selector: query.selector,
|
|
178
|
+
options: query.options,
|
|
179
|
+
state: "active",
|
|
180
|
+
error: null,
|
|
181
|
+
items: [],
|
|
182
|
+
stateChangeCallbacks: [],
|
|
183
|
+
eventHandler: existing?.eventHandler,
|
|
184
|
+
...existing,
|
|
185
|
+
...update
|
|
186
|
+
};
|
|
187
|
+
collectionQueries.set(id, newState);
|
|
188
|
+
this.queries[collectionName] = collectionQueries;
|
|
189
|
+
}
|
|
190
|
+
createCollectionBackend(collection, indices) {
|
|
191
|
+
this.queries[collection.name] = /* @__PURE__ */ new Map();
|
|
192
|
+
this.exec("registerCollection", collection.name, indices);
|
|
193
|
+
this.collectionReady.set(collection.name, this.exec("isReady", collection.name));
|
|
194
|
+
this.batchExecutionHelpers.set(collection.name, require_batchOnNextTick.default(async (method, args) => this.exec(method, collection.name, args)));
|
|
195
|
+
return {
|
|
196
|
+
insert: async (item) => {
|
|
197
|
+
return this.withPendingWrite(collection.name, {
|
|
198
|
+
upserts: [item],
|
|
199
|
+
deletes: []
|
|
200
|
+
}, () => this.enqueueBatched(collection.name, "insert", [item]));
|
|
201
|
+
},
|
|
202
|
+
updateOne: async (selector, modifier) => {
|
|
203
|
+
return this.withPendingWrite(collection.name, this.resolveUpdate(collection.name, selector, modifier, true), () => this.enqueueBatched(collection.name, "updateOne", [selector, modifier]));
|
|
204
|
+
},
|
|
205
|
+
updateMany: async (selector, modifier) => {
|
|
206
|
+
return this.withPendingWrite(collection.name, this.resolveUpdate(collection.name, selector, modifier, false), () => this.enqueueBatched(collection.name, "updateMany", [selector, modifier]));
|
|
207
|
+
},
|
|
208
|
+
replaceOne: async (selector, replacement) => {
|
|
209
|
+
const [item] = this.matchObservableItems(collection.name, selector, true);
|
|
210
|
+
return this.withPendingWrite(collection.name, item == null ? {
|
|
211
|
+
upserts: [],
|
|
212
|
+
deletes: []
|
|
213
|
+
} : this.resolveReplacement(item, replacement), () => this.enqueueBatched(collection.name, "replaceOne", [selector, replacement]));
|
|
214
|
+
},
|
|
215
|
+
removeOne: async (selector) => {
|
|
216
|
+
return this.withPendingWrite(collection.name, {
|
|
217
|
+
upserts: [],
|
|
218
|
+
deletes: this.resolveRemoval(collection.name, selector, true)
|
|
219
|
+
}, () => this.enqueueBatched(collection.name, "removeOne", [selector]));
|
|
220
|
+
},
|
|
221
|
+
removeMany: async (selector) => {
|
|
222
|
+
return this.withPendingWrite(collection.name, {
|
|
223
|
+
upserts: [],
|
|
224
|
+
deletes: this.resolveRemoval(collection.name, selector, false)
|
|
225
|
+
}, () => this.enqueueBatched(collection.name, "removeMany", [selector]));
|
|
226
|
+
},
|
|
227
|
+
registerQuery: (selector, options) => {
|
|
228
|
+
this.updateQuery(collection.name, {
|
|
229
|
+
selector,
|
|
230
|
+
options
|
|
231
|
+
}, {
|
|
232
|
+
state: "active",
|
|
233
|
+
error: null,
|
|
234
|
+
items: []
|
|
235
|
+
});
|
|
236
|
+
this.exec("registerQuery", collection.name, selector, options);
|
|
237
|
+
const handler = (event) => {
|
|
238
|
+
const { type, data, workerId, error } = event.data;
|
|
239
|
+
if (type !== "queryUpdate") return;
|
|
240
|
+
if (data == null) return;
|
|
241
|
+
const { collectionName, selector: responseSelector, options: responseOptions, state, items } = data;
|
|
242
|
+
if (workerId !== this.id) return;
|
|
243
|
+
if (collectionName !== collection.name) return;
|
|
244
|
+
if (require_queryId.default(responseSelector, responseOptions) !== require_queryId.default(selector, options)) return;
|
|
245
|
+
this.log("queryUpdate", responseSelector, responseOptions, state, data ?? error);
|
|
246
|
+
this.updateQuery(collection.name, {
|
|
247
|
+
selector: responseSelector,
|
|
248
|
+
options: responseOptions
|
|
249
|
+
}, {
|
|
250
|
+
state,
|
|
251
|
+
error,
|
|
252
|
+
items
|
|
253
|
+
});
|
|
254
|
+
const query = this.queries[collection.name]?.get(require_queryId.default(selector, options));
|
|
255
|
+
if (!query) return;
|
|
256
|
+
query.stateChangeCallbacks.forEach((callback) => callback(state));
|
|
257
|
+
};
|
|
258
|
+
this.worker.addEventListener("message", handler);
|
|
259
|
+
this.updateQuery(collection.name, {
|
|
260
|
+
selector,
|
|
261
|
+
options
|
|
262
|
+
}, { eventHandler: handler });
|
|
263
|
+
},
|
|
264
|
+
unregisterQuery: (selector, options) => {
|
|
265
|
+
const qid = require_queryId.default(selector, options);
|
|
266
|
+
const query = this.queries[collection.name]?.get(qid);
|
|
267
|
+
if (query?.eventHandler) this.worker.removeEventListener("message", query.eventHandler);
|
|
268
|
+
this.queries[collection.name]?.delete(qid);
|
|
269
|
+
this.exec("unregisterQuery", collection.name, selector, options);
|
|
270
|
+
},
|
|
271
|
+
getQueryState: (selector, options) => {
|
|
272
|
+
return (this.queries[collection.name]?.get(require_queryId.default(selector, options)))?.state || "active";
|
|
273
|
+
},
|
|
274
|
+
getQueryError: (selector, options) => {
|
|
275
|
+
return (this.queries[collection.name]?.get(require_queryId.default(selector, options)))?.error || null;
|
|
276
|
+
},
|
|
277
|
+
getQueryResult: (selector, options) => {
|
|
278
|
+
const query = this.queries[collection.name]?.get(require_queryId.default(selector, options));
|
|
279
|
+
if (!query) return [];
|
|
280
|
+
const pending = this.pendingWrites.get(collection.name);
|
|
281
|
+
if (!pending || pending.size === 0) return query.items;
|
|
282
|
+
return require_applyQueryOptions.default(this.mergePendingWrites(collection.name, query.items), selector, options);
|
|
283
|
+
},
|
|
284
|
+
onQueryStateChange: (selector, options, callback) => {
|
|
285
|
+
this.updateQuery(collection.name, {
|
|
286
|
+
selector,
|
|
287
|
+
options
|
|
288
|
+
}, { stateChangeCallbacks: [...this.queries[collection.name]?.get(require_queryId.default(selector, options))?.stateChangeCallbacks || [], callback] });
|
|
289
|
+
return () => {
|
|
290
|
+
const currentCallbacks = this.queries[collection.name]?.get(require_queryId.default(selector, options))?.stateChangeCallbacks;
|
|
291
|
+
if (!currentCallbacks) return;
|
|
292
|
+
this.updateQuery(collection.name, {
|
|
293
|
+
selector,
|
|
294
|
+
options
|
|
295
|
+
}, { stateChangeCallbacks: currentCallbacks.filter((existingCallback) => existingCallback !== callback) });
|
|
296
|
+
};
|
|
297
|
+
},
|
|
298
|
+
executeQuery: (selector, options) => this.exec("executeQuery", collection.name, selector, options),
|
|
299
|
+
dispose: async () => {
|
|
300
|
+
await this.exec("unregisterCollection", collection.name);
|
|
301
|
+
this.isDisposed = true;
|
|
302
|
+
this.worker.terminate?.();
|
|
303
|
+
},
|
|
304
|
+
isReady: async () => {
|
|
305
|
+
await this.exec("isReady", collection.name);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
};
|
|
20
310
|
//#endregion
|
|
21
|
-
exports.default =
|
|
311
|
+
exports.default = WorkerDataAdapter;
|