@signaldb/core 2.0.0-beta.0 → 2.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/.vite/manifest.json +24 -11
  2. package/dist/AsyncDataAdapter.d.ts +1 -1
  3. package/dist/AutoFetchDataAdapter.d.ts +1 -2
  4. package/dist/Collection/Cursor.d.ts +3 -2
  5. package/dist/Collection/index.d.ts +17 -12
  6. package/dist/Collection/types.d.ts +1 -0
  7. package/dist/DataAdapter.d.ts +9 -7
  8. package/dist/DefaultDataAdapter.d.ts +2 -1
  9. package/dist/WorkerDataAdapter.d.ts +5 -2
  10. package/dist/WorkerDataAdapterHost.d.ts +9 -6
  11. package/dist/index.cjs12.js +35 -21
  12. package/dist/index.cjs13.js +27 -15
  13. package/dist/index.cjs14.js +72 -56
  14. package/dist/index.cjs15.js +122 -75
  15. package/dist/index.cjs16.js +45 -36
  16. package/dist/index.cjs17.js +4 -2
  17. package/dist/index.cjs19.js +0 -1
  18. package/dist/index.cjs2.js +6 -2
  19. package/dist/index.cjs20.js +14 -102
  20. package/dist/index.cjs21.js +93 -118
  21. package/dist/index.cjs22.js +127 -5
  22. package/dist/index.cjs23.js +5 -25
  23. package/dist/index.cjs24.js +25 -5
  24. package/dist/index.cjs27.js +44 -3
  25. package/dist/index.cjs28.js +6 -5
  26. package/dist/index.cjs29.js +5 -27
  27. package/dist/index.cjs3.js +41 -22
  28. package/dist/index.cjs31.js +27 -7
  29. package/dist/index.cjs32.js +9 -0
  30. package/dist/index.cjs33.js +5 -0
  31. package/dist/index.d.ts +2 -1
  32. package/dist/index12.mjs +35 -21
  33. package/dist/index13.mjs +27 -15
  34. package/dist/index14.mjs +72 -56
  35. package/dist/index15.mjs +122 -75
  36. package/dist/index16.mjs +45 -36
  37. package/dist/index17.mjs +4 -2
  38. package/dist/index19.mjs +0 -1
  39. package/dist/index2.mjs +6 -2
  40. package/dist/index20.mjs +14 -102
  41. package/dist/index21.mjs +93 -117
  42. package/dist/index22.mjs +126 -5
  43. package/dist/index23.mjs +5 -25
  44. package/dist/index24.mjs +25 -5
  45. package/dist/index27.mjs +44 -3
  46. package/dist/index28.mjs +6 -5
  47. package/dist/index29.mjs +5 -27
  48. package/dist/index3.mjs +41 -22
  49. package/dist/index31.mjs +27 -7
  50. package/dist/index32.mjs +10 -0
  51. package/dist/index33.mjs +6 -0
  52. package/dist/utils/batchOnNextTick.d.ts +16 -0
  53. package/dist/utils/deepClone.d.ts +1 -1
  54. package/package.json +3 -3
@@ -59,6 +59,7 @@
59
59
  "src/DefaultDataAdapter.ts",
60
60
  "src/utils/modify.ts",
61
61
  "src/utils/deepClone.ts",
62
+ "src/utils/queryId.ts",
62
63
  "src/Collection/Cursor.ts"
63
64
  ]
64
65
  },
@@ -86,7 +87,8 @@
86
87
  "src": "src/WorkerDataAdapter.ts",
87
88
  "imports": [
88
89
  "src/utils/queryId.ts",
89
- "src/utils/randomId.ts"
90
+ "src/utils/randomId.ts",
91
+ "src/utils/batchOnNextTick.ts"
90
92
  ]
91
93
  },
92
94
  "src/WorkerDataAdapterHost.ts": {
@@ -102,11 +104,12 @@
102
104
  "src/getIndexInfo.ts",
103
105
  "src/utils/getMatchingKeys.ts",
104
106
  "src/utils/sortItems.ts",
105
- "src/utils/project.ts"
107
+ "src/utils/project.ts",
108
+ "src/utils/compact.ts"
106
109
  ]
107
110
  },
108
111
  "src/createIndex.ts": {
109
- "file": "index.cjs20.js",
112
+ "file": "index.cjs21.js",
110
113
  "name": "createIndex",
111
114
  "src": "src/createIndex.ts",
112
115
  "imports": [
@@ -117,7 +120,7 @@
117
120
  ]
118
121
  },
119
122
  "src/createIndexProvider.ts": {
120
- "file": "index.cjs27.js",
123
+ "file": "index.cjs33.js",
121
124
  "name": "createIndexProvider",
122
125
  "src": "src/createIndexProvider.ts"
123
126
  },
@@ -132,7 +135,7 @@
132
135
  "src": "src/createStorageAdapter.ts"
133
136
  },
134
137
  "src/getIndexInfo.ts": {
135
- "file": "index.cjs21.js",
138
+ "file": "index.cjs22.js",
136
139
  "name": "getIndexInfo",
137
140
  "src": "src/getIndexInfo.ts",
138
141
  "imports": [
@@ -167,6 +170,16 @@
167
170
  "name": "utils/EventEmitter",
168
171
  "src": "src/utils/EventEmitter.ts"
169
172
  },
173
+ "src/utils/batchOnNextTick.ts": {
174
+ "file": "index.cjs27.js",
175
+ "name": "utils/batchOnNextTick",
176
+ "src": "src/utils/batchOnNextTick.ts"
177
+ },
178
+ "src/utils/compact.ts": {
179
+ "file": "index.cjs28.js",
180
+ "name": "utils/compact",
181
+ "src": "src/utils/compact.ts"
182
+ },
170
183
  "src/utils/createSignal.ts": {
171
184
  "file": "index.cjs18.js",
172
185
  "name": "utils/createSignal",
@@ -192,7 +205,7 @@
192
205
  ]
193
206
  },
194
207
  "src/utils/intersection.ts": {
195
- "file": "index.cjs28.js",
208
+ "file": "index.cjs29.js",
196
209
  "name": "utils/intersection",
197
210
  "src": "src/utils/intersection.ts"
198
211
  },
@@ -207,7 +220,7 @@
207
220
  "src": "src/utils/isFieldExpression.ts"
208
221
  },
209
222
  "src/utils/match.ts": {
210
- "file": "index.cjs22.js",
223
+ "file": "index.cjs23.js",
211
224
  "name": "utils/match",
212
225
  "src": "src/utils/match.ts"
213
226
  },
@@ -220,7 +233,7 @@
220
233
  ]
221
234
  },
222
235
  "src/utils/project.ts": {
223
- "file": "index.cjs23.js",
236
+ "file": "index.cjs24.js",
224
237
  "name": "utils/project",
225
238
  "src": "src/utils/project.ts",
226
239
  "imports": [
@@ -229,7 +242,7 @@
229
242
  ]
230
243
  },
231
244
  "src/utils/queryId.ts": {
232
- "file": "index.cjs24.js",
245
+ "file": "index.cjs20.js",
233
246
  "name": "utils/queryId",
234
247
  "src": "src/utils/queryId.ts"
235
248
  },
@@ -244,7 +257,7 @@
244
257
  "src": "src/utils/serializeValue.ts"
245
258
  },
246
259
  "src/utils/set.ts": {
247
- "file": "index.cjs29.js",
260
+ "file": "index.cjs31.js",
248
261
  "name": "utils/set",
249
262
  "src": "src/utils/set.ts"
250
263
  },
@@ -257,7 +270,7 @@
257
270
  ]
258
271
  },
259
272
  "src/utils/uniqueBy.ts": {
260
- "file": "index.cjs31.js",
273
+ "file": "index.cjs32.js",
261
274
  "name": "utils/uniqueBy",
262
275
  "src": "src/utils/uniqueBy.ts"
263
276
  }
@@ -27,7 +27,7 @@ export default class AsyncDataAdapter implements DataAdapter {
27
27
  private collectionIndices;
28
28
  private queries;
29
29
  constructor(options: AsyncDataAdapterOptions);
30
- createCollectionBackend<T extends BaseItem<I>, I = any, U = T>(collection: Collection<T, I, U>, indices: string[]): CollectionBackend<T, I>;
30
+ createCollectionBackend<T extends BaseItem<I>, I = any, E extends BaseItem = T, U = E>(collection: Collection<T, I, E, U>, indices: string[]): CollectionBackend<T, I>;
31
31
  private setupStorage;
32
32
  private ensureStorageAdapter;
33
33
  /**
@@ -71,8 +71,7 @@ export default class AutoFetchDataAdapter implements DataAdapter {
71
71
  private idRefCounts;
72
72
  private autoloadIds;
73
73
  constructor(options: AutoFetchDataAdapterOptions);
74
- createCollectionBackend<T extends BaseItem<I>, I = any, U = T>(collection: Collection<T, I, U>, indices: string[]): CollectionBackend<T, I>;
75
- private selectorKey;
74
+ createCollectionBackend<T extends BaseItem<I>, I = any, E extends BaseItem = T, U = E>(collection: Collection<T, I, E, U>, indices: string[]): CollectionBackend<T, I>;
76
75
  private forceRefetchAll;
77
76
  private fetchAndIngest;
78
77
  private purgeSelector;
@@ -15,7 +15,7 @@ export interface CursorOptions<T extends BaseItem, U = T, Async extends boolean
15
15
  * Represents a cursor for querying and observing a filtered, sorted, and transformed
16
16
  * subset of items from a collection. Supports reactivity and field tracking.
17
17
  * @template T - The type of the items in the collection.
18
- * @template U - The transformed item type after applying transformations (default is T).
18
+ * @template U - The transformed item type after applying transform (default is T).
19
19
  */
20
20
  export default class Cursor<T extends BaseItem, U = T, Async extends boolean = false> {
21
21
  private observer;
@@ -37,6 +37,7 @@ export default class Cursor<T extends BaseItem, U = T, Async extends boolean = f
37
37
  * @param options.limit - The maximum number of items to return in the result set.
38
38
  * @param options.reactive - A reactivity adapter to enable observing changes in the cursor's result set.
39
39
  * @param options.fieldTracking - A boolean to enable fine-grained field tracking for reactivity.
40
+ * @param options.transformAll - A function that will be able to solve the n+1 problem
40
41
  */
41
42
  constructor(getItems: Async extends true ? () => Promise<T[]> : () => T[], options?: CursorOptions<T, U, Async>);
42
43
  private addGetters;
@@ -102,7 +103,7 @@ export default class Cursor<T extends BaseItem, U = T, Async extends boolean = f
102
103
  * @param skipInitial - A boolean indicating whether to skip the initial notification of the current result set.
103
104
  * @returns A function to stop observing changes.
104
105
  */
105
- observeChanges(callbacks: ObserveCallbacks<U>, skipInitial?: boolean): () => void;
106
+ observeChanges(callbacks: ObserveCallbacks<T>, skipInitial?: boolean): () => void;
106
107
  /**
107
108
  * Forces the cursor to re-evaluate its result set by re-fetching items
108
109
  * from the collection. This is useful when the underlying data or query
@@ -6,12 +6,12 @@ import type DataAdapter from '../DataAdapter';
6
6
  import type { QueryOptions } from '../DataAdapter';
7
7
  import type StorageAdapter from '../types/StorageAdapter';
8
8
  import Cursor from './Cursor';
9
- import type { BaseItem, FindOptions, Transform } from './types';
10
- export type { BaseItem, Transform, SortSpecifier, FieldSpecifier, FindOptions } from './types';
9
+ import type { BaseItem, FindOptions, Transform, TransformAll } from './types';
10
+ export type { BaseItem, Transform, TransformAll, SortSpecifier, FieldSpecifier, FindOptions } from './types';
11
11
  export type { CursorOptions } from './Cursor';
12
12
  export type { ObserveCallbacks } from './Observer';
13
13
  export { default as createIndex } from '../createIndex';
14
- export interface CollectionOptions<T extends BaseItem<I>, I, U = T> {
14
+ export interface CollectionOptions<T extends BaseItem<I>, I, E extends BaseItem = T, U = E> {
15
15
  /**
16
16
  * @deprecated Use new constructor parameters instead.
17
17
  */
@@ -22,19 +22,20 @@ export interface CollectionOptions<T extends BaseItem<I>, I, U = T> {
22
22
  persistence?: StorageAdapter<T, I>;
23
23
  primaryKeyGenerator?: (item: Omit<T, 'id'>) => I;
24
24
  reactivity?: ReactivityAdapter;
25
- transform?: Transform<T, U>;
25
+ transform?: Transform<E, U>;
26
+ transformAll?: TransformAll<T, E>;
26
27
  indices?: string[];
27
28
  enableDebugMode?: boolean;
28
29
  fieldTracking?: boolean;
29
30
  }
30
- interface CollectionEvents<T extends BaseItem, U = T> {
31
+ interface CollectionEvents<T extends BaseItem, E extends BaseItem = T, U = E> {
31
32
  'added': (item: T) => void;
32
33
  'changed': (item: T, modifier: Modifier<T>) => void;
33
34
  'removed': (item: T) => void;
34
35
  'observer.created': <O extends QueryOptions<T>>(selector?: Selector<T>, options?: O) => void;
35
36
  'observer.disposed': <O extends QueryOptions<T>>(selector?: Selector<T>, options?: O) => void;
36
37
  'getItems': (selector: Selector<T> | undefined) => void;
37
- 'find': <O extends FindOptions<T, Async>, Async extends boolean>(selector: Selector<T> | undefined, options: O | undefined, cursor: Cursor<T, U, Async>) => void;
38
+ 'find': <O extends FindOptions<T, Async>, Async extends boolean>(selector: Selector<T> | undefined, options: O | undefined, cursor: Cursor<E, U, Async>) => void;
38
39
  'findOne': <O extends QueryOptions<T>>(selector: Selector<T>, options: O | undefined, item: U | undefined) => void;
39
40
  'insert': (item: Omit<T, 'id'> & Partial<Pick<T, 'id'>>) => void;
40
41
  'updateOne': (selector: Selector<T>, modifier: Modifier<T>) => void;
@@ -44,7 +45,7 @@ interface CollectionEvents<T extends BaseItem, U = T> {
44
45
  'removeMany': (selector: Selector<T>) => void;
45
46
  'validate': (item: T) => void;
46
47
  '_debug.getItems': (callstack: string, selector: Selector<T> | undefined, measuredTime: number) => void;
47
- '_debug.find': <O extends FindOptions<T, Async>, Async extends boolean>(callstack: string, selector: Selector<T> | undefined, options: O | undefined, cursor: Cursor<T, U, Async>) => void;
48
+ '_debug.find': <O extends FindOptions<T, Async>, Async extends boolean>(callstack: string, selector: Selector<T> | undefined, options: O | undefined, cursor: Cursor<E, U, Async>) => void;
48
49
  '_debug.findOne': <O extends FindOptions<T, Async>, Async extends boolean>(callstack: string, selector: Selector<T>, options: O | undefined, item: U | undefined) => void;
49
50
  '_debug.insert': (callstack: string, item: Omit<T, 'id'> & Partial<Pick<T, 'id'>>) => void;
50
51
  '_debug.updateOne': (callstack: string, selector: Selector<T>, modifier: Modifier<T>) => void;
@@ -61,14 +62,14 @@ interface CollectionEvents<T extends BaseItem, U = T> {
61
62
  * @template I - The type of the unique identifier for the items.
62
63
  * @template U - The transformed item type after applying transformations (default is T).
63
64
  */
64
- export default class Collection<T extends BaseItem<I> = BaseItem, I = any, U = T> extends EventEmitter<CollectionEvents<T, U>> {
65
+ export default class Collection<T extends BaseItem<I> = BaseItem, I = any, E extends BaseItem = T, U = E> extends EventEmitter<CollectionEvents<T, E, U>> {
65
66
  private static collections;
66
67
  private static debugMode;
67
68
  private static batchOperationInProgress;
68
69
  private static fieldTracking;
69
70
  private static onCreationCallbacks;
70
71
  private static onDisposeCallbacks;
71
- static getCollections(): Collection<any, any, any>[];
72
+ static getCollections(): Collection<any, any, any, any>[];
72
73
  static onCreation(callback: (collection: Collection<any>) => void): void;
73
74
  static onDispose(callback: (collection: Collection<any>) => void): void;
74
75
  /**
@@ -102,6 +103,7 @@ export default class Collection<T extends BaseItem<I> = BaseItem, I = any, U = T
102
103
  private isDisposed;
103
104
  private postBatchCallbacks;
104
105
  private fieldTracking;
106
+ private queryListenersMap;
105
107
  /**
106
108
  * Initializes a new instance of the `Collection` class with optional configuration.
107
109
  * Sets up memory, persistence, reactivity, and indices as specified in the options.
@@ -119,9 +121,10 @@ export default class Collection<T extends BaseItem<I> = BaseItem, I = any, U = T
119
121
  * @param options.indices - An array of index providers for optimized querying.
120
122
  * @param options.enableDebugMode - A boolean to enable or disable debug mode.
121
123
  * @param options.fieldTracking - A boolean to enable or disable field tracking by default.
124
+ * @param options.transformAll - A function that will be able to solve the n+1 problem
122
125
  */
123
- constructor(options?: CollectionOptions<T, I, U>);
124
- constructor(name: string, dataAdapter: DataAdapter, options?: CollectionOptions<T, I, U>);
126
+ constructor(options?: CollectionOptions<T, I, E, U>);
127
+ constructor(name: string, dataAdapter: DataAdapter, options?: CollectionOptions<T, I, E, U>);
125
128
  isBatchOperationInProgress(): boolean;
126
129
  /**
127
130
  * Checks whether the collection is currently performing a pull operation
@@ -183,9 +186,11 @@ export default class Collection<T extends BaseItem<I> = BaseItem, I = any, U = T
183
186
  private profile;
184
187
  private executeInDebugMode;
185
188
  private transform;
189
+ private transformAll;
186
190
  private getItem;
187
191
  private getItems;
188
192
  private withPushState;
193
+ private queryListeners;
189
194
  /**
190
195
  * Disposes the collection, unregisters persistence adapters, clears memory, and
191
196
  * cleans up all resources used by the collection.
@@ -200,7 +205,7 @@ export default class Collection<T extends BaseItem<I> = BaseItem, I = any, U = T
200
205
  * @param [options] - Options for the find operation, such as limit and sort.
201
206
  * @returns A cursor to fetch and observe the matching items.
202
207
  */
203
- find<Async extends boolean = false, O extends FindOptions<T, Async> = FindOptions<T, Async>>(selector?: Selector<T>, options?: O): Cursor<T, U, Async>;
208
+ find<Async extends boolean = false, O extends FindOptions<T, Async> = FindOptions<T, Async>>(selector?: Selector<T>, options?: O): Cursor<E, U, Async>;
204
209
  /**
205
210
  * Finds a single item in the collection based on a selector and optional options.
206
211
  * ⚡️ this function is reactive!
@@ -4,6 +4,7 @@ export type BaseItem<I = any> = {
4
4
  id: I;
5
5
  } & Record<string, any>;
6
6
  export type Transform<T, U = T> = ((document: T) => U) | null | undefined;
7
+ export type TransformAll<T extends BaseItem, O extends BaseItem = T> = ((items: T[], fields: FieldSpecifier<O> | undefined) => O[]) | null | undefined;
7
8
  export type SortSpecifier<T> = {
8
9
  [P in keyof T]?: -1 | 1;
9
10
  } & Record<string, -1 | 1>;
@@ -12,6 +12,7 @@ export interface QueryOptions<T extends BaseItem> {
12
12
  /** Dictionary of fields to return or exclude. */
13
13
  fields?: FieldSpecifier<T> | undefined;
14
14
  }
15
+ export type StateChangeCallback = (state: 'active' | 'complete' | 'error') => void;
15
16
  export interface CollectionBackend<T extends BaseItem<I>, I> {
16
17
  insert(item: T): Promise<T>;
17
18
  updateOne(selector: Selector<T>, modifier: Modifier<T>): Promise<T[]>;
@@ -19,15 +20,16 @@ export interface CollectionBackend<T extends BaseItem<I>, I> {
19
20
  replaceOne(selector: Selector<T>, replacement: Omit<T, 'id'> & Partial<Pick<T, 'id'>>): Promise<T[]>;
20
21
  removeOne(selector: Selector<T>): Promise<T[]>;
21
22
  removeMany(selector: Selector<T>): Promise<T[]>;
22
- registerQuery<O extends QueryOptions<T>>(selector: Selector<T>, options?: O): void;
23
- unregisterQuery<O extends QueryOptions<T>>(selector: Selector<T>, options?: O): void;
24
- getQueryState<O extends QueryOptions<T>>(selector: Selector<T>, options?: O): 'active' | 'complete' | 'error';
25
- getQueryError<O extends QueryOptions<T>>(selector: Selector<T>, options?: O): Error | null;
26
- getQueryResult<O extends QueryOptions<T>>(selector: Selector<T>, options?: O): T[];
27
- onQueryStateChange<O extends QueryOptions<T>>(selector: Selector<T> | undefined, options: O | undefined, callback: (state: 'active' | 'complete' | 'error') => void): () => void;
23
+ registerQuery<O extends QueryOptions<T>>(selector: Selector<T>, options: O): void;
24
+ unregisterQuery<O extends QueryOptions<T>>(selector: Selector<T>, options: O): void;
25
+ getQueryState<O extends QueryOptions<T>>(selector: Selector<T>, options: O): 'active' | 'complete' | 'error';
26
+ getQueryError<O extends QueryOptions<T>>(selector: Selector<T>, options: O): Error | null;
27
+ getQueryResult<O extends QueryOptions<T>>(selector: Selector<T>, options: O): T[];
28
+ executeQuery<O extends QueryOptions<T>>(selector: Selector<T>, options: O): Promise<T[]>;
29
+ onQueryStateChange<O extends QueryOptions<T>>(selector: Selector<T>, options: O, callback: StateChangeCallback): () => void;
28
30
  dispose(): Promise<void>;
29
31
  isReady(): Promise<void>;
30
32
  }
31
33
  export default interface DataAdapter {
32
- createCollectionBackend<T extends BaseItem<I>, I = any, U = T>(collection: Collection<T, I, U>, indices: string[]): CollectionBackend<T, I>;
34
+ createCollectionBackend<T extends BaseItem<I>, I = any, E extends BaseItem = T, U = E>(collection: Collection<T, I, E, U>, indices: string[]): CollectionBackend<T, I>;
33
35
  }
@@ -26,7 +26,8 @@ export default class DefaultDataAdapter implements DataAdapter {
26
26
  private queryItems;
27
27
  private executeQuery;
28
28
  private flushQueuedQueryUpdates;
29
+ private executeAndCacheQuery;
29
30
  private updateQueries;
30
- createCollectionBackend<T extends BaseItem<I>, I = any, U = T>(collection: Collection<T, I, U>, indices: string[]): CollectionBackend<T, I>;
31
+ createCollectionBackend<T extends BaseItem<I>, I = any, E extends BaseItem = T, U = E>(collection: Collection<T, I, E, U>, indices: string[]): CollectionBackend<T, I>;
31
32
  }
32
33
  export {};
@@ -4,6 +4,7 @@ import type DataAdapter from './DataAdapter';
4
4
  import type { CollectionBackend } from './DataAdapter';
5
5
  interface WorkerDataAdapterOptions {
6
6
  id?: string;
7
+ log?: (message: string, ...args: any[]) => void;
7
8
  }
8
9
  export default class WorkerDataAdapter implements DataAdapter {
9
10
  private worker;
@@ -11,12 +12,14 @@ export default class WorkerDataAdapter implements DataAdapter {
11
12
  private id;
12
13
  private isDisposed;
13
14
  private workerReady;
15
+ private log;
14
16
  private collectionReady;
17
+ private batchExecutionHelpers;
15
18
  private queries;
16
19
  constructor(worker: Worker, options: WorkerDataAdapterOptions);
17
20
  private exec;
18
- private queryListeners;
21
+ private enqueueBatched;
19
22
  private updateQuery;
20
- createCollectionBackend<T extends BaseItem<I>, I = any, U = T>(collection: Collection<T, I, U>, indices?: string[]): CollectionBackend<T, I>;
23
+ createCollectionBackend<T extends BaseItem<I>, I = any, E extends BaseItem = T, U = E>(collection: Collection<T, I, E, U>, indices: string[]): CollectionBackend<T, I>;
21
24
  }
22
25
  export {};
@@ -11,24 +11,27 @@ interface WorkerDataAdapterHostOptions {
11
11
  id?: string;
12
12
  storage: (name: string) => StorageAdapter<any, any>;
13
13
  onError?: (error: Error) => void;
14
+ log?: (message: string, ...args: any[]) => void;
14
15
  }
15
16
  type CollectionMethods<T extends BaseItem<I>, I = any> = {
16
17
  registerCollection: (collectionName: string, indices: string[]) => Promise<void>;
17
18
  unregisterCollection: (collectionName: string) => Promise<void>;
18
19
  registerQuery: <O extends QueryOptions<T>>(collectionName: string, selector: Selector<T>, options?: O) => Promise<void>;
19
20
  unregisterQuery: <O extends QueryOptions<T>>(collectionName: string, selector: Selector<T>, options?: O) => Promise<void>;
20
- insert: (collectionName: string, item: T) => Promise<T>;
21
- updateOne: (collectionName: string, selector: Selector<T>, modifier: Modifier<T>) => Promise<T[]>;
22
- updateMany: (collectionName: string, selector: Selector<T>, modifier: Modifier<T>) => Promise<T[]>;
23
- replaceOne: (collectionName: string, selector: Selector<T>, replacement: Omit<T, 'id'> & Partial<Pick<T, 'id'>>) => Promise<T[]>;
24
- removeOne: (collectionName: string, selector: Selector<T>) => Promise<T[]>;
25
- removeMany: (collectionName: string, selector: Selector<T>) => Promise<T[]>;
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)[]>;
26
28
  isReady: (collectionName: string) => Promise<void>;
27
29
  };
28
30
  export default class WorkerDataAdapterHost<T extends BaseItem<I>, I = any> {
29
31
  private workerContext;
30
32
  private options;
31
33
  private id;
34
+ private log;
32
35
  private storageAdapters;
33
36
  private storageAdapterReady;
34
37
  private collectionIndices;
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
- const createIndex = require("./index.cjs20.js");
3
- const getIndexInfo = require("./index.cjs21.js");
2
+ const createIndex = require("./index.cjs21.js");
3
+ const getIndexInfo = require("./index.cjs22.js");
4
4
  const deepClone = require("./index.cjs19.js");
5
5
  const EventEmitter = require("./index.cjs9.js");
6
6
  const isEqual = require("./index.cjs6.js");
7
- const match = require("./index.cjs22.js");
7
+ const match = require("./index.cjs23.js");
8
8
  const modify = require("./index.cjs7.js");
9
- const project = require("./index.cjs23.js");
10
- const queryId = require("./index.cjs24.js");
9
+ const project = require("./index.cjs24.js");
10
+ const queryId = require("./index.cjs20.js");
11
11
  const serializeValue = require("./index.cjs11.js");
12
12
  const sortItems = require("./index.cjs25.js");
13
13
  function hasPendingUpdates(pendingUpdates) {
@@ -143,14 +143,28 @@ class DefaultDataAdapter {
143
143
  return;
144
144
  this.queuedQueryUpdates.set(collection.name, { added: [], modified: [], removed: [] });
145
145
  const flatItems = [...changes.added, ...changes.modified, ...changes.removed];
146
- const queries = [...this.activeQueries.get(collection.name)?.values() ?? []].filter(({ selector }) => flatItems.some((item) => match(item, selector)));
146
+ const itemIds = new Set(flatItems.map((i) => i.id));
147
+ const queries = [
148
+ ...this.activeQueries.get(collection.name)?.values() ?? []
149
+ ].filter(({ selector, options }) => {
150
+ const idsInQuery = this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options))?.map((i) => i.id) ?? [];
151
+ if (idsInQuery.some((id) => itemIds.has(id)))
152
+ return true;
153
+ return flatItems.some((item) => match(item, selector));
154
+ });
147
155
  queries.forEach(({ selector, options }) => {
148
- const emitter = this.queryEmitters.get(collection.name);
149
- if (!emitter)
150
- return;
151
- emitter.emit("change", selector, options, "complete");
156
+ this.executeAndCacheQuery(collection, selector, options);
152
157
  });
153
158
  }
159
+ executeAndCacheQuery(collection, selector, options) {
160
+ const result = this.executeQuery(collection, selector, options);
161
+ this.cachedQueryResults.set(collection.name, this.cachedQueryResults.get(collection.name) || /* @__PURE__ */ new Map());
162
+ this.cachedQueryResults.get(collection.name)?.set(queryId(selector, options), result);
163
+ const emitter = this.queryEmitters.get(collection.name);
164
+ if (!emitter)
165
+ return;
166
+ emitter.emit("change", selector, options, "complete");
167
+ }
154
168
  updateQueries(collection, changes) {
155
169
  this.queuedQueryUpdates.set(collection.name, this.queuedQueryUpdates.get(collection.name) || { added: [], modified: [], removed: [] });
156
170
  this.queuedQueryUpdates.get(collection.name)?.added.push(...changes.added);
@@ -162,6 +176,7 @@ class DefaultDataAdapter {
162
176
  this.ensureStorageAdapter(collection.name);
163
177
  this.items.set(collection.name, this.items.get(collection.name) ?? /* @__PURE__ */ new Map());
164
178
  this.queryEmitters.set(collection.name, this.queryEmitters.get(collection.name) ?? new EventEmitter());
179
+ this.queryEmitters.get(collection.name)?.setMaxListeners(Infinity);
165
180
  this.activeQueries.set(collection.name, this.activeQueries.get(collection.name) || /* @__PURE__ */ new Map());
166
181
  this.indices.set(collection.name, indices.map((field) => createIndex(field)));
167
182
  this.rebuildIndices(collection);
@@ -207,7 +222,7 @@ class DefaultDataAdapter {
207
222
  },
208
223
  updateMany: async (selector, modifier) => {
209
224
  const { $setOnInsert, ...restModifier } = modifier;
210
- const items = backend.getQueryResult(selector);
225
+ const items = this.executeQuery(collection, selector, {});
211
226
  const changedItems = items.map((item) => {
212
227
  const modifiedItem = modify(deepClone.default(item), restModifier);
213
228
  const hasItemWithSameId = item.id !== modifiedItem.id && this.getItem(collection, { id: modifiedItem.id }) != null;
@@ -263,7 +278,7 @@ class DefaultDataAdapter {
263
278
  return [item];
264
279
  },
265
280
  removeMany: async (selector) => {
266
- const items = backend.getQueryResult(selector);
281
+ const items = backend.getQueryResult(selector, {});
267
282
  items.forEach((item) => {
268
283
  this.items.get(collection.name)?.delete(serializeValue(item.id));
269
284
  });
@@ -283,10 +298,7 @@ class DefaultDataAdapter {
283
298
  selector,
284
299
  options
285
300
  });
286
- const emitter = this.queryEmitters.get(collection.name);
287
- if (!emitter)
288
- throw new Error(`Query emitter not found for collection ${collection.name}`);
289
- emitter.emit("change", selector, options, "complete");
301
+ this.executeAndCacheQuery(collection, selector, options);
290
302
  },
291
303
  unregisterQuery: (selector, options) => {
292
304
  if (!this.activeQueries.get(collection.name))
@@ -299,7 +311,7 @@ class DefaultDataAdapter {
299
311
  if (!emitter)
300
312
  throw new Error(`Query emitter not found for collection ${collection.name}`);
301
313
  const handler = (querySelector, queryOptions, state) => {
302
- if (querySelector !== selector || queryOptions !== options)
314
+ if (queryId(querySelector, queryOptions) !== queryId(selector, options))
303
315
  return;
304
316
  callback(state);
305
317
  };
@@ -310,14 +322,16 @@ class DefaultDataAdapter {
310
322
  },
311
323
  getQueryError: () => null,
312
324
  getQueryResult: (selector, options) => {
313
- const result = this.executeQuery(collection, selector, options);
314
325
  const isQueryActive = this.activeQueries.get(collection.name)?.has(queryId(selector, options));
315
326
  if (isQueryActive) {
316
- this.cachedQueryResults.set(collection.name, this.cachedQueryResults.get(collection.name) || /* @__PURE__ */ new Map());
317
- this.cachedQueryResults.get(collection.name)?.set(queryId(selector, options), result);
327
+ const results = this.cachedQueryResults.get(collection.name)?.get(queryId(selector, options));
328
+ if (!results)
329
+ throw new Error("Cached query results are not defined!");
330
+ return results;
318
331
  }
319
- return result;
332
+ return this.executeQuery(collection, selector, options);
320
333
  },
334
+ executeQuery: (selector, options) => Promise.resolve(this.executeQuery(collection, selector, options)),
321
335
  // lifecycle methods
322
336
  dispose: async () => {
323
337
  const adapter = this.storageAdapters.get(collection.name);
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  const deepClone = require("./index.cjs19.js");
3
- const match = require("./index.cjs22.js");
3
+ const match = require("./index.cjs23.js");
4
4
  const modify = require("./index.cjs7.js");
5
- const queryId = require("./index.cjs24.js");
5
+ const queryId = require("./index.cjs20.js");
6
6
  const isEqual = require("./index.cjs6.js");
7
- const getIndexInfo = require("./index.cjs21.js");
7
+ const getIndexInfo = require("./index.cjs22.js");
8
8
  const getMatchingKeys = require("./index.cjs26.js");
9
9
  const sortItems = require("./index.cjs25.js");
10
- const project = require("./index.cjs23.js");
10
+ const project = require("./index.cjs24.js");
11
11
  class AsyncDataAdapter {
12
12
  options;
13
13
  id;
@@ -120,6 +120,13 @@ class AsyncDataAdapter {
120
120
  getQueryError,
121
121
  getQueryResult,
122
122
  onQueryStateChange,
123
+ executeQuery: async (selector, options) => {
124
+ await ready;
125
+ registerQuery(selector, options);
126
+ const result = getQueryResult(selector, options);
127
+ unregisterQuery(selector, options);
128
+ return result;
129
+ },
123
130
  dispose: async () => {
124
131
  this.storageAdapters.delete(collection.name);
125
132
  this.queries.delete(collection.name);
@@ -135,11 +142,8 @@ class AsyncDataAdapter {
135
142
  const storage = this.storageAdapters.get(collectionName);
136
143
  if (!storage)
137
144
  throw new Error(`No persistence adapter for collection ${collectionName}`);
138
- await Promise.all([
139
- storage.createIndex("id"),
140
- ...indices.map((index) => storage.createIndex(index))
141
- ]);
142
145
  await storage.setup();
146
+ await Promise.all(indices.map((index) => storage.createIndex(index)));
143
147
  }
144
148
  ensureStorageAdapter(name) {
145
149
  if (this.storageAdapters.has(name))
@@ -200,20 +204,28 @@ class AsyncDataAdapter {
200
204
  rec.items = items;
201
205
  }
202
206
  async getIndexInfo(collectionName, selector) {
203
- const storage = this.storageAdapters.get(collectionName);
204
- if (!storage)
207
+ const storageAdapter = this.storageAdapters.get(collectionName);
208
+ if (!storageAdapter)
205
209
  throw new Error(`No persistence adapter for collection ${collectionName}`);
206
210
  if (selector != null && Object.keys(selector).length === 1 && "id" in selector && typeof selector.id !== "object") {
207
- return { matched: true, ids: [selector.id], optimizedSelector: {} };
211
+ return {
212
+ matched: true,
213
+ ids: [selector.id].filter(Boolean),
214
+ optimizedSelector: {}
215
+ };
208
216
  }
209
217
  if (selector == null) {
210
- return { matched: false, ids: [], optimizedSelector: {} };
218
+ return {
219
+ matched: false,
220
+ ids: [],
221
+ optimizedSelector: {}
222
+ };
211
223
  }
212
224
  const indices = this.collectionIndices.get(collectionName) ?? [];
213
225
  return getIndexInfo.default(indices.map((field) => async (flatSelector) => {
214
226
  if (!Object.hasOwnProperty.call(flatSelector, field))
215
227
  return { matched: false };
216
- const index = await storage.readIndex(field);
228
+ const index = await storageAdapter.readIndex(field);
217
229
  const fieldSelector = flatSelector[field];
218
230
  const filtersForNull = fieldSelector == null || fieldSelector.$exists === false;
219
231
  const keys = filtersForNull ? { include: null, exclude: [...index.keys()].filter((key) => key != null) } : getMatchingKeys(field, flatSelector);
@@ -315,8 +327,8 @@ class AsyncDataAdapter {
315
327
  const storage = this.storageAdapters.get(collectionName);
316
328
  if (!storage)
317
329
  throw new Error(`No persistence adapter for collection ${collectionName}`);
318
- const existing = await this.executeQuery(collectionName, { id: newItem.id }, { limit: 1 });
319
- if (existing.length > 0)
330
+ const existingItems = await storage.readIds([newItem.id]);
331
+ if (existingItems.length > 0)
320
332
  throw new Error(`Item with id ${String(newItem.id)} already exists`);
321
333
  await storage.insert([newItem]);
322
334
  await this.checkQueryUpdates(collectionName, [newItem]);