@signaldb/svelte 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/base/core/src/AsyncDataAdapter.d.ts +64 -0
- package/dist/base/core/src/AsyncDataAdapter.js +450 -0
- package/dist/base/core/src/AutoFetchDataAdapter.d.ts +112 -0
- package/dist/base/core/src/AutoFetchDataAdapter.js +652 -0
- package/dist/base/core/src/Collection/Cursor.d.ts +113 -0
- package/dist/base/core/src/Collection/Cursor.js +293 -0
- package/dist/base/core/src/Collection/Observer.d.ts +64 -0
- package/dist/base/core/src/Collection/Observer.js +181 -0
- package/dist/base/core/src/Collection/index.d.ts +294 -0
- package/dist/base/core/src/Collection/index.js +580 -0
- package/dist/base/core/src/Collection/types.d.ts +28 -0
- package/dist/base/core/src/Collection/types.js +2 -0
- package/dist/base/core/src/DataAdapter.d.ts +35 -0
- package/dist/base/core/src/DataAdapter.js +2 -0
- package/dist/base/core/src/DefaultDataAdapter.d.ts +35 -0
- package/dist/base/core/src/DefaultDataAdapter.js +398 -0
- package/dist/base/core/src/WorkerDataAdapter.d.ts +25 -0
- package/dist/base/core/src/WorkerDataAdapter.js +211 -0
- package/dist/base/core/src/WorkerDataAdapterHost.d.ts +62 -0
- package/dist/base/core/src/WorkerDataAdapterHost.js +409 -0
- package/dist/base/core/src/createIndex.d.ts +7 -0
- package/dist/base/core/src/createIndex.js +120 -0
- package/dist/base/core/src/createIndexProvider.d.ts +8 -0
- package/dist/base/core/src/createIndexProvider.js +11 -0
- package/dist/base/core/src/createReactivityAdapter.d.ts +8 -0
- package/dist/base/core/src/createReactivityAdapter.js +11 -0
- package/dist/base/core/src/createStorageAdapter.d.ts +9 -0
- package/dist/base/core/src/createStorageAdapter.js +11 -0
- package/dist/base/core/src/getIndexInfo.d.ts +39 -0
- package/dist/base/core/src/getIndexInfo.js +176 -0
- package/dist/base/core/src/index.d.ts +22 -0
- package/dist/base/core/src/index.js +39 -0
- package/dist/base/core/src/types/Dependency.d.ts +4 -0
- package/dist/base/core/src/types/Dependency.js +2 -0
- package/dist/base/core/src/types/IndexProvider.d.ts +26 -0
- package/dist/base/core/src/types/IndexProvider.js +2 -0
- package/dist/base/core/src/types/Modifier.d.ts +46 -0
- package/dist/base/core/src/types/Modifier.js +3 -0
- package/dist/base/core/src/types/ReactivityAdapter.d.ts +6 -0
- package/dist/base/core/src/types/ReactivityAdapter.js +2 -0
- package/dist/base/core/src/types/Selector.d.ts +46 -0
- package/dist/base/core/src/types/Selector.js +3 -0
- package/dist/base/core/src/types/Signal.d.ts +4 -0
- package/dist/base/core/src/types/Signal.js +2 -0
- package/dist/base/core/src/types/StorageAdapter.d.ts +20 -0
- package/dist/base/core/src/types/StorageAdapter.js +2 -0
- package/dist/base/core/src/utils/EventEmitter.d.ts +71 -0
- package/dist/base/core/src/utils/EventEmitter.js +144 -0
- package/dist/base/core/src/utils/batchOnNextTick.d.ts +16 -0
- package/dist/base/core/src/utils/batchOnNextTick.js +72 -0
- package/dist/base/core/src/utils/compact.d.ts +9 -0
- package/dist/base/core/src/utils/compact.js +21 -0
- package/dist/base/core/src/utils/createSignal.d.ts +14 -0
- package/dist/base/core/src/utils/createSignal.js +38 -0
- package/dist/base/core/src/utils/deepClone.d.ts +17 -0
- package/dist/base/core/src/utils/deepClone.js +68 -0
- package/dist/base/core/src/utils/get.d.ts +9 -0
- package/dist/base/core/src/utils/get.js +27 -0
- package/dist/base/core/src/utils/getMatchingKeys.d.ts +19 -0
- package/dist/base/core/src/utils/getMatchingKeys.js +49 -0
- package/dist/base/core/src/utils/intersection.d.ts +9 -0
- package/dist/base/core/src/utils/intersection.js +16 -0
- package/dist/base/core/src/utils/isEqual.d.ts +14 -0
- package/dist/base/core/src/utils/isEqual.js +43 -0
- package/dist/base/core/src/utils/isFieldExpression.d.ts +11 -0
- package/dist/base/core/src/utils/isFieldExpression.js +52 -0
- package/dist/base/core/src/utils/match.d.ts +12 -0
- package/dist/base/core/src/utils/match.js +16 -0
- package/dist/base/core/src/utils/modify.d.ts +14 -0
- package/dist/base/core/src/utils/modify.js +29 -0
- package/dist/base/core/src/utils/project.d.ts +15 -0
- package/dist/base/core/src/utils/project.js +43 -0
- package/dist/base/core/src/utils/queryId.d.ts +9 -0
- package/dist/base/core/src/utils/queryId.js +30 -0
- package/dist/base/core/src/utils/randomId.d.ts +7 -0
- package/dist/base/core/src/utils/randomId.js +12 -0
- package/dist/base/core/src/utils/reactiveOrAsync.d.ts +59 -0
- package/dist/base/core/src/utils/reactiveOrAsync.js +93 -0
- package/dist/base/core/src/utils/serializeValue.d.ts +12 -0
- package/dist/base/core/src/utils/serializeValue.js +27 -0
- package/dist/base/core/src/utils/set.d.ts +13 -0
- package/dist/base/core/src/utils/set.js +43 -0
- package/dist/base/core/src/utils/sortItems.d.ts +12 -0
- package/dist/base/core/src/utils/sortItems.js +23 -0
- package/dist/base/core/src/utils/uniqueBy.d.ts +10 -0
- package/dist/base/core/src/utils/uniqueBy.js +19 -0
- package/dist/reactivity-adapters/svelte/index.svelte.d.ts +10 -0
- package/dist/reactivity-adapters/svelte/index.svelte.js +36 -0
- package/package.json +3 -3
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { BaseItem } from './Collection';
|
|
2
|
+
import type { QueryOptions } from './DataAdapter';
|
|
3
|
+
import type Modifier from './types/Modifier';
|
|
4
|
+
import type StorageAdapter from './types/StorageAdapter';
|
|
5
|
+
import type Selector from './types/Selector';
|
|
6
|
+
interface WorkerContext {
|
|
7
|
+
addEventListener: (type: 'message', listener: (event: MessageEvent) => any) => void;
|
|
8
|
+
postMessage: (message: any) => void;
|
|
9
|
+
}
|
|
10
|
+
interface WorkerDataAdapterHostOptions {
|
|
11
|
+
id?: string;
|
|
12
|
+
storage: (name: string) => StorageAdapter<any, any>;
|
|
13
|
+
onError?: (error: Error) => void;
|
|
14
|
+
log?: (message: string, ...args: any[]) => void;
|
|
15
|
+
}
|
|
16
|
+
type CollectionMethods<T extends BaseItem<I>, I = any> = {
|
|
17
|
+
registerCollection: (collectionName: string, indices: string[]) => Promise<void>;
|
|
18
|
+
unregisterCollection: (collectionName: string) => Promise<void>;
|
|
19
|
+
registerQuery: <O extends QueryOptions<T>>(collectionName: string, selector: Selector<T>, options?: O) => Promise<void>;
|
|
20
|
+
unregisterQuery: <O extends QueryOptions<T>>(collectionName: string, selector: Selector<T>, options?: O) => Promise<void>;
|
|
21
|
+
executeQuery: <O extends QueryOptions<T>>(collectionName: string, selector: Selector<T>, options?: O) => Promise<T[]>;
|
|
22
|
+
insert: (collectionName: string, items: [T][]) => Promise<(T | Error)[]>;
|
|
23
|
+
updateOne: (collectionName: string, args: [Selector<T>, Modifier<T>][]) => Promise<(T[] | Error)[]>;
|
|
24
|
+
updateMany: (collectionName: string, args: [Selector<T>, Modifier<T>][]) => Promise<(T[] | Error)[]>;
|
|
25
|
+
replaceOne: (collectionName: string, args: [Selector<T>, Omit<T, 'id'> & Partial<Pick<T, 'id'>>][]) => Promise<(T[] | Error)[]>;
|
|
26
|
+
removeOne: (collectionName: string, selectors: [Selector<T>][]) => Promise<(T[] | Error)[]>;
|
|
27
|
+
removeMany: (collectionName: string, selectors: [Selector<T>][]) => Promise<(T[] | Error)[]>;
|
|
28
|
+
isReady: (collectionName: string) => Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
export default class WorkerDataAdapterHost<T extends BaseItem<I>, I = any> {
|
|
31
|
+
private workerContext;
|
|
32
|
+
private options;
|
|
33
|
+
private id;
|
|
34
|
+
private log;
|
|
35
|
+
private storageAdapters;
|
|
36
|
+
private storageAdapterReady;
|
|
37
|
+
private collectionIndices;
|
|
38
|
+
private queries;
|
|
39
|
+
private onError;
|
|
40
|
+
constructor(workerContext: WorkerContext, options: WorkerDataAdapterHostOptions);
|
|
41
|
+
private respond;
|
|
42
|
+
private handleMessage;
|
|
43
|
+
private getIndexInfo;
|
|
44
|
+
private queryItems;
|
|
45
|
+
private executeQuery;
|
|
46
|
+
private ensureQuery;
|
|
47
|
+
private emitQueryUpdate;
|
|
48
|
+
private ensureStorageAdapter;
|
|
49
|
+
private checkQueryUpdates;
|
|
50
|
+
protected registerCollection: CollectionMethods<T, I>['registerCollection'];
|
|
51
|
+
protected unregisterCollection: CollectionMethods<T, I>['unregisterCollection'];
|
|
52
|
+
protected registerQuery: CollectionMethods<T, I>['registerQuery'];
|
|
53
|
+
protected unregisterQuery: CollectionMethods<T, I>['unregisterQuery'];
|
|
54
|
+
protected insert: CollectionMethods<T, I>['insert'];
|
|
55
|
+
protected updateOne: CollectionMethods<T, I>['updateOne'];
|
|
56
|
+
protected updateMany: CollectionMethods<T, I>['updateMany'];
|
|
57
|
+
protected replaceOne: CollectionMethods<T, I>['replaceOne'];
|
|
58
|
+
protected removeOne: CollectionMethods<T, I>['removeOne'];
|
|
59
|
+
protected removeMany: CollectionMethods<T, I>['removeMany'];
|
|
60
|
+
protected isReady: CollectionMethods<T, I>['isReady'];
|
|
61
|
+
}
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const deepClone_1 = __importDefault(require("./utils/deepClone"));
|
|
7
|
+
const match_1 = __importDefault(require("./utils/match"));
|
|
8
|
+
const modify_1 = __importDefault(require("./utils/modify"));
|
|
9
|
+
const queryId_1 = __importDefault(require("./utils/queryId"));
|
|
10
|
+
const isEqual_1 = __importDefault(require("./utils/isEqual"));
|
|
11
|
+
const getIndexInfo_1 = __importDefault(require("./getIndexInfo"));
|
|
12
|
+
const getMatchingKeys_1 = __importDefault(require("./utils/getMatchingKeys"));
|
|
13
|
+
const sortItems_1 = __importDefault(require("./utils/sortItems"));
|
|
14
|
+
const project_1 = __importDefault(require("./utils/project"));
|
|
15
|
+
const compact_1 = __importDefault(require("./utils/compact"));
|
|
16
|
+
class WorkerDataAdapterHost {
|
|
17
|
+
workerContext;
|
|
18
|
+
options;
|
|
19
|
+
id;
|
|
20
|
+
log = () => { };
|
|
21
|
+
storageAdapters = new Map();
|
|
22
|
+
storageAdapterReady = new Map();
|
|
23
|
+
collectionIndices = new Map();
|
|
24
|
+
queries = new Map();
|
|
25
|
+
onError = (error) => {
|
|
26
|
+
// eslint-disable-next-line no-console
|
|
27
|
+
console.error(error);
|
|
28
|
+
};
|
|
29
|
+
constructor(workerContext, options) {
|
|
30
|
+
this.workerContext = workerContext;
|
|
31
|
+
this.options = options;
|
|
32
|
+
this.id = this.options.id || 'default-worker-data-adapter';
|
|
33
|
+
if (this.options.onError) {
|
|
34
|
+
this.onError = this.options.onError;
|
|
35
|
+
}
|
|
36
|
+
if (this.options.log)
|
|
37
|
+
this.log = this.options.log;
|
|
38
|
+
if (typeof addEventListener === 'undefined' || typeof postMessage === 'undefined') {
|
|
39
|
+
throw new TypeError('WorkerDataAdapterHost can only be used in a Web Worker context');
|
|
40
|
+
}
|
|
41
|
+
this.workerContext.addEventListener('message', async (event) => {
|
|
42
|
+
try {
|
|
43
|
+
const { workerId, id, method, args } = event.data;
|
|
44
|
+
await this.handleMessage(workerId, id, method, args);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
this.onError(error);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
this.respond('ready', null, null, 'ready');
|
|
51
|
+
}
|
|
52
|
+
respond(id, data, error = null, type = 'response') {
|
|
53
|
+
this.workerContext.postMessage({ id, workerId: this.id, type, data, error });
|
|
54
|
+
}
|
|
55
|
+
async handleMessage(workerId, id, method, args) {
|
|
56
|
+
if (workerId !== this.id)
|
|
57
|
+
return;
|
|
58
|
+
const fn = this[method];
|
|
59
|
+
if (typeof fn !== 'function') {
|
|
60
|
+
this.respond(id, null, new Error(`Method ${method} not found`));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
64
|
+
this.log(method, ...args);
|
|
65
|
+
// wait for the storage adapter to be ready
|
|
66
|
+
await this.isReady(args[0]);
|
|
67
|
+
try {
|
|
68
|
+
const result = await fn.apply(this, args);
|
|
69
|
+
this.respond(id, result);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
this.respond(id, null, error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async getIndexInfo(collectionName, selector) {
|
|
76
|
+
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
77
|
+
if (!storageAdapter)
|
|
78
|
+
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
79
|
+
if (selector != null
|
|
80
|
+
&& Object.keys(selector).length === 1
|
|
81
|
+
&& 'id' in selector
|
|
82
|
+
&& typeof selector.id !== 'object') {
|
|
83
|
+
return {
|
|
84
|
+
matched: true,
|
|
85
|
+
ids: (0, compact_1.default)([selector.id]),
|
|
86
|
+
optimizedSelector: {},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (selector == null) {
|
|
90
|
+
return {
|
|
91
|
+
matched: false,
|
|
92
|
+
ids: [],
|
|
93
|
+
optimizedSelector: {},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const indices = this.collectionIndices.get(collectionName) ?? [];
|
|
97
|
+
return (0, getIndexInfo_1.default)(indices.map(field => async (flatSelector) => {
|
|
98
|
+
if (!Object.hasOwnProperty.call(flatSelector, field)) {
|
|
99
|
+
// If the field is not present in the selector, we can't optimize
|
|
100
|
+
return { matched: false };
|
|
101
|
+
}
|
|
102
|
+
const index = await storageAdapter.readIndex(field);
|
|
103
|
+
const fieldSelector = flatSelector[field];
|
|
104
|
+
const filteresForNull = fieldSelector == null || fieldSelector.$exists === false;
|
|
105
|
+
const keys = filteresForNull
|
|
106
|
+
? { include: null, exclude: [...index.keys()].filter(key => key != null) }
|
|
107
|
+
: (0, getMatchingKeys_1.default)(field, flatSelector);
|
|
108
|
+
if (keys.include == null && keys.exclude == null)
|
|
109
|
+
return { matched: false };
|
|
110
|
+
// Accumulate included positions
|
|
111
|
+
let includedIds = [];
|
|
112
|
+
if (keys.include == null) {
|
|
113
|
+
for (const set of index.values()) {
|
|
114
|
+
for (const pos of set) {
|
|
115
|
+
includedIds.push(pos);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
for (const key of keys.include) {
|
|
121
|
+
const idSet = index.get(key);
|
|
122
|
+
if (idSet) {
|
|
123
|
+
for (const id of idSet) {
|
|
124
|
+
includedIds.push(id);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// If exclusion is specified, build a single set of all positions to exclude.
|
|
130
|
+
if (keys.exclude != null) {
|
|
131
|
+
const excludeIds = new Set();
|
|
132
|
+
for (const key of keys.exclude) {
|
|
133
|
+
const idSet = index.get(key);
|
|
134
|
+
if (idSet) {
|
|
135
|
+
for (const id of idSet) {
|
|
136
|
+
excludeIds.add(id);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Filter out any position that exists in the exclude set.
|
|
141
|
+
includedIds = includedIds.filter(pos => !excludeIds.has(pos));
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
matched: true,
|
|
145
|
+
ids: includedIds,
|
|
146
|
+
fields: [field],
|
|
147
|
+
keepSelector: filteresForNull,
|
|
148
|
+
};
|
|
149
|
+
}), selector);
|
|
150
|
+
}
|
|
151
|
+
async queryItems(collectionName, selector) {
|
|
152
|
+
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
153
|
+
if (!storageAdapter)
|
|
154
|
+
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
155
|
+
const indexInfo = await this.getIndexInfo(collectionName, selector);
|
|
156
|
+
const matchItems = (item) => {
|
|
157
|
+
if (indexInfo.optimizedSelector == null)
|
|
158
|
+
return true; // if no selector is given, return all items
|
|
159
|
+
if (Object.keys(indexInfo.optimizedSelector).length <= 0)
|
|
160
|
+
return true; // if selector is empty, return all items
|
|
161
|
+
const matches = (0, match_1.default)(item, indexInfo.optimizedSelector);
|
|
162
|
+
return matches;
|
|
163
|
+
};
|
|
164
|
+
if (indexInfo.matched) {
|
|
165
|
+
const items = await storageAdapter.readIds(indexInfo.ids);
|
|
166
|
+
if ((0, isEqual_1.default)(indexInfo.optimizedSelector, {}))
|
|
167
|
+
return items;
|
|
168
|
+
return items.filter(matchItems);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
const allItems = await storageAdapter.readAll();
|
|
172
|
+
if ((0, isEqual_1.default)(selector, {}))
|
|
173
|
+
return allItems;
|
|
174
|
+
return allItems.filter(matchItems);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async executeQuery(collectionName, selector, options) {
|
|
178
|
+
// null selector means no matches
|
|
179
|
+
if (selector === null)
|
|
180
|
+
return [];
|
|
181
|
+
const items = await this.queryItems(collectionName, selector || {});
|
|
182
|
+
const { sort, skip, limit, fields } = options || {};
|
|
183
|
+
const sorted = sort ? (0, sortItems_1.default)(items, sort) : items;
|
|
184
|
+
const skipped = skip ? sorted.slice(skip) : sorted;
|
|
185
|
+
const limited = limit ? skipped.slice(0, limit) : skipped;
|
|
186
|
+
const idExcluded = fields && fields.id === 0;
|
|
187
|
+
return limited.map((item) => {
|
|
188
|
+
if (!fields)
|
|
189
|
+
return item;
|
|
190
|
+
return {
|
|
191
|
+
...idExcluded ? {} : { id: item.id },
|
|
192
|
+
...(0, project_1.default)(item, fields),
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
ensureQuery(collectionName, selector, options) {
|
|
197
|
+
const id = (0, queryId_1.default)(selector, options);
|
|
198
|
+
if (!this.queries.get(collectionName)) {
|
|
199
|
+
throw new Error(`Collection ${collectionName} not initialized!`);
|
|
200
|
+
}
|
|
201
|
+
let query = this.queries.get(collectionName)?.get(id);
|
|
202
|
+
if (!query) {
|
|
203
|
+
query = { selector, options };
|
|
204
|
+
this.queries.get(collectionName)?.set(id, query);
|
|
205
|
+
}
|
|
206
|
+
return query;
|
|
207
|
+
}
|
|
208
|
+
emitQueryUpdate(collectionName, selector, options, state, error, items) {
|
|
209
|
+
const id = (0, queryId_1.default)(selector, options);
|
|
210
|
+
const collectionQueries = this.queries.get(collectionName);
|
|
211
|
+
if (!collectionQueries)
|
|
212
|
+
throw new Error(`Collection ${collectionName} not initialized!`);
|
|
213
|
+
this.respond(id, { collectionName, selector, options, state, error, items }, null, 'queryUpdate');
|
|
214
|
+
}
|
|
215
|
+
ensureStorageAdapter(name) {
|
|
216
|
+
if (this.storageAdapters.has(name))
|
|
217
|
+
return; // already created
|
|
218
|
+
const adapter = this.options.storage(name);
|
|
219
|
+
if (!adapter)
|
|
220
|
+
return; // no adapter returned
|
|
221
|
+
this.storageAdapters.set(name, adapter);
|
|
222
|
+
}
|
|
223
|
+
async checkQueryUpdates(collectionName, items) {
|
|
224
|
+
const queries = this.queries.get(collectionName);
|
|
225
|
+
if (!queries)
|
|
226
|
+
throw new Error(`Collection ${collectionName} not initialized!`);
|
|
227
|
+
const affectedQueries = [...queries.values()].filter(({ selector }) => items.some(item => (0, match_1.default)(item, selector))) ?? [];
|
|
228
|
+
if (affectedQueries.length === 0)
|
|
229
|
+
return; // no active queries affected
|
|
230
|
+
affectedQueries.forEach(({ selector, options }) => {
|
|
231
|
+
this.emitQueryUpdate(collectionName, selector, options, 'active', null);
|
|
232
|
+
});
|
|
233
|
+
await Promise.all(affectedQueries.map(async ({ selector, options }) => {
|
|
234
|
+
const queryItems = await this.executeQuery(collectionName, selector, options);
|
|
235
|
+
this.emitQueryUpdate(collectionName, selector, options, 'complete', null, queryItems);
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
registerCollection = async (collectionName, indices) => {
|
|
239
|
+
this.collectionIndices.set(collectionName, indices);
|
|
240
|
+
this.queries.set(collectionName, new Map());
|
|
241
|
+
this.ensureStorageAdapter(collectionName);
|
|
242
|
+
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
243
|
+
if (!storageAdapter)
|
|
244
|
+
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
245
|
+
const setupPromise = (async () => {
|
|
246
|
+
await storageAdapter.setup();
|
|
247
|
+
await Promise.all(indices.map(index => storageAdapter.createIndex(index)));
|
|
248
|
+
})();
|
|
249
|
+
this.storageAdapterReady.set(collectionName, setupPromise);
|
|
250
|
+
await setupPromise;
|
|
251
|
+
};
|
|
252
|
+
unregisterCollection = async (collectionName) => {
|
|
253
|
+
this.storageAdapters.delete(collectionName);
|
|
254
|
+
this.queries.delete(collectionName);
|
|
255
|
+
};
|
|
256
|
+
registerQuery = async (collectionName, selector, options) => {
|
|
257
|
+
this.ensureQuery(collectionName, selector, options);
|
|
258
|
+
const queryItems = await this.executeQuery(collectionName, selector, options);
|
|
259
|
+
this.emitQueryUpdate(collectionName, selector, options, 'complete', null, queryItems);
|
|
260
|
+
};
|
|
261
|
+
unregisterQuery = async (collectionName, selector, options) => {
|
|
262
|
+
const id = (0, queryId_1.default)(selector, options);
|
|
263
|
+
if (!this.queries.get(collectionName))
|
|
264
|
+
throw new Error(`Collection ${collectionName} not initialized!`);
|
|
265
|
+
this.queries.get(collectionName)?.delete(id);
|
|
266
|
+
};
|
|
267
|
+
insert = async (collectionName, input) => {
|
|
268
|
+
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
269
|
+
if (!storageAdapter)
|
|
270
|
+
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
271
|
+
const existingItems = await this.executeQuery(collectionName, { id: { $in: input.map(i => i[0].id) } });
|
|
272
|
+
const result = input.map(([item]) => {
|
|
273
|
+
if (item.id == null)
|
|
274
|
+
return new Error('Item must have an id');
|
|
275
|
+
if (existingItems.some(existing => existing.id === item.id)) {
|
|
276
|
+
return new Error(`Item with id ${item.id} already exists`);
|
|
277
|
+
}
|
|
278
|
+
return item;
|
|
279
|
+
});
|
|
280
|
+
const newItems = result.filter(item => !(item instanceof Error));
|
|
281
|
+
await storageAdapter.insert(newItems);
|
|
282
|
+
await this.checkQueryUpdates(collectionName, newItems);
|
|
283
|
+
return result;
|
|
284
|
+
};
|
|
285
|
+
updateOne = async (collectionName, parameters) => {
|
|
286
|
+
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
287
|
+
if (!storageAdapter)
|
|
288
|
+
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
289
|
+
const previousItems = [];
|
|
290
|
+
const result = await Promise.all(parameters.map(async ([selector, modifier]) => {
|
|
291
|
+
const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then(items => items[0] ?? null);
|
|
292
|
+
const { $setOnInsert, ...restModifier } = modifier;
|
|
293
|
+
if (item == null)
|
|
294
|
+
return [];
|
|
295
|
+
previousItems.push(item);
|
|
296
|
+
const modifiedItem = (0, modify_1.default)((0, deepClone_1.default)(item), restModifier);
|
|
297
|
+
if (item.id !== modifiedItem.id) {
|
|
298
|
+
const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
|
|
299
|
+
if (existingItems.length > 0) {
|
|
300
|
+
return new Error(`Item with id ${modifiedItem.id} already exists`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return [modifiedItem];
|
|
304
|
+
}));
|
|
305
|
+
const modifiedItems = (0, compact_1.default)(result.filter(item => !(item instanceof Error)).flat());
|
|
306
|
+
if (modifiedItems.length > 0) {
|
|
307
|
+
await storageAdapter.replace(modifiedItems);
|
|
308
|
+
await this.checkQueryUpdates(collectionName, [...modifiedItems, ...previousItems]);
|
|
309
|
+
}
|
|
310
|
+
return result;
|
|
311
|
+
};
|
|
312
|
+
updateMany = async (collectionName, parameters) => {
|
|
313
|
+
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
314
|
+
if (!storageAdapter)
|
|
315
|
+
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
316
|
+
const previousItems = [];
|
|
317
|
+
const result = await Promise.all(parameters.map(async ([selector, modifier]) => {
|
|
318
|
+
const items = await this.executeQuery(collectionName, selector);
|
|
319
|
+
if (items.length === 0)
|
|
320
|
+
return []; // no items found, nothing to update
|
|
321
|
+
const { $setOnInsert, ...restModifier } = modifier;
|
|
322
|
+
try {
|
|
323
|
+
const changedItems = await Promise.all(items.map(async (item) => {
|
|
324
|
+
const modifiedItem = (0, modify_1.default)((0, deepClone_1.default)(item), restModifier);
|
|
325
|
+
if (item.id !== modifiedItem.id) {
|
|
326
|
+
const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
|
|
327
|
+
if (existingItems.length > 0) {
|
|
328
|
+
throw new Error(`Item with id ${modifiedItem.id} already exists`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
previousItems.push(item);
|
|
332
|
+
return modifiedItem;
|
|
333
|
+
}));
|
|
334
|
+
return changedItems;
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
return error;
|
|
338
|
+
}
|
|
339
|
+
}));
|
|
340
|
+
const modifiedItems = (0, compact_1.default)(result.filter(item => !(item instanceof Error)).flat());
|
|
341
|
+
if (modifiedItems.length > 0) {
|
|
342
|
+
await storageAdapter.replace(modifiedItems);
|
|
343
|
+
await this.checkQueryUpdates(collectionName, [...modifiedItems, ...previousItems]);
|
|
344
|
+
}
|
|
345
|
+
return result;
|
|
346
|
+
};
|
|
347
|
+
replaceOne = async (collectionName, parameters) => {
|
|
348
|
+
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
349
|
+
if (!storageAdapter)
|
|
350
|
+
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
351
|
+
const previousItems = [];
|
|
352
|
+
const result = await Promise.all(parameters.map(async ([selector, replacement,]) => {
|
|
353
|
+
const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then(items => items[0] ?? null);
|
|
354
|
+
if (item == null)
|
|
355
|
+
return []; // no item found, nothing to update
|
|
356
|
+
previousItems.push(item);
|
|
357
|
+
const modifiedItem = {
|
|
358
|
+
...replacement,
|
|
359
|
+
id: replacement.id ?? item.id,
|
|
360
|
+
};
|
|
361
|
+
if (item.id !== modifiedItem.id) {
|
|
362
|
+
const existingItems = await this.executeQuery(collectionName, { id: modifiedItem.id }, { limit: 1 });
|
|
363
|
+
if (existingItems.length > 0) {
|
|
364
|
+
return new Error(`Item with id ${modifiedItem.id} already exists`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return [modifiedItem];
|
|
368
|
+
}));
|
|
369
|
+
const modifiedItems = (0, compact_1.default)(result.filter(item => !(item instanceof Error)).flat());
|
|
370
|
+
if (modifiedItems.length > 0) {
|
|
371
|
+
await storageAdapter.replace(modifiedItems);
|
|
372
|
+
await this.checkQueryUpdates(collectionName, [...modifiedItems, ...previousItems]);
|
|
373
|
+
}
|
|
374
|
+
return result;
|
|
375
|
+
};
|
|
376
|
+
removeOne = async (collectionName, selectors) => {
|
|
377
|
+
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
378
|
+
if (!storageAdapter)
|
|
379
|
+
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
380
|
+
const result = await Promise.all(selectors.map(async ([selector]) => {
|
|
381
|
+
const item = await this.executeQuery(collectionName, selector, { limit: 1 }).then(items => items[0] ?? null);
|
|
382
|
+
if (item == null)
|
|
383
|
+
return []; // no item found, nothing to remove
|
|
384
|
+
return [item];
|
|
385
|
+
}));
|
|
386
|
+
const items = result.flat();
|
|
387
|
+
if (items.length > 0) {
|
|
388
|
+
await storageAdapter.remove(items);
|
|
389
|
+
await this.checkQueryUpdates(collectionName, items);
|
|
390
|
+
}
|
|
391
|
+
return result;
|
|
392
|
+
};
|
|
393
|
+
removeMany = async (collectionName, selectors) => {
|
|
394
|
+
const storageAdapter = this.storageAdapters.get(collectionName);
|
|
395
|
+
if (!storageAdapter)
|
|
396
|
+
throw new Error(`No persistence adapter for collection ${collectionName}`);
|
|
397
|
+
const result = await Promise.all(selectors.map(async ([selector]) => this.executeQuery(collectionName, selector)));
|
|
398
|
+
const items = result.flat();
|
|
399
|
+
if (items.length > 0) {
|
|
400
|
+
await storageAdapter.remove(items);
|
|
401
|
+
await this.checkQueryUpdates(collectionName, items);
|
|
402
|
+
}
|
|
403
|
+
return result;
|
|
404
|
+
};
|
|
405
|
+
isReady = async (collectionName) => {
|
|
406
|
+
return this.storageAdapterReady.get(collectionName);
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
exports.default = WorkerDataAdapterHost;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BaseItem } from './Collection/types';
|
|
2
|
+
/**
|
|
3
|
+
* creates an index for a specific field
|
|
4
|
+
* @param field name of the field
|
|
5
|
+
* @returns an index provider to pass to the `indices` option of the collection constructor
|
|
6
|
+
*/
|
|
7
|
+
export default function createIndex<T extends BaseItem<I> = BaseItem, I = any>(field: string): import("./types/IndexProvider").default<T, I>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = createIndex;
|
|
7
|
+
const createIndexProvider_1 = __importDefault(require("./createIndexProvider"));
|
|
8
|
+
const get_1 = __importDefault(require("./utils/get"));
|
|
9
|
+
const getMatchingKeys_1 = __importDefault(require("./utils/getMatchingKeys"));
|
|
10
|
+
const serializeValue_1 = __importDefault(require("./utils/serializeValue"));
|
|
11
|
+
/**
|
|
12
|
+
* creates an index for a specific field
|
|
13
|
+
* @param field name of the field
|
|
14
|
+
* @returns an index provider to pass to the `indices` option of the collection constructor
|
|
15
|
+
*/
|
|
16
|
+
function createIndex(field) {
|
|
17
|
+
const index = new Map();
|
|
18
|
+
const ensureSet = (key) => {
|
|
19
|
+
let set = index.get(key);
|
|
20
|
+
if (!set) {
|
|
21
|
+
set = new Set();
|
|
22
|
+
index.set(key, set);
|
|
23
|
+
}
|
|
24
|
+
return set;
|
|
25
|
+
};
|
|
26
|
+
return (0, createIndexProvider_1.default)({
|
|
27
|
+
query(selector) {
|
|
28
|
+
if (!Object.hasOwnProperty.call(selector, field)) {
|
|
29
|
+
// If the field is not present in the selector, we can't optimize
|
|
30
|
+
return { matched: false };
|
|
31
|
+
}
|
|
32
|
+
const fieldSelector = selector[field];
|
|
33
|
+
const filteresForNull = fieldSelector == null || fieldSelector.$exists === false;
|
|
34
|
+
const keys = filteresForNull
|
|
35
|
+
? { include: null, exclude: [...index.keys()].filter(key => key != null) }
|
|
36
|
+
: (0, getMatchingKeys_1.default)(field, selector);
|
|
37
|
+
if (keys.include == null && keys.exclude == null)
|
|
38
|
+
return { matched: false };
|
|
39
|
+
// Accumulate included positions
|
|
40
|
+
let includedIds = [];
|
|
41
|
+
if (keys.include == null) {
|
|
42
|
+
for (const set of index.values()) {
|
|
43
|
+
for (const pos of set) {
|
|
44
|
+
includedIds.push(pos);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
for (const key of keys.include) {
|
|
50
|
+
const posSet = index.get(key);
|
|
51
|
+
if (posSet) {
|
|
52
|
+
for (const pos of posSet) {
|
|
53
|
+
includedIds.push(pos);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// If exclusion is specified, build a single set of all positions to exclude.
|
|
59
|
+
if (keys.exclude != null) {
|
|
60
|
+
const excludeIds = new Set();
|
|
61
|
+
for (const key of keys.exclude) {
|
|
62
|
+
const posSet = index.get(key);
|
|
63
|
+
if (posSet) {
|
|
64
|
+
for (const pos of posSet) {
|
|
65
|
+
excludeIds.add(pos);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Filter out any position that exists in the exclude set.
|
|
70
|
+
includedIds = includedIds.filter(pos => !excludeIds.has(pos));
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
matched: true,
|
|
74
|
+
ids: includedIds,
|
|
75
|
+
fields: [field],
|
|
76
|
+
keepSelector: filteresForNull,
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
rebuild(items) {
|
|
80
|
+
index.clear();
|
|
81
|
+
items.forEach((item) => {
|
|
82
|
+
const value = (0, serializeValue_1.default)((0, get_1.default)(item, field));
|
|
83
|
+
ensureSet(value).add(item.id);
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
// NEW: delta methods
|
|
87
|
+
insert(items) {
|
|
88
|
+
for (const item of items) {
|
|
89
|
+
const value = (0, serializeValue_1.default)((0, get_1.default)(item, field));
|
|
90
|
+
ensureSet(value).add(item.id);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
remove(items) {
|
|
94
|
+
for (const item of items) {
|
|
95
|
+
const value = (0, serializeValue_1.default)((0, get_1.default)(item, field));
|
|
96
|
+
const set = index.get(value);
|
|
97
|
+
if (!set)
|
|
98
|
+
continue;
|
|
99
|
+
set.delete(item.id);
|
|
100
|
+
if (set.size === 0)
|
|
101
|
+
index.delete(value);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
update(pairs) {
|
|
105
|
+
for (const { oldItem, newItem } of pairs) {
|
|
106
|
+
const oldValue = (0, serializeValue_1.default)((0, get_1.default)(oldItem, field));
|
|
107
|
+
const newValue = (0, serializeValue_1.default)((0, get_1.default)(newItem, field));
|
|
108
|
+
if (oldValue === newValue)
|
|
109
|
+
continue;
|
|
110
|
+
const oldSet = index.get(oldValue);
|
|
111
|
+
if (oldSet) {
|
|
112
|
+
oldSet.delete(oldItem.id);
|
|
113
|
+
if (oldSet.size === 0)
|
|
114
|
+
index.delete(oldValue);
|
|
115
|
+
}
|
|
116
|
+
ensureSet(newValue).add(newItem.id);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BaseItem } from './Collection';
|
|
2
|
+
import type IndexProvider from './types/IndexProvider';
|
|
3
|
+
/**
|
|
4
|
+
* Creates an IndexProvider based on the given definition.
|
|
5
|
+
* @param definition - The definition of the IndexProvider.
|
|
6
|
+
* @returns The created IndexProvider.
|
|
7
|
+
*/
|
|
8
|
+
export default function createIndexProvider<T extends BaseItem<I> = BaseItem, I = any>(definition: IndexProvider<T, I>): IndexProvider<T, I>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = createIndexProvider;
|
|
4
|
+
/**
|
|
5
|
+
* Creates an IndexProvider based on the given definition.
|
|
6
|
+
* @param definition - The definition of the IndexProvider.
|
|
7
|
+
* @returns The created IndexProvider.
|
|
8
|
+
*/
|
|
9
|
+
function createIndexProvider(definition) {
|
|
10
|
+
return definition;
|
|
11
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type Dependency from './types/Dependency';
|
|
2
|
+
import type ReactivityAdapter from './types/ReactivityAdapter';
|
|
3
|
+
/**
|
|
4
|
+
* Creates an ReactivityAdapter based on the given definition.
|
|
5
|
+
* @param definition - The definition of the ReactivityAdapter.
|
|
6
|
+
* @returns The created ReactivityAdapter.
|
|
7
|
+
*/
|
|
8
|
+
export default function createReactivityAdapter<T extends Dependency = Dependency>(definition: ReactivityAdapter<T>): ReactivityAdapter<T>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = createReactivityAdapter;
|
|
4
|
+
/**
|
|
5
|
+
* Creates an ReactivityAdapter based on the given definition.
|
|
6
|
+
* @param definition - The definition of the ReactivityAdapter.
|
|
7
|
+
* @returns The created ReactivityAdapter.
|
|
8
|
+
*/
|
|
9
|
+
function createReactivityAdapter(definition) {
|
|
10
|
+
return definition;
|
|
11
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type StorageAdapter from './types/StorageAdapter';
|
|
2
|
+
/**
|
|
3
|
+
* Creates an StorageAdapter based on the given definition.
|
|
4
|
+
* @param definition - The definition of the StorageAdapter.
|
|
5
|
+
* @returns The created StorageAdapter.
|
|
6
|
+
*/
|
|
7
|
+
export default function createStorageAdapter<T extends {
|
|
8
|
+
id: I;
|
|
9
|
+
} & Record<string, any>, I>(definition: StorageAdapter<T, I>): StorageAdapter<T, I>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = createStorageAdapter;
|
|
4
|
+
/**
|
|
5
|
+
* Creates an StorageAdapter based on the given definition.
|
|
6
|
+
* @param definition - The definition of the StorageAdapter.
|
|
7
|
+
* @returns The created StorageAdapter.
|
|
8
|
+
*/
|
|
9
|
+
function createStorageAdapter(definition) {
|
|
10
|
+
return definition;
|
|
11
|
+
}
|