@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.
Files changed (104) hide show
  1. package/dist/.vite/manifest.json +118 -84
  2. package/dist/AsyncDataAdapter.d.ts +1 -1
  3. package/dist/index.cjs.js +33 -34
  4. package/dist/index.mjs +17 -35
  5. package/dist/index10.cjs.js +23 -0
  6. package/dist/index10.mjs +21 -17
  7. package/dist/index11.cjs.js +45 -0
  8. package/dist/index11.mjs +44 -15
  9. package/dist/index12.cjs.js +22 -0
  10. package/dist/index12.mjs +21 -47
  11. package/dist/index13.cjs.js +45 -0
  12. package/dist/index13.mjs +44 -365
  13. package/dist/index14.cjs.js +86 -0
  14. package/dist/index14.mjs +85 -416
  15. package/dist/index15.cjs.js +15 -0
  16. package/dist/index15.mjs +14 -206
  17. package/dist/index16.cjs.js +136 -0
  18. package/dist/index16.mjs +135 -388
  19. package/dist/index17.cjs.js +47 -0
  20. package/dist/index17.mjs +45 -578
  21. package/dist/index18.cjs.js +15 -0
  22. package/dist/index18.mjs +14 -157
  23. package/dist/index19.cjs.js +23 -0
  24. package/dist/index19.mjs +22 -26
  25. package/dist/index2.cjs.js +33 -0
  26. package/dist/index2.mjs +32 -258
  27. package/dist/index20.cjs.js +37 -0
  28. package/dist/index20.mjs +36 -41
  29. package/dist/index21.cjs.js +35 -0
  30. package/dist/index21.mjs +34 -16
  31. package/dist/index22.cjs.js +25 -0
  32. package/dist/index22.mjs +24 -104
  33. package/dist/index23.cjs.js +19 -0
  34. package/dist/index23.mjs +18 -128
  35. package/dist/index24.cjs.js +342 -0
  36. package/dist/index24.mjs +340 -6
  37. package/dist/index25.cjs.js +519 -0
  38. package/dist/index25.mjs +518 -27
  39. package/dist/index26.cjs.js +11 -0
  40. package/dist/index26.mjs +10 -10
  41. package/dist/index27.cjs.js +11 -0
  42. package/dist/index27.mjs +10 -29
  43. package/dist/index28.cjs.js +90 -0
  44. package/dist/index28.mjs +88 -46
  45. package/dist/index29.cjs.js +370 -0
  46. package/dist/index29.mjs +369 -8
  47. package/dist/index3.cjs.js +19 -0
  48. package/dist/index3.mjs +18 -539
  49. package/dist/index30.cjs.js +72 -0
  50. package/dist/index30.mjs +71 -9
  51. package/dist/index31.cjs.js +191 -0
  52. package/dist/index31.mjs +190 -7
  53. package/dist/index32.cjs.js +21 -0
  54. package/dist/index32.mjs +20 -42
  55. package/dist/index33.cjs.js +336 -0
  56. package/dist/index33.mjs +335 -29
  57. package/dist/index34.cjs.js +539 -0
  58. package/dist/index34.mjs +537 -4
  59. package/dist/index4.cjs.js +150 -0
  60. package/dist/index4.mjs +149 -5
  61. package/dist/index5.cjs.js +254 -0
  62. package/dist/index5.mjs +252 -4
  63. package/dist/index6.cjs.js +125 -0
  64. package/dist/index6.mjs +124 -29
  65. package/dist/index7.cjs.js +33 -0
  66. package/dist/index7.mjs +32 -12
  67. package/dist/index8.cjs.js +12 -0
  68. package/dist/index8.mjs +10 -4
  69. package/dist/index9.cjs.js +11 -0
  70. package/dist/index9.mjs +10 -133
  71. package/package.json +1 -1
  72. package/dist/index.cjs10.js +0 -18
  73. package/dist/index.cjs11.js +0 -15
  74. package/dist/index.cjs12.js +0 -48
  75. package/dist/index.cjs13.js +0 -365
  76. package/dist/index.cjs14.js +0 -416
  77. package/dist/index.cjs15.js +0 -206
  78. package/dist/index.cjs16.js +0 -388
  79. package/dist/index.cjs17.js +0 -579
  80. package/dist/index.cjs18.js +0 -157
  81. package/dist/index.cjs19.js +0 -26
  82. package/dist/index.cjs2.js +0 -259
  83. package/dist/index.cjs20.js +0 -42
  84. package/dist/index.cjs21.js +0 -16
  85. package/dist/index.cjs22.js +0 -104
  86. package/dist/index.cjs23.js +0 -129
  87. package/dist/index.cjs24.js +0 -7
  88. package/dist/index.cjs25.js +0 -27
  89. package/dist/index.cjs26.js +0 -10
  90. package/dist/index.cjs27.js +0 -29
  91. package/dist/index.cjs28.js +0 -46
  92. package/dist/index.cjs29.js +0 -8
  93. package/dist/index.cjs3.js +0 -540
  94. package/dist/index.cjs30.js +0 -9
  95. package/dist/index.cjs31.js +0 -7
  96. package/dist/index.cjs32.js +0 -42
  97. package/dist/index.cjs33.js +0 -29
  98. package/dist/index.cjs34.js +0 -5
  99. package/dist/index.cjs4.js +0 -5
  100. package/dist/index.cjs5.js +0 -5
  101. package/dist/index.cjs6.js +0 -29
  102. package/dist/index.cjs7.js +0 -12
  103. package/dist/index.cjs8.js +0 -5
  104. package/dist/index.cjs9.js +0 -133
package/dist/index11.mjs CHANGED
@@ -1,16 +1,45 @@
1
- function serializeValue(value) {
2
- if (value == null)
3
- return null;
4
- if (typeof value === "string")
5
- return value;
6
- if (typeof value === "number")
7
- return value.toString();
8
- if (typeof value === "boolean")
9
- return value.toString();
10
- if (value instanceof Date)
11
- return value.toISOString();
12
- return JSON.stringify(value);
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
- export {
15
- serializeValue as default
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
- function unwrap(value) {
2
- return (function* () {
3
- return yield value;
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
- function isThenable(value) {
7
- return typeof value === "object" && value !== null && typeof value.then === "function";
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 createIndex from "./index22.mjs";
2
- import getIndexInfo from "./index23.mjs";
3
- import deepClone from "./index20.mjs";
4
- import EventEmitter from "./index9.mjs";
5
- import isEqual from "./index6.mjs";
6
- import match from "./index24.mjs";
7
- import modify from "./index7.mjs";
8
- import project from "./index25.mjs";
9
- import queryId from "./index21.mjs";
10
- import serializeValue from "./index11.mjs";
11
- import sortItems from "./index26.mjs";
12
- function hasPendingUpdates(pendingUpdates) {
13
- return pendingUpdates.added.length > 0 || pendingUpdates.modified.length > 0 || pendingUpdates.removed.length > 0;
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
- class DefaultDataAdapter {
16
- items = /* @__PURE__ */ new Map();
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 };