@signaldb/core 2.0.0-beta.6 → 2.0.0-beta.7
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 +118 -84
- package/dist/AsyncDataAdapter.d.ts +1 -1
- package/dist/index.cjs.js +33 -34
- package/dist/index.mjs +17 -35
- package/dist/index10.cjs.js +23 -0
- package/dist/index10.mjs +21 -17
- package/dist/index11.cjs.js +45 -0
- package/dist/index11.mjs +44 -15
- package/dist/index12.cjs.js +22 -0
- package/dist/index12.mjs +21 -47
- package/dist/index13.cjs.js +45 -0
- package/dist/index13.mjs +44 -365
- package/dist/index14.cjs.js +86 -0
- package/dist/index14.mjs +85 -416
- package/dist/index15.cjs.js +15 -0
- package/dist/index15.mjs +14 -206
- package/dist/index16.cjs.js +136 -0
- package/dist/index16.mjs +135 -388
- package/dist/index17.cjs.js +47 -0
- package/dist/index17.mjs +45 -578
- package/dist/index18.cjs.js +15 -0
- package/dist/index18.mjs +14 -157
- package/dist/index19.cjs.js +23 -0
- package/dist/index19.mjs +22 -26
- package/dist/index2.cjs.js +33 -0
- package/dist/index2.mjs +32 -258
- package/dist/index20.cjs.js +37 -0
- package/dist/index20.mjs +36 -41
- package/dist/index21.cjs.js +35 -0
- package/dist/index21.mjs +34 -16
- package/dist/index22.cjs.js +25 -0
- package/dist/index22.mjs +24 -104
- package/dist/index23.cjs.js +19 -0
- package/dist/index23.mjs +18 -128
- package/dist/index24.cjs.js +342 -0
- package/dist/index24.mjs +340 -6
- package/dist/index25.cjs.js +519 -0
- package/dist/index25.mjs +518 -27
- package/dist/index26.cjs.js +11 -0
- package/dist/index26.mjs +10 -10
- package/dist/index27.cjs.js +11 -0
- package/dist/index27.mjs +10 -29
- package/dist/index28.cjs.js +90 -0
- package/dist/index28.mjs +88 -46
- package/dist/index29.cjs.js +370 -0
- package/dist/index29.mjs +369 -8
- package/dist/index3.cjs.js +19 -0
- package/dist/index3.mjs +18 -539
- package/dist/index30.cjs.js +72 -0
- package/dist/index30.mjs +71 -9
- package/dist/index31.cjs.js +191 -0
- package/dist/index31.mjs +190 -7
- package/dist/index32.cjs.js +21 -0
- package/dist/index32.mjs +20 -42
- package/dist/index33.cjs.js +336 -0
- package/dist/index33.mjs +335 -29
- package/dist/index34.cjs.js +539 -0
- package/dist/index34.mjs +537 -4
- package/dist/index4.cjs.js +150 -0
- package/dist/index4.mjs +149 -5
- package/dist/index5.cjs.js +254 -0
- package/dist/index5.mjs +252 -4
- package/dist/index6.cjs.js +125 -0
- package/dist/index6.mjs +124 -29
- package/dist/index7.cjs.js +33 -0
- package/dist/index7.mjs +32 -12
- package/dist/index8.cjs.js +12 -0
- package/dist/index8.mjs +10 -4
- package/dist/index9.cjs.js +11 -0
- package/dist/index9.mjs +10 -133
- package/package.json +1 -1
- package/dist/index.cjs10.js +0 -18
- package/dist/index.cjs11.js +0 -15
- package/dist/index.cjs12.js +0 -48
- package/dist/index.cjs13.js +0 -365
- package/dist/index.cjs14.js +0 -416
- package/dist/index.cjs15.js +0 -206
- package/dist/index.cjs16.js +0 -388
- package/dist/index.cjs17.js +0 -579
- package/dist/index.cjs18.js +0 -157
- package/dist/index.cjs19.js +0 -26
- package/dist/index.cjs2.js +0 -259
- package/dist/index.cjs20.js +0 -42
- package/dist/index.cjs21.js +0 -16
- package/dist/index.cjs22.js +0 -104
- package/dist/index.cjs23.js +0 -129
- package/dist/index.cjs24.js +0 -7
- package/dist/index.cjs25.js +0 -27
- package/dist/index.cjs26.js +0 -10
- package/dist/index.cjs27.js +0 -29
- package/dist/index.cjs28.js +0 -46
- package/dist/index.cjs29.js +0 -8
- package/dist/index.cjs3.js +0 -540
- package/dist/index.cjs30.js +0 -9
- package/dist/index.cjs31.js +0 -7
- package/dist/index.cjs32.js +0 -42
- package/dist/index.cjs33.js +0 -29
- package/dist/index.cjs34.js +0 -5
- package/dist/index.cjs4.js +0 -5
- package/dist/index.cjs5.js +0 -5
- package/dist/index.cjs6.js +0 -29
- package/dist/index.cjs7.js +0 -12
- package/dist/index.cjs8.js +0 -5
- package/dist/index.cjs9.js +0 -133
package/dist/index11.mjs
CHANGED
|
@@ -1,16 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
//#region src/utils/isFieldExpression.ts
|
|
2
|
+
var expressionKeys = new Set([
|
|
3
|
+
"$eq",
|
|
4
|
+
"$gt",
|
|
5
|
+
"$gte",
|
|
6
|
+
"$lt",
|
|
7
|
+
"$lte",
|
|
8
|
+
"$in",
|
|
9
|
+
"$nin",
|
|
10
|
+
"$ne",
|
|
11
|
+
"$exists",
|
|
12
|
+
"$not",
|
|
13
|
+
"$expr",
|
|
14
|
+
"$jsonSchema",
|
|
15
|
+
"$mod",
|
|
16
|
+
"$regex",
|
|
17
|
+
"$options",
|
|
18
|
+
"$text",
|
|
19
|
+
"$where",
|
|
20
|
+
"$all",
|
|
21
|
+
"$elemMatch",
|
|
22
|
+
"$size",
|
|
23
|
+
"$bitsAllClear",
|
|
24
|
+
"$bitsAllSet",
|
|
25
|
+
"$bitsAnyClear",
|
|
26
|
+
"$bitsAnySet"
|
|
27
|
+
]);
|
|
28
|
+
/**
|
|
29
|
+
* Determines whether a given object is a valid field expression.
|
|
30
|
+
* A field expression is an object containing query operators supported by MongoDB-style queries.
|
|
31
|
+
* @template T - The type of the field expression.
|
|
32
|
+
* @param expression - The object to test.
|
|
33
|
+
* @returns A boolean indicating whether the object is a valid field expression.
|
|
34
|
+
* - `true` if the object contains only recognized query operators.
|
|
35
|
+
* - `false` otherwise.
|
|
36
|
+
*/
|
|
37
|
+
function isFieldExpression(expression) {
|
|
38
|
+
if (typeof expression !== "object" || expression == null) return false;
|
|
39
|
+
const keys = Object.keys(expression);
|
|
40
|
+
if (keys.length === 0) return false;
|
|
41
|
+
if (keys.some((key) => !expressionKeys.has(key))) return false;
|
|
42
|
+
return keys.every((key) => expressionKeys.has(key));
|
|
13
43
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { isFieldExpression as default };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/utils/serializeValue.ts
|
|
2
|
+
/**
|
|
3
|
+
* Serializes a value into a string representation.
|
|
4
|
+
* Handles various types, including strings, numbers, booleans, dates, and objects.
|
|
5
|
+
* Falls back to JSON stringification for unsupported types.
|
|
6
|
+
* @param value - The value to serialize.
|
|
7
|
+
* - Strings are returned as-is.
|
|
8
|
+
* - Numbers and booleans are converted to their string representation.
|
|
9
|
+
* - Dates are converted to ISO string format.
|
|
10
|
+
* - Other values are stringified using `JSON.stringify`.
|
|
11
|
+
* @returns A string representation of the value.
|
|
12
|
+
*/
|
|
13
|
+
function serializeValue(value) {
|
|
14
|
+
if (value == null) return null;
|
|
15
|
+
if (typeof value === "string") return value;
|
|
16
|
+
if (typeof value === "number") return value.toString();
|
|
17
|
+
if (typeof value === "boolean") return value.toString();
|
|
18
|
+
if (value instanceof Date) return value.toISOString();
|
|
19
|
+
return JSON.stringify(value);
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
exports.default = serializeValue;
|
package/dist/index12.mjs
CHANGED
|
@@ -1,48 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
//#region src/utils/serializeValue.ts
|
|
2
|
+
/**
|
|
3
|
+
* Serializes a value into a string representation.
|
|
4
|
+
* Handles various types, including strings, numbers, booleans, dates, and objects.
|
|
5
|
+
* Falls back to JSON stringification for unsupported types.
|
|
6
|
+
* @param value - The value to serialize.
|
|
7
|
+
* - Strings are returned as-is.
|
|
8
|
+
* - Numbers and booleans are converted to their string representation.
|
|
9
|
+
* - Dates are converted to ISO string format.
|
|
10
|
+
* - Other values are stringified using `JSON.stringify`.
|
|
11
|
+
* @returns A string representation of the value.
|
|
12
|
+
*/
|
|
13
|
+
function serializeValue(value) {
|
|
14
|
+
if (value == null) return null;
|
|
15
|
+
if (typeof value === "string") return value;
|
|
16
|
+
if (typeof value === "number") return value.toString();
|
|
17
|
+
if (typeof value === "boolean") return value.toString();
|
|
18
|
+
if (value instanceof Date) return value.toISOString();
|
|
19
|
+
return JSON.stringify(value);
|
|
5
20
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
function runReactiveOrAsync(thisArgument, mode, gen) {
|
|
10
|
-
const a = !!mode?.async;
|
|
11
|
-
const it = gen.call(thisArgument, a);
|
|
12
|
-
if (!a) {
|
|
13
|
-
let step = it.next();
|
|
14
|
-
while (!step.done) {
|
|
15
|
-
const y = step.value;
|
|
16
|
-
if (isThenable(y))
|
|
17
|
-
throw new Error("Promise yielded in sync flow");
|
|
18
|
-
step = it.next(y);
|
|
19
|
-
}
|
|
20
|
-
return step.value;
|
|
21
|
-
}
|
|
22
|
-
return (async function() {
|
|
23
|
-
let step = it.next();
|
|
24
|
-
while (!step.done) {
|
|
25
|
-
const y = step.value;
|
|
26
|
-
const v = isThenable(y) ? await y : y;
|
|
27
|
-
step = it.next(v);
|
|
28
|
-
}
|
|
29
|
-
return step.value;
|
|
30
|
-
})();
|
|
31
|
-
}
|
|
32
|
-
function reactiveOrAsync(gen) {
|
|
33
|
-
function method(...allArguments) {
|
|
34
|
-
const last = allArguments.length > 0 ? allArguments.at(-1) : void 0;
|
|
35
|
-
const hasMode = typeof last === "object" && last !== null && "async" in last;
|
|
36
|
-
const mode = hasMode ? last : void 0;
|
|
37
|
-
const parameters = hasMode ? allArguments.slice(0, -1) : allArguments;
|
|
38
|
-
return runReactiveOrAsync(this, mode, function* (a) {
|
|
39
|
-
return yield* gen.call(this, a, ...parameters);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
method.generator = gen;
|
|
43
|
-
return method;
|
|
44
|
-
}
|
|
45
|
-
export {
|
|
46
|
-
reactiveOrAsync as default,
|
|
47
|
-
unwrap
|
|
48
|
-
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { serializeValue as default };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const require_isFieldExpression = require("./index11.cjs.js");
|
|
2
|
+
const require_serializeValue = require("./index12.cjs.js");
|
|
3
|
+
//#region src/utils/getMatchingKeys.ts
|
|
4
|
+
/**
|
|
5
|
+
* Extracts the matching and excluded keys for a given field in a selector.
|
|
6
|
+
* Supports serialized values and `$in`/`$nin` field expressions for optimization.
|
|
7
|
+
* Returns `null` for include/exclude if the field cannot be optimized.
|
|
8
|
+
* @template T - The type of the items in the selector.
|
|
9
|
+
* @template I - The type of the unique identifier for the items.
|
|
10
|
+
* @param field - The name of the field to extract matching keys for.
|
|
11
|
+
* @param selector - The selector object containing query criteria.
|
|
12
|
+
* @returns An object containing arrays of serialized included and excluded keys,
|
|
13
|
+
* or `null` if the field cannot be optimized.
|
|
14
|
+
*/
|
|
15
|
+
function getMatchingKeys(field, selector) {
|
|
16
|
+
const result = {
|
|
17
|
+
include: null,
|
|
18
|
+
exclude: null
|
|
19
|
+
};
|
|
20
|
+
const fieldSelector = selector[field];
|
|
21
|
+
if (fieldSelector instanceof RegExp) return result;
|
|
22
|
+
if (fieldSelector == null) return result;
|
|
23
|
+
if (require_isFieldExpression.default(fieldSelector)) {
|
|
24
|
+
if (fieldSelector.$ne != null) {
|
|
25
|
+
result.exclude = [require_serializeValue.default(fieldSelector.$ne)];
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
if (Array.isArray(fieldSelector.$in) && fieldSelector.$in.length > 0) {
|
|
29
|
+
result.include = fieldSelector.$in.map(require_serializeValue.default);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
if (Array.isArray(fieldSelector.$nin) && fieldSelector.$nin.length > 0) {
|
|
33
|
+
result.exclude = fieldSelector.$nin.map(require_serializeValue.default);
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
include: null,
|
|
38
|
+
exclude: null
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
result.include = [require_serializeValue.default(fieldSelector)];
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
exports.default = getMatchingKeys;
|
package/dist/index13.mjs
CHANGED
|
@@ -1,366 +1,45 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import isFieldExpression from "./index11.mjs";
|
|
2
|
+
import serializeValue from "./index12.mjs";
|
|
3
|
+
//#region src/utils/getMatchingKeys.ts
|
|
4
|
+
/**
|
|
5
|
+
* Extracts the matching and excluded keys for a given field in a selector.
|
|
6
|
+
* Supports serialized values and `$in`/`$nin` field expressions for optimization.
|
|
7
|
+
* Returns `null` for include/exclude if the field cannot be optimized.
|
|
8
|
+
* @template T - The type of the items in the selector.
|
|
9
|
+
* @template I - The type of the unique identifier for the items.
|
|
10
|
+
* @param field - The name of the field to extract matching keys for.
|
|
11
|
+
* @param selector - The selector object containing query criteria.
|
|
12
|
+
* @returns An object containing arrays of serialized included and excluded keys,
|
|
13
|
+
* or `null` if the field cannot be optimized.
|
|
14
|
+
*/
|
|
15
|
+
function getMatchingKeys(field, selector) {
|
|
16
|
+
const result = {
|
|
17
|
+
include: null,
|
|
18
|
+
exclude: null
|
|
19
|
+
};
|
|
20
|
+
const fieldSelector = selector[field];
|
|
21
|
+
if (fieldSelector instanceof RegExp) return result;
|
|
22
|
+
if (fieldSelector == null) return result;
|
|
23
|
+
if (isFieldExpression(fieldSelector)) {
|
|
24
|
+
if (fieldSelector.$ne != null) {
|
|
25
|
+
result.exclude = [serializeValue(fieldSelector.$ne)];
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
if (Array.isArray(fieldSelector.$in) && fieldSelector.$in.length > 0) {
|
|
29
|
+
result.include = fieldSelector.$in.map(serializeValue);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
if (Array.isArray(fieldSelector.$nin) && fieldSelector.$nin.length > 0) {
|
|
33
|
+
result.exclude = fieldSelector.$nin.map(serializeValue);
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
include: null,
|
|
38
|
+
exclude: null
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
result.include = [serializeValue(fieldSelector)];
|
|
42
|
+
return result;
|
|
14
43
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
options;
|
|
18
|
-
storageAdapters = /* @__PURE__ */ new Map();
|
|
19
|
-
collections = /* @__PURE__ */ new Set();
|
|
20
|
-
indices = /* @__PURE__ */ new Map();
|
|
21
|
-
activeQueries = /* @__PURE__ */ new Map();
|
|
22
|
-
queryEmitters = /* @__PURE__ */ new Map();
|
|
23
|
-
queuedQueryUpdates = /* @__PURE__ */ new Map();
|
|
24
|
-
cachedQueryResults = /* @__PURE__ */ new Map();
|
|
25
|
-
constructor(options) {
|
|
26
|
-
this.options = options || {};
|
|
27
|
-
}
|
|
28
|
-
ensureStorageAdapter(name) {
|
|
29
|
-
if (this.storageAdapters.get(name))
|
|
30
|
-
return;
|
|
31
|
-
if (!this.options.storage)
|
|
32
|
-
return;
|
|
33
|
-
const adapter = this.options.storage(name);
|
|
34
|
-
if (!adapter)
|
|
35
|
-
return;
|
|
36
|
-
this.storageAdapters.set(name, adapter);
|
|
37
|
-
}
|
|
38
|
-
rebuildIndices(collection) {
|
|
39
|
-
const items = this.items.get(collection.name);
|
|
40
|
-
if (!items)
|
|
41
|
-
throw new Error(`Items not found for collection ${collection.name}`);
|
|
42
|
-
const indices = this.indices.get(collection.name);
|
|
43
|
-
if (!indices)
|
|
44
|
-
throw new Error(`Indices not found for collection ${collection.name}`);
|
|
45
|
-
indices.forEach((index) => index.rebuild([...items.values()]));
|
|
46
|
-
}
|
|
47
|
-
async setupStorageAdapter(collection) {
|
|
48
|
-
const storageAdapter = this.storageAdapters.get(collection.name);
|
|
49
|
-
if (!storageAdapter)
|
|
50
|
-
return;
|
|
51
|
-
return storageAdapter.setup().then(async () => {
|
|
52
|
-
await this.fetchItemsFromStorage(collection);
|
|
53
|
-
}).catch((error) => {
|
|
54
|
-
if (!this.options.onError) {
|
|
55
|
-
console.error(`Error during data persistence operation in collection ${collection.name}`, error);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
this.options.onError(collection.name, error instanceof Error ? error : new Error(error));
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
getIndexInfo(collection, selector) {
|
|
62
|
-
if (selector != null && Object.keys(selector).length === 1 && "id" in selector && typeof selector.id !== "object") {
|
|
63
|
-
return {
|
|
64
|
-
matched: true,
|
|
65
|
-
ids: [serializeValue(selector.id)],
|
|
66
|
-
optimizedSelector: {}
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
if (selector == null) {
|
|
70
|
-
return {
|
|
71
|
-
matched: false,
|
|
72
|
-
ids: [],
|
|
73
|
-
optimizedSelector: {}
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
return getIndexInfo((this.indices.get(collection.name) ?? []).map((i) => i.query.bind(i)), selector);
|
|
77
|
-
}
|
|
78
|
-
applyIndexDeltas(collection, changes) {
|
|
79
|
-
const indices = this.indices.get(collection.name) ?? [];
|
|
80
|
-
for (const index of indices) {
|
|
81
|
-
if (changes.modified)
|
|
82
|
-
index.update(changes.modified);
|
|
83
|
-
if (changes.added && changes.added.length > 0)
|
|
84
|
-
index.insert(changes.added);
|
|
85
|
-
if (changes.removed && changes.removed.length > 0)
|
|
86
|
-
index.remove(changes.removed);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
getItem(collection, selector) {
|
|
90
|
-
const memory = this.items.get(collection.name) ?? /* @__PURE__ */ new Map();
|
|
91
|
-
const indexInfo = this.getIndexInfo(collection, selector);
|
|
92
|
-
const items = indexInfo.matched ? indexInfo.ids.map((id) => memory.get(serializeValue(id))).filter((i) => i != null) : [...memory.values()];
|
|
93
|
-
const item = items.find((document) => match(document, selector));
|
|
94
|
-
return item;
|
|
95
|
-
}
|
|
96
|
-
queryItems(collection, selector) {
|
|
97
|
-
const indexInfo = this.getIndexInfo(collection, selector);
|
|
98
|
-
const matchItems = (item) => {
|
|
99
|
-
if (indexInfo.optimizedSelector == null)
|
|
100
|
-
return true;
|
|
101
|
-
if (Object.keys(indexInfo.optimizedSelector).length <= 0)
|
|
102
|
-
return true;
|
|
103
|
-
const matches = match(item, indexInfo.optimizedSelector);
|
|
104
|
-
return matches;
|
|
105
|
-
};
|
|
106
|
-
const items = this.items.get(collection.name);
|
|
107
|
-
if (!indexInfo.matched) {
|
|
108
|
-
if (isEqual(selector, {}))
|
|
109
|
-
return [...items.values()];
|
|
110
|
-
return [...items.values()].filter(matchItems);
|
|
111
|
-
}
|
|
112
|
-
const foundItems = indexInfo.ids.map((ids) => items.get(serializeValue(ids))).filter((i) => i != null);
|
|
113
|
-
if (isEqual(indexInfo.optimizedSelector, {}))
|
|
114
|
-
return foundItems;
|
|
115
|
-
return foundItems.filter(matchItems);
|
|
116
|
-
}
|
|
117
|
-
executeQuery(collection, selector, options) {
|
|
118
|
-
const items = this.queryItems(collection, selector || {});
|
|
119
|
-
const { sort, skip, limit, fields } = options || {};
|
|
120
|
-
const sorted = sort ? sortItems(items, sort) : items;
|
|
121
|
-
const skipped = skip ? sorted.slice(skip) : sorted;
|
|
122
|
-
const limited = limit ? skipped.slice(0, limit) : skipped;
|
|
123
|
-
const idExcluded = fields && fields.id === 0;
|
|
124
|
-
return limited.map((item) => {
|
|
125
|
-
if (!fields)
|
|
126
|
-
return item;
|
|
127
|
-
return {
|
|
128
|
-
...idExcluded ? {} : { id: item.id },
|
|
129
|
-
...project(item, fields)
|
|
130
|
-
};
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
flushQueuedQueryUpdates(collection) {
|
|
134
|
-
if (!this.queuedQueryUpdates.get(collection.name))
|
|
135
|
-
return;
|
|
136
|
-
const changes = this.queuedQueryUpdates.get(collection.name);
|
|
137
|
-
if (!changes || !hasPendingUpdates(changes))
|
|
138
|
-
return;
|
|
139
|
-
this.queuedQueryUpdates.set(collection.name, { added: [], modified: [], removed: [] });
|
|
140
|
-
const flatItems = [...changes.added, ...changes.modified, ...changes.removed];
|
|
141
|
-
const itemIds = new Set(flatItems.map((i) => i.id));
|
|
142
|
-
const queries = [
|
|
143
|
-
...this.activeQueries.get(collection.name)?.values() ?? []
|
|
144
|
-
].filter(({ selector, options }) => {
|
|
145
|
-
const idsInQuery = this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options))?.map((i) => i.id) ?? [];
|
|
146
|
-
if (idsInQuery.some((id) => itemIds.has(id)))
|
|
147
|
-
return true;
|
|
148
|
-
return flatItems.some((item) => match(item, selector));
|
|
149
|
-
});
|
|
150
|
-
queries.forEach(({ selector, options }) => {
|
|
151
|
-
this.executeAndCacheQuery(collection, selector, options);
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
executeAndCacheQuery(collection, selector, options) {
|
|
155
|
-
const result = this.executeQuery(collection, selector, options);
|
|
156
|
-
this.cachedQueryResults.set(collection.name, this.cachedQueryResults.get(collection.name) || /* @__PURE__ */ new Map());
|
|
157
|
-
this.cachedQueryResults.get(collection.name)?.set(queryId(selector, options), result);
|
|
158
|
-
const emitter = this.queryEmitters.get(collection.name);
|
|
159
|
-
if (!emitter)
|
|
160
|
-
return;
|
|
161
|
-
emitter.emit("change", selector, options, "complete");
|
|
162
|
-
}
|
|
163
|
-
updateQueries(collection, changes) {
|
|
164
|
-
this.queuedQueryUpdates.set(collection.name, this.queuedQueryUpdates.get(collection.name) || { added: [], modified: [], removed: [] });
|
|
165
|
-
this.queuedQueryUpdates.get(collection.name)?.added.push(...changes.added);
|
|
166
|
-
this.queuedQueryUpdates.get(collection.name)?.modified.push(...changes.modified);
|
|
167
|
-
this.queuedQueryUpdates.get(collection.name)?.removed.push(...changes.removed);
|
|
168
|
-
this.flushQueuedQueryUpdates(collection);
|
|
169
|
-
}
|
|
170
|
-
createCollectionBackend(collection, indices) {
|
|
171
|
-
this.collections.add(collection);
|
|
172
|
-
this.ensureStorageAdapter(collection.name);
|
|
173
|
-
this.items.set(collection.name, this.items.get(collection.name) ?? /* @__PURE__ */ new Map());
|
|
174
|
-
this.queryEmitters.set(collection.name, this.queryEmitters.get(collection.name) ?? new EventEmitter());
|
|
175
|
-
this.queryEmitters.get(collection.name)?.setMaxListeners(Infinity);
|
|
176
|
-
this.activeQueries.set(collection.name, this.activeQueries.get(collection.name) || /* @__PURE__ */ new Map());
|
|
177
|
-
this.indices.set(collection.name, indices.map((field) => createIndex(field)));
|
|
178
|
-
this.rebuildIndices(collection);
|
|
179
|
-
const persistenceReadyPromise = this.setupStorageAdapter(collection);
|
|
180
|
-
const backend = {
|
|
181
|
-
// CRUD operations
|
|
182
|
-
insert: async (newItem) => {
|
|
183
|
-
const items = this.items.get(collection.name);
|
|
184
|
-
if (!items)
|
|
185
|
-
throw new Error(`Items not found for collection ${collection.name}`);
|
|
186
|
-
if (items.has(serializeValue(newItem.id))) {
|
|
187
|
-
throw new Error(`Item with id '${newItem.id}' already exists`);
|
|
188
|
-
}
|
|
189
|
-
this.items.get(collection.name)?.set(serializeValue(newItem.id), newItem);
|
|
190
|
-
await this.storageAdapters.get(collection.name)?.insert([newItem]);
|
|
191
|
-
this.applyIndexDeltas(collection, { added: [newItem] });
|
|
192
|
-
this.updateQueries(collection, {
|
|
193
|
-
added: [],
|
|
194
|
-
modified: [newItem],
|
|
195
|
-
removed: []
|
|
196
|
-
});
|
|
197
|
-
return newItem;
|
|
198
|
-
},
|
|
199
|
-
updateOne: async (selector, modifier) => {
|
|
200
|
-
const { $setOnInsert, ...restModifier } = modifier;
|
|
201
|
-
const item = this.getItem(collection, selector);
|
|
202
|
-
if (item == null)
|
|
203
|
-
return [];
|
|
204
|
-
const modifiedItem = modify(deepClone(item), restModifier);
|
|
205
|
-
const hasItemWithSameId = item.id !== modifiedItem.id && this.getItem(collection, { id: modifiedItem.id }) != null;
|
|
206
|
-
if (hasItemWithSameId) {
|
|
207
|
-
throw new Error(`Item with id '${modifiedItem.id}' already exists`);
|
|
208
|
-
}
|
|
209
|
-
this.items.get(collection.name)?.set(serializeValue(modifiedItem.id), modifiedItem);
|
|
210
|
-
await this.storageAdapters.get(collection.name)?.replace([modifiedItem]);
|
|
211
|
-
this.applyIndexDeltas(collection, { modified: [{ oldItem: item, newItem: modifiedItem }] });
|
|
212
|
-
this.updateQueries(collection, {
|
|
213
|
-
added: [],
|
|
214
|
-
modified: [modifiedItem],
|
|
215
|
-
removed: []
|
|
216
|
-
});
|
|
217
|
-
return [modifiedItem];
|
|
218
|
-
},
|
|
219
|
-
updateMany: async (selector, modifier) => {
|
|
220
|
-
const { $setOnInsert, ...restModifier } = modifier;
|
|
221
|
-
const items = this.executeQuery(collection, selector, {});
|
|
222
|
-
const changedItems = items.map((item) => {
|
|
223
|
-
const modifiedItem = modify(deepClone(item), restModifier);
|
|
224
|
-
const hasItemWithSameId = item.id !== modifiedItem.id && this.getItem(collection, { id: modifiedItem.id }) != null;
|
|
225
|
-
if (hasItemWithSameId) {
|
|
226
|
-
throw new Error(`Item with id '${modifiedItem.id}' already exists`);
|
|
227
|
-
}
|
|
228
|
-
return modifiedItem;
|
|
229
|
-
});
|
|
230
|
-
changedItems.forEach((item) => {
|
|
231
|
-
this.items.get(collection.name)?.set(serializeValue(item.id), item);
|
|
232
|
-
});
|
|
233
|
-
await this.storageAdapters.get(collection.name)?.replace(changedItems);
|
|
234
|
-
const pairs = items.map((oldItem, index) => ({ oldItem, newItem: changedItems[index] }));
|
|
235
|
-
this.applyIndexDeltas(collection, { modified: pairs });
|
|
236
|
-
this.updateQueries(collection, {
|
|
237
|
-
added: [],
|
|
238
|
-
modified: changedItems,
|
|
239
|
-
removed: []
|
|
240
|
-
});
|
|
241
|
-
return changedItems;
|
|
242
|
-
},
|
|
243
|
-
replaceOne: async (selector, replacement) => {
|
|
244
|
-
const item = this.getItem(collection, selector);
|
|
245
|
-
if (item == null)
|
|
246
|
-
return [];
|
|
247
|
-
const hasItemWithSameId = item.id !== replacement.id && replacement.id != null && this.getItem(collection, { id: replacement.id }) != null;
|
|
248
|
-
if (hasItemWithSameId) {
|
|
249
|
-
throw new Error(`Item with id '${replacement.id}' already exists`);
|
|
250
|
-
}
|
|
251
|
-
const modifiedItem = { id: item.id, ...replacement };
|
|
252
|
-
this.items.get(collection.name)?.set(serializeValue(modifiedItem.id), modifiedItem);
|
|
253
|
-
await this.storageAdapters.get(collection.name)?.replace([modifiedItem]);
|
|
254
|
-
this.applyIndexDeltas(collection, { modified: [{ oldItem: item, newItem: modifiedItem }] });
|
|
255
|
-
this.updateQueries(collection, {
|
|
256
|
-
added: [],
|
|
257
|
-
modified: [modifiedItem],
|
|
258
|
-
removed: []
|
|
259
|
-
});
|
|
260
|
-
return [modifiedItem];
|
|
261
|
-
},
|
|
262
|
-
removeOne: async (selector) => {
|
|
263
|
-
const item = this.getItem(collection, selector);
|
|
264
|
-
if (item == null)
|
|
265
|
-
return [];
|
|
266
|
-
this.items.get(collection.name)?.delete(serializeValue(item.id));
|
|
267
|
-
await this.storageAdapters.get(collection.name)?.remove([item]);
|
|
268
|
-
this.applyIndexDeltas(collection, { removed: [item] });
|
|
269
|
-
this.updateQueries(collection, {
|
|
270
|
-
added: [],
|
|
271
|
-
modified: [],
|
|
272
|
-
removed: [item]
|
|
273
|
-
});
|
|
274
|
-
return [item];
|
|
275
|
-
},
|
|
276
|
-
removeMany: async (selector) => {
|
|
277
|
-
const items = backend.getQueryResult(selector, {});
|
|
278
|
-
items.forEach((item) => {
|
|
279
|
-
this.items.get(collection.name)?.delete(serializeValue(item.id));
|
|
280
|
-
});
|
|
281
|
-
await this.storageAdapters.get(collection.name)?.remove(items);
|
|
282
|
-
this.applyIndexDeltas(collection, { removed: items });
|
|
283
|
-
this.updateQueries(collection, {
|
|
284
|
-
added: [],
|
|
285
|
-
modified: [],
|
|
286
|
-
removed: items
|
|
287
|
-
});
|
|
288
|
-
return items;
|
|
289
|
-
},
|
|
290
|
-
// methods for registering and unregistering queries that will be called from the collection during find/findOne
|
|
291
|
-
registerQuery: (selector, options) => {
|
|
292
|
-
this.activeQueries.set(collection.name, this.activeQueries.get(collection.name) || /* @__PURE__ */ new Map());
|
|
293
|
-
this.activeQueries.get(collection.name)?.set(queryId(selector, options), {
|
|
294
|
-
selector,
|
|
295
|
-
options
|
|
296
|
-
});
|
|
297
|
-
this.executeAndCacheQuery(collection, selector, options);
|
|
298
|
-
},
|
|
299
|
-
unregisterQuery: (selector, options) => {
|
|
300
|
-
if (!this.activeQueries.get(collection.name))
|
|
301
|
-
return;
|
|
302
|
-
this.activeQueries.get(collection.name)?.delete(queryId(selector, options));
|
|
303
|
-
},
|
|
304
|
-
getQueryState: () => "complete",
|
|
305
|
-
onQueryStateChange: (selector, options, callback) => {
|
|
306
|
-
const emitter = this.queryEmitters.get(collection.name);
|
|
307
|
-
if (!emitter)
|
|
308
|
-
throw new Error(`Query emitter not found for collection ${collection.name}`);
|
|
309
|
-
const handler = (querySelector, queryOptions, state) => {
|
|
310
|
-
if (queryId(querySelector, queryOptions) !== queryId(selector, options))
|
|
311
|
-
return;
|
|
312
|
-
callback(state);
|
|
313
|
-
};
|
|
314
|
-
emitter.on("change", handler);
|
|
315
|
-
return () => {
|
|
316
|
-
emitter.off("change", handler);
|
|
317
|
-
};
|
|
318
|
-
},
|
|
319
|
-
getQueryError: () => null,
|
|
320
|
-
getQueryResult: (selector, options) => {
|
|
321
|
-
const isQueryActive = this.activeQueries.get(collection.name)?.has(queryId(selector, options));
|
|
322
|
-
if (isQueryActive) {
|
|
323
|
-
const results = this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options));
|
|
324
|
-
if (!results)
|
|
325
|
-
throw new Error("Cached query results are not defined!");
|
|
326
|
-
return results;
|
|
327
|
-
}
|
|
328
|
-
return this.executeQuery(collection, selector, options);
|
|
329
|
-
},
|
|
330
|
-
executeQuery: (selector, options) => Promise.resolve(this.executeQuery(collection, selector, options)),
|
|
331
|
-
// lifecycle methods
|
|
332
|
-
dispose: async () => {
|
|
333
|
-
const adapter = this.storageAdapters.get(collection.name);
|
|
334
|
-
if (adapter?.teardown)
|
|
335
|
-
await adapter.teardown();
|
|
336
|
-
this.storageAdapters.delete(collection.name);
|
|
337
|
-
this.items.delete(collection.name);
|
|
338
|
-
this.indices.delete(collection.name);
|
|
339
|
-
this.activeQueries.delete(collection.name);
|
|
340
|
-
this.queryEmitters.delete(collection.name);
|
|
341
|
-
this.queuedQueryUpdates.delete(collection.name);
|
|
342
|
-
this.cachedQueryResults.delete(collection.name);
|
|
343
|
-
},
|
|
344
|
-
isReady: () => persistenceReadyPromise
|
|
345
|
-
};
|
|
346
|
-
return backend;
|
|
347
|
-
}
|
|
348
|
-
async fetchItemsFromStorage(collection) {
|
|
349
|
-
if (!collection) {
|
|
350
|
-
await Promise.all([...this.collections].map((currentCollection) => this.fetchItemsFromStorage(currentCollection)));
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
const storageAdapter = this.storageAdapters.get(collection.name);
|
|
354
|
-
if (!storageAdapter)
|
|
355
|
-
return;
|
|
356
|
-
const items = await storageAdapter.readAll();
|
|
357
|
-
this.items.set(collection.name, items.reduce((map, item) => {
|
|
358
|
-
map.set(serializeValue(item.id), item);
|
|
359
|
-
return map;
|
|
360
|
-
}, /* @__PURE__ */ new Map()));
|
|
361
|
-
this.rebuildIndices(collection);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
export {
|
|
365
|
-
DefaultDataAdapter as default
|
|
366
|
-
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { getMatchingKeys as default };
|