@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.cjs22.js
CHANGED
|
@@ -1,7 +1,129 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const intersection = require("./index.cjs29.js");
|
|
4
|
+
function getMergedIndexInfo(queryFunctions, selector) {
|
|
5
|
+
return queryFunctions.reduce((memoOrPromise, queryFunction) => {
|
|
6
|
+
const resultOrPromise = queryFunction(selector);
|
|
7
|
+
const processResult = (memo2, result) => {
|
|
8
|
+
if (!result.matched)
|
|
9
|
+
return memo2;
|
|
10
|
+
const optimizedSelector = result.keepSelector ? memo2.optimizedSelector : Object.fromEntries(Object.entries(memo2.optimizedSelector).filter(([key]) => !result.fields.includes(key)));
|
|
11
|
+
return {
|
|
12
|
+
matched: true,
|
|
13
|
+
ids: [...new Set(memo2.matched ? intersection(memo2.ids, result.ids) : result.ids)],
|
|
14
|
+
optimizedSelector
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
if (resultOrPromise instanceof Promise) {
|
|
18
|
+
return resultOrPromise.then(async (result) => {
|
|
19
|
+
const memo2 = memoOrPromise instanceof Promise ? await memoOrPromise : memoOrPromise;
|
|
20
|
+
return processResult(memo2, result);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const memo = memoOrPromise;
|
|
24
|
+
if (memo instanceof Promise)
|
|
25
|
+
throw new Error("Mixing async and sync index providers is not supported");
|
|
26
|
+
return processResult(memo, resultOrPromise);
|
|
27
|
+
}, {
|
|
28
|
+
matched: false,
|
|
29
|
+
ids: [],
|
|
30
|
+
optimizedSelector: { ...selector }
|
|
31
|
+
});
|
|
6
32
|
}
|
|
7
|
-
|
|
33
|
+
function optimizeLogicGate(queryFunctions, logicGate, idsCallback) {
|
|
34
|
+
return logicGate.reduce((memoOrPromise, sel) => {
|
|
35
|
+
const getSelector = (indexInfo) => {
|
|
36
|
+
const { matched: selMatched, ids: selIds, optimizedSelector: optimizedSelector2 } = indexInfo;
|
|
37
|
+
if (selMatched) {
|
|
38
|
+
idsCallback(true, selIds);
|
|
39
|
+
if (Object.keys(optimizedSelector2).length > 0) {
|
|
40
|
+
return optimizedSelector2;
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
idsCallback(false, []);
|
|
44
|
+
return sel;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const indexInfoOrPromise = getIndexInfo(queryFunctions, sel);
|
|
48
|
+
if (indexInfoOrPromise instanceof Promise) {
|
|
49
|
+
return indexInfoOrPromise.then(async (indexInfo) => {
|
|
50
|
+
const memo2 = memoOrPromise instanceof Promise ? await memoOrPromise : memoOrPromise;
|
|
51
|
+
const optimizedSelector2 = getSelector(indexInfo);
|
|
52
|
+
if (optimizedSelector2)
|
|
53
|
+
memo2.push(optimizedSelector2);
|
|
54
|
+
return memo2;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const memo = memoOrPromise;
|
|
58
|
+
if (memo instanceof Promise)
|
|
59
|
+
throw new Error("Mixing async and sync index providers is not supported");
|
|
60
|
+
const optimizedSelector = getSelector(indexInfoOrPromise);
|
|
61
|
+
if (optimizedSelector)
|
|
62
|
+
memo.push(optimizedSelector);
|
|
63
|
+
return memo;
|
|
64
|
+
}, []);
|
|
65
|
+
}
|
|
66
|
+
function getIndexInfo(queryFunctions, selector) {
|
|
67
|
+
if (selector == null || Object.keys(selector).length <= 0) {
|
|
68
|
+
return {
|
|
69
|
+
matched: false,
|
|
70
|
+
ids: [],
|
|
71
|
+
optimizedSelector: selector
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const { $and, $or, ...rest } = selector;
|
|
75
|
+
const flatInfoOrPromise = getMergedIndexInfo(queryFunctions, rest);
|
|
76
|
+
const processFlatInfo = (flatInfo) => {
|
|
77
|
+
let { matched, ids } = flatInfo;
|
|
78
|
+
const newSelector = flatInfo.optimizedSelector;
|
|
79
|
+
const $andNewOrPromise = Array.isArray($and) ? optimizeLogicGate(queryFunctions, $and, (match, selIds) => {
|
|
80
|
+
if (!match)
|
|
81
|
+
return;
|
|
82
|
+
ids = matched ? intersection(ids, selIds) : selIds;
|
|
83
|
+
matched = true;
|
|
84
|
+
}) : void 0;
|
|
85
|
+
const process$and = ($andNew) => {
|
|
86
|
+
if ($andNew && $andNew.length > 0)
|
|
87
|
+
newSelector.$and = $andNew;
|
|
88
|
+
let hasNonIndexField = false;
|
|
89
|
+
const matchedBefore = matched;
|
|
90
|
+
const idsBefore = ids;
|
|
91
|
+
const process$or = ($orNew) => {
|
|
92
|
+
if ($orNew && $orNew.length > 0)
|
|
93
|
+
newSelector.$or = $orNew;
|
|
94
|
+
if (hasNonIndexField) {
|
|
95
|
+
newSelector.$or = $or;
|
|
96
|
+
matched = matchedBefore;
|
|
97
|
+
ids = idsBefore;
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
matched,
|
|
101
|
+
ids: ids || [],
|
|
102
|
+
optimizedSelector: newSelector
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
const $orNewOrPromise = Array.isArray($or) ? optimizeLogicGate(queryFunctions, $or, (match, selIds) => {
|
|
106
|
+
if (match) {
|
|
107
|
+
ids = [.../* @__PURE__ */ new Set([...ids, ...selIds])];
|
|
108
|
+
matched = true;
|
|
109
|
+
} else {
|
|
110
|
+
hasNonIndexField = true;
|
|
111
|
+
}
|
|
112
|
+
}) : void 0;
|
|
113
|
+
if ($orNewOrPromise instanceof Promise) {
|
|
114
|
+
return $orNewOrPromise.then(($orNew) => process$or($orNew));
|
|
115
|
+
}
|
|
116
|
+
return process$or($orNewOrPromise);
|
|
117
|
+
};
|
|
118
|
+
if ($andNewOrPromise instanceof Promise) {
|
|
119
|
+
return $andNewOrPromise.then(($andNew) => process$and($andNew));
|
|
120
|
+
}
|
|
121
|
+
return process$and($andNewOrPromise);
|
|
122
|
+
};
|
|
123
|
+
if (flatInfoOrPromise instanceof Promise) {
|
|
124
|
+
return flatInfoOrPromise.then(processFlatInfo);
|
|
125
|
+
}
|
|
126
|
+
return processFlatInfo(flatInfoOrPromise);
|
|
127
|
+
}
|
|
128
|
+
exports.default = getIndexInfo;
|
|
129
|
+
exports.getMergedIndexInfo = getMergedIndexInfo;
|
package/dist/index.cjs23.js
CHANGED
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (allFieldsDeactivated) {
|
|
7
|
-
const result2 = { ...item };
|
|
8
|
-
Object.keys(fields).forEach((key) => {
|
|
9
|
-
const fieldValue = get(item, key);
|
|
10
|
-
if (fieldValue === void 0)
|
|
11
|
-
return;
|
|
12
|
-
set(result2, key, void 0, true);
|
|
13
|
-
});
|
|
14
|
-
return result2;
|
|
15
|
-
}
|
|
16
|
-
const result = {};
|
|
17
|
-
Object.entries(fields).forEach(([key, value]) => {
|
|
18
|
-
const fieldValue = get(item, key);
|
|
19
|
-
if (fieldValue === void 0)
|
|
20
|
-
return;
|
|
21
|
-
if (fieldValue == null && value !== 1)
|
|
22
|
-
return;
|
|
23
|
-
set(result, key, value === 1 ? fieldValue : void 0);
|
|
24
|
-
});
|
|
25
|
-
return result;
|
|
2
|
+
const mingo = require("mingo");
|
|
3
|
+
function match(item, selector) {
|
|
4
|
+
const query = new mingo.Query(selector);
|
|
5
|
+
return query.test(item);
|
|
26
6
|
}
|
|
27
|
-
module.exports =
|
|
7
|
+
module.exports = match;
|
package/dist/index.cjs24.js
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
const get = require("./index.cjs10.js");
|
|
3
|
+
const set = require("./index.cjs31.js");
|
|
4
|
+
function project(item, fields) {
|
|
5
|
+
const allFieldsDeactivated = Object.values(fields).every((value) => value === 0);
|
|
6
|
+
if (allFieldsDeactivated) {
|
|
7
|
+
const result2 = { ...item };
|
|
8
|
+
Object.keys(fields).forEach((key) => {
|
|
9
|
+
const fieldValue = get(item, key);
|
|
10
|
+
if (fieldValue === void 0)
|
|
11
|
+
return;
|
|
12
|
+
set(result2, key, void 0, true);
|
|
13
|
+
});
|
|
14
|
+
return result2;
|
|
15
|
+
}
|
|
16
|
+
const result = {};
|
|
17
|
+
Object.entries(fields).forEach(([key, value]) => {
|
|
18
|
+
const fieldValue = get(item, key);
|
|
19
|
+
if (fieldValue === void 0)
|
|
20
|
+
return;
|
|
21
|
+
if (fieldValue == null && value !== 1)
|
|
22
|
+
return;
|
|
23
|
+
set(result, key, value === 1 ? fieldValue : void 0);
|
|
24
|
+
});
|
|
25
|
+
return result;
|
|
6
26
|
}
|
|
7
|
-
module.exports =
|
|
27
|
+
module.exports = project;
|
package/dist/index.cjs27.js
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
function
|
|
3
|
-
|
|
2
|
+
function batchOnNextTick(onFlush) {
|
|
3
|
+
const queues = /* @__PURE__ */ new Map();
|
|
4
|
+
function enqueue(key, args) {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
let q = queues.get(key);
|
|
7
|
+
if (!q) {
|
|
8
|
+
q = {
|
|
9
|
+
timer: null,
|
|
10
|
+
items: [],
|
|
11
|
+
flush: () => flush(key)
|
|
12
|
+
};
|
|
13
|
+
queues.set(key, q);
|
|
14
|
+
}
|
|
15
|
+
q.items.push({ args, resolve, reject });
|
|
16
|
+
if (q.timer == null) {
|
|
17
|
+
q.timer = setTimeout(() => {
|
|
18
|
+
q.timer = null;
|
|
19
|
+
void q.flush();
|
|
20
|
+
}, 0);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
async function flush(key) {
|
|
25
|
+
const q = queues.get(key);
|
|
26
|
+
if (!q || q.items.length === 0)
|
|
27
|
+
return;
|
|
28
|
+
if (q.timer != null) {
|
|
29
|
+
clearTimeout(q.timer);
|
|
30
|
+
q.timer = null;
|
|
31
|
+
}
|
|
32
|
+
const items = q.items.splice(0);
|
|
33
|
+
onFlush(key, items.map((i) => i.args)).then((results) => {
|
|
34
|
+
for (const [index, result] of results.entries()) {
|
|
35
|
+
const { resolve } = items[index];
|
|
36
|
+
resolve(result);
|
|
37
|
+
}
|
|
38
|
+
}).catch((error) => {
|
|
39
|
+
for (const { reject } of items) {
|
|
40
|
+
reject(error);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return { enqueue, flush };
|
|
4
45
|
}
|
|
5
|
-
module.exports =
|
|
46
|
+
module.exports = batchOnNextTick;
|
package/dist/index.cjs28.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
return [];
|
|
5
|
-
return [...new Set(arrays.reduce((a, b) => a.filter((c) => b.includes(c))))];
|
|
2
|
+
function truthy(value) {
|
|
3
|
+
return !!value;
|
|
6
4
|
}
|
|
7
|
-
|
|
5
|
+
function compact(array) {
|
|
6
|
+
return array.filter(truthy);
|
|
7
|
+
}
|
|
8
|
+
module.exports = compact;
|
package/dist/index.cjs29.js
CHANGED
|
@@ -1,29 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
function
|
|
3
|
-
if (
|
|
4
|
-
return
|
|
5
|
-
|
|
6
|
-
if (segments[0] === "")
|
|
7
|
-
segments.shift();
|
|
8
|
-
if (segments.at(-1) === "")
|
|
9
|
-
segments.pop();
|
|
10
|
-
const apply = (node) => {
|
|
11
|
-
if (segments.length > 1) {
|
|
12
|
-
const key = segments.shift();
|
|
13
|
-
const nextIsNumber = !Number.isNaN(Number.parseInt(segments[0], 10));
|
|
14
|
-
if (node[key] === void 0) {
|
|
15
|
-
node[key] = nextIsNumber ? [] : {};
|
|
16
|
-
}
|
|
17
|
-
apply(node[key]);
|
|
18
|
-
} else {
|
|
19
|
-
if (deleteIfUndefined && value === void 0) {
|
|
20
|
-
delete node[segments[0]];
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
node[segments[0]] = value;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
apply(object);
|
|
27
|
-
return object;
|
|
2
|
+
function intersection(...arrays) {
|
|
3
|
+
if (arrays.length === 0)
|
|
4
|
+
return [];
|
|
5
|
+
return [...new Set(arrays.reduce((a, b) => a.filter((c) => b.includes(c))))];
|
|
28
6
|
}
|
|
29
|
-
module.exports =
|
|
7
|
+
module.exports = intersection;
|
package/dist/index.cjs3.js
CHANGED
|
@@ -6,6 +6,7 @@ const randomId = require("./index.cjs8.js");
|
|
|
6
6
|
const DefaultDataAdapter = require("./index.cjs12.js");
|
|
7
7
|
const modify = require("./index.cjs7.js");
|
|
8
8
|
const deepClone = require("./index.cjs19.js");
|
|
9
|
+
const queryId = require("./index.cjs20.js");
|
|
9
10
|
const Cursor = require("./index.cjs2.js");
|
|
10
11
|
class Collection extends EventEmitter {
|
|
11
12
|
static collections = [];
|
|
@@ -68,6 +69,7 @@ class Collection extends EventEmitter {
|
|
|
68
69
|
isDisposed = false;
|
|
69
70
|
postBatchCallbacks = /* @__PURE__ */ new Set();
|
|
70
71
|
fieldTracking = false;
|
|
72
|
+
queryListenersMap = /* @__PURE__ */ new Map();
|
|
71
73
|
constructor(nameOrOptions, maybeDataAdapter, maybeOptions) {
|
|
72
74
|
super();
|
|
73
75
|
const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions?.name || `${this.constructor.name}-${randomId()}`;
|
|
@@ -192,6 +194,11 @@ class Collection extends EventEmitter {
|
|
|
192
194
|
return item;
|
|
193
195
|
return this.options.transform(item);
|
|
194
196
|
}
|
|
197
|
+
transformAll(items, fields) {
|
|
198
|
+
if (!this.options.transformAll)
|
|
199
|
+
return items;
|
|
200
|
+
return this.options.transformAll(deepClone.default(items), fields);
|
|
201
|
+
}
|
|
195
202
|
getItem(selector, options) {
|
|
196
203
|
const itemsOrPromise = this.getItems(selector, { ...options, limit: 1 });
|
|
197
204
|
if (itemsOrPromise instanceof Promise) {
|
|
@@ -206,21 +213,9 @@ class Collection extends EventEmitter {
|
|
|
206
213
|
return this.profile(() => {
|
|
207
214
|
if (!options?.async)
|
|
208
215
|
return this.backend.getQueryResult(selector, options);
|
|
209
|
-
|
|
210
|
-
|
|
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(() => {
|
|
216
|
+
this.isPullingSignal.set(true);
|
|
217
|
+
return this.backend.executeQuery(selector, options).finally(() => {
|
|
222
218
|
this.isPullingSignal.set(false);
|
|
223
|
-
this.backend.unregisterQuery(selector, options);
|
|
224
219
|
});
|
|
225
220
|
}, (measuredTime) => this.executeInDebugMode((callstack) => this.emit("_debug.getItems", callstack, selector, measuredTime)));
|
|
226
221
|
}
|
|
@@ -232,6 +227,13 @@ class Collection extends EventEmitter {
|
|
|
232
227
|
this.isPushingSignal.set(false);
|
|
233
228
|
}
|
|
234
229
|
}
|
|
230
|
+
queryListeners(query, listeners) {
|
|
231
|
+
const id = queryId(query.selector, query.options);
|
|
232
|
+
if (listeners != null) {
|
|
233
|
+
return this.queryListenersMap.set(id, listeners);
|
|
234
|
+
}
|
|
235
|
+
return this.queryListenersMap.get(id) ?? 0;
|
|
236
|
+
}
|
|
235
237
|
/**
|
|
236
238
|
* Disposes the collection, unregisters persistence adapters, clears memory, and
|
|
237
239
|
* cleans up all resources used by the collection.
|
|
@@ -257,7 +259,17 @@ class Collection extends EventEmitter {
|
|
|
257
259
|
throw new Error("Collection is disposed");
|
|
258
260
|
if (selector !== void 0 && (!selector || typeof selector !== "object"))
|
|
259
261
|
throw new Error("Invalid selector");
|
|
260
|
-
const
|
|
262
|
+
const getTransformedItems = () => {
|
|
263
|
+
const itemsOrPromise = this.getItems(selector, options || {});
|
|
264
|
+
if (itemsOrPromise instanceof Promise) {
|
|
265
|
+
return itemsOrPromise.then((items2) => {
|
|
266
|
+
return this.transformAll(items2, options?.fields);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const items = itemsOrPromise;
|
|
270
|
+
return this.transformAll(items, options?.fields);
|
|
271
|
+
};
|
|
272
|
+
const cursor = new Cursor.default(getTransformedItems, {
|
|
261
273
|
reactive: this.options.reactivity,
|
|
262
274
|
fieldTracking: this.fieldTracking,
|
|
263
275
|
...options,
|
|
@@ -270,17 +282,25 @@ class Collection extends EventEmitter {
|
|
|
270
282
|
}
|
|
271
283
|
requery();
|
|
272
284
|
};
|
|
273
|
-
this.
|
|
274
|
-
|
|
285
|
+
const listeners = this.queryListeners({ selector, options });
|
|
286
|
+
if (listeners === 0)
|
|
287
|
+
this.backend.registerQuery(selector, options || {});
|
|
288
|
+
this.queryListeners({ selector, options }, listeners + 1);
|
|
289
|
+
const queryStateChangeCleanup = this.backend.onQueryStateChange(selector, options || {}, (state) => {
|
|
275
290
|
if (state !== "complete")
|
|
276
291
|
return;
|
|
277
292
|
handleRequery();
|
|
278
293
|
});
|
|
279
294
|
this.emit("observer.created", selector, options);
|
|
280
295
|
return () => {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
296
|
+
setTimeout(() => {
|
|
297
|
+
const newListeners = Math.max(0, this.queryListeners({ selector, options }) - 1);
|
|
298
|
+
if (newListeners === 0)
|
|
299
|
+
this.backend.unregisterQuery(selector, options || {});
|
|
300
|
+
this.queryListeners({ selector, options }, newListeners);
|
|
301
|
+
queryStateChangeCleanup();
|
|
302
|
+
this.emit("observer.disposed", selector, options);
|
|
303
|
+
}, 0);
|
|
284
304
|
};
|
|
285
305
|
}
|
|
286
306
|
});
|
|
@@ -373,9 +393,8 @@ class Collection extends EventEmitter {
|
|
|
373
393
|
throw new Error("Collection is disposed");
|
|
374
394
|
if (!items)
|
|
375
395
|
throw new Error("Invalid items");
|
|
376
|
-
if (items.length === 0)
|
|
396
|
+
if (items.length === 0)
|
|
377
397
|
return [];
|
|
378
|
-
}
|
|
379
398
|
const ids = [];
|
|
380
399
|
await this.batch(async () => {
|
|
381
400
|
await Promise.all(items.map(async (item) => {
|
package/dist/index.cjs31.js
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
function set(object, path, value, deleteIfUndefined = false) {
|
|
3
|
+
if (object == null)
|
|
4
|
+
return object;
|
|
5
|
+
const segments = path.split(/[.[\]]/g);
|
|
6
|
+
if (segments[0] === "")
|
|
7
|
+
segments.shift();
|
|
8
|
+
if (segments.at(-1) === "")
|
|
9
|
+
segments.pop();
|
|
10
|
+
const apply = (node) => {
|
|
11
|
+
if (segments.length > 1) {
|
|
12
|
+
const key = segments.shift();
|
|
13
|
+
const nextIsNumber = !Number.isNaN(Number.parseInt(segments[0], 10));
|
|
14
|
+
if (node[key] === void 0) {
|
|
15
|
+
node[key] = nextIsNumber ? [] : {};
|
|
16
|
+
}
|
|
17
|
+
apply(node[key]);
|
|
18
|
+
} else {
|
|
19
|
+
if (deleteIfUndefined && value === void 0) {
|
|
20
|
+
delete node[segments[0]];
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
node[segments[0]] = value;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
apply(object);
|
|
27
|
+
return object;
|
|
8
28
|
}
|
|
9
|
-
module.exports =
|
|
29
|
+
module.exports = set;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
function uniqueBy(array, fn) {
|
|
3
|
+
const set = /* @__PURE__ */ new Set();
|
|
4
|
+
return array.filter((element) => {
|
|
5
|
+
const value = typeof fn === "function" ? fn(element) : element[fn];
|
|
6
|
+
return !set.has(value) && set.add(value);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
module.exports = uniqueBy;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ export type { default as ReactivityAdapter } from './types/ReactivityAdapter';
|
|
|
2
2
|
export type { default as StorageAdapter, Changeset, } from './types/StorageAdapter';
|
|
3
3
|
export type { default as Selector } from './types/Selector';
|
|
4
4
|
export type { default as Modifier } from './types/Modifier';
|
|
5
|
-
export type { BaseItem, ObserveCallbacks, CursorOptions, Transform, SortSpecifier, FieldSpecifier, FindOptions, CollectionOptions, } from './Collection';
|
|
5
|
+
export type { BaseItem, ObserveCallbacks, CursorOptions, Transform, TransformAll, SortSpecifier, FieldSpecifier, FindOptions, CollectionOptions, } from './Collection';
|
|
6
|
+
export type { default as DataAdapter } from './DataAdapter';
|
|
6
7
|
export { default as Cursor } from './Collection/Cursor';
|
|
7
8
|
export { default as Collection } from './Collection';
|
|
8
9
|
export { default as createStorageAdapter } from './createStorageAdapter';
|
package/dist/index12.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import createIndex from "./
|
|
2
|
-
import getIndexInfo from "./
|
|
1
|
+
import createIndex from "./index21.mjs";
|
|
2
|
+
import getIndexInfo from "./index22.mjs";
|
|
3
3
|
import deepClone from "./index19.mjs";
|
|
4
4
|
import EventEmitter from "./index9.mjs";
|
|
5
5
|
import isEqual from "./index6.mjs";
|
|
6
|
-
import match from "./
|
|
6
|
+
import match from "./index23.mjs";
|
|
7
7
|
import modify from "./index7.mjs";
|
|
8
|
-
import project from "./
|
|
9
|
-
import queryId from "./
|
|
8
|
+
import project from "./index24.mjs";
|
|
9
|
+
import queryId from "./index20.mjs";
|
|
10
10
|
import serializeValue from "./index11.mjs";
|
|
11
11
|
import sortItems from "./index25.mjs";
|
|
12
12
|
function hasPendingUpdates(pendingUpdates) {
|
|
@@ -142,14 +142,28 @@ class DefaultDataAdapter {
|
|
|
142
142
|
return;
|
|
143
143
|
this.queuedQueryUpdates.set(collection.name, { added: [], modified: [], removed: [] });
|
|
144
144
|
const flatItems = [...changes.added, ...changes.modified, ...changes.removed];
|
|
145
|
-
const
|
|
145
|
+
const itemIds = new Set(flatItems.map((i) => i.id));
|
|
146
|
+
const queries = [
|
|
147
|
+
...this.activeQueries.get(collection.name)?.values() ?? []
|
|
148
|
+
].filter(({ selector, options }) => {
|
|
149
|
+
const idsInQuery = this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options))?.map((i) => i.id) ?? [];
|
|
150
|
+
if (idsInQuery.some((id) => itemIds.has(id)))
|
|
151
|
+
return true;
|
|
152
|
+
return flatItems.some((item) => match(item, selector));
|
|
153
|
+
});
|
|
146
154
|
queries.forEach(({ selector, options }) => {
|
|
147
|
-
|
|
148
|
-
if (!emitter)
|
|
149
|
-
return;
|
|
150
|
-
emitter.emit("change", selector, options, "complete");
|
|
155
|
+
this.executeAndCacheQuery(collection, selector, options);
|
|
151
156
|
});
|
|
152
157
|
}
|
|
158
|
+
executeAndCacheQuery(collection, selector, options) {
|
|
159
|
+
const result = this.executeQuery(collection, selector, options);
|
|
160
|
+
this.cachedQueryResults.set(collection.name, this.cachedQueryResults.get(collection.name) || /* @__PURE__ */ new Map());
|
|
161
|
+
this.cachedQueryResults.get(collection.name)?.set(queryId(selector, options), result);
|
|
162
|
+
const emitter = this.queryEmitters.get(collection.name);
|
|
163
|
+
if (!emitter)
|
|
164
|
+
return;
|
|
165
|
+
emitter.emit("change", selector, options, "complete");
|
|
166
|
+
}
|
|
153
167
|
updateQueries(collection, changes) {
|
|
154
168
|
this.queuedQueryUpdates.set(collection.name, this.queuedQueryUpdates.get(collection.name) || { added: [], modified: [], removed: [] });
|
|
155
169
|
this.queuedQueryUpdates.get(collection.name)?.added.push(...changes.added);
|
|
@@ -161,6 +175,7 @@ class DefaultDataAdapter {
|
|
|
161
175
|
this.ensureStorageAdapter(collection.name);
|
|
162
176
|
this.items.set(collection.name, this.items.get(collection.name) ?? /* @__PURE__ */ new Map());
|
|
163
177
|
this.queryEmitters.set(collection.name, this.queryEmitters.get(collection.name) ?? new EventEmitter());
|
|
178
|
+
this.queryEmitters.get(collection.name)?.setMaxListeners(Infinity);
|
|
164
179
|
this.activeQueries.set(collection.name, this.activeQueries.get(collection.name) || /* @__PURE__ */ new Map());
|
|
165
180
|
this.indices.set(collection.name, indices.map((field) => createIndex(field)));
|
|
166
181
|
this.rebuildIndices(collection);
|
|
@@ -206,7 +221,7 @@ class DefaultDataAdapter {
|
|
|
206
221
|
},
|
|
207
222
|
updateMany: async (selector, modifier) => {
|
|
208
223
|
const { $setOnInsert, ...restModifier } = modifier;
|
|
209
|
-
const items =
|
|
224
|
+
const items = this.executeQuery(collection, selector, {});
|
|
210
225
|
const changedItems = items.map((item) => {
|
|
211
226
|
const modifiedItem = modify(deepClone(item), restModifier);
|
|
212
227
|
const hasItemWithSameId = item.id !== modifiedItem.id && this.getItem(collection, { id: modifiedItem.id }) != null;
|
|
@@ -262,7 +277,7 @@ class DefaultDataAdapter {
|
|
|
262
277
|
return [item];
|
|
263
278
|
},
|
|
264
279
|
removeMany: async (selector) => {
|
|
265
|
-
const items = backend.getQueryResult(selector);
|
|
280
|
+
const items = backend.getQueryResult(selector, {});
|
|
266
281
|
items.forEach((item) => {
|
|
267
282
|
this.items.get(collection.name)?.delete(serializeValue(item.id));
|
|
268
283
|
});
|
|
@@ -282,10 +297,7 @@ class DefaultDataAdapter {
|
|
|
282
297
|
selector,
|
|
283
298
|
options
|
|
284
299
|
});
|
|
285
|
-
|
|
286
|
-
if (!emitter)
|
|
287
|
-
throw new Error(`Query emitter not found for collection ${collection.name}`);
|
|
288
|
-
emitter.emit("change", selector, options, "complete");
|
|
300
|
+
this.executeAndCacheQuery(collection, selector, options);
|
|
289
301
|
},
|
|
290
302
|
unregisterQuery: (selector, options) => {
|
|
291
303
|
if (!this.activeQueries.get(collection.name))
|
|
@@ -298,7 +310,7 @@ class DefaultDataAdapter {
|
|
|
298
310
|
if (!emitter)
|
|
299
311
|
throw new Error(`Query emitter not found for collection ${collection.name}`);
|
|
300
312
|
const handler = (querySelector, queryOptions, state) => {
|
|
301
|
-
if (querySelector !== selector
|
|
313
|
+
if (queryId(querySelector, queryOptions) !== queryId(selector, options))
|
|
302
314
|
return;
|
|
303
315
|
callback(state);
|
|
304
316
|
};
|
|
@@ -309,14 +321,16 @@ class DefaultDataAdapter {
|
|
|
309
321
|
},
|
|
310
322
|
getQueryError: () => null,
|
|
311
323
|
getQueryResult: (selector, options) => {
|
|
312
|
-
const result = this.executeQuery(collection, selector, options);
|
|
313
324
|
const isQueryActive = this.activeQueries.get(collection.name)?.has(queryId(selector, options));
|
|
314
325
|
if (isQueryActive) {
|
|
315
|
-
|
|
316
|
-
|
|
326
|
+
const results = this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options));
|
|
327
|
+
if (!results)
|
|
328
|
+
throw new Error("Cached query results are not defined!");
|
|
329
|
+
return results;
|
|
317
330
|
}
|
|
318
|
-
return
|
|
331
|
+
return this.executeQuery(collection, selector, options);
|
|
319
332
|
},
|
|
333
|
+
executeQuery: (selector, options) => Promise.resolve(this.executeQuery(collection, selector, options)),
|
|
320
334
|
// lifecycle methods
|
|
321
335
|
dispose: async () => {
|
|
322
336
|
const adapter = this.storageAdapters.get(collection.name);
|