@signaldb/core 2.0.0-beta.10 → 2.0.0-beta.12

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.
@@ -17,7 +17,7 @@
17
17
  ]
18
18
  },
19
19
  "src/AutoFetchDataAdapter.ts": {
20
- "file": "index34.cjs.js",
20
+ "file": "index35.cjs.js",
21
21
  "name": "AutoFetchDataAdapter",
22
22
  "src": "src/AutoFetchDataAdapter.ts",
23
23
  "isDynamicEntry": true,
@@ -89,18 +89,22 @@
89
89
  ]
90
90
  },
91
91
  "src/WorkerDataAdapter.ts": {
92
- "file": "index31.cjs.js",
92
+ "file": "index32.cjs.js",
93
93
  "name": "WorkerDataAdapter",
94
94
  "src": "src/WorkerDataAdapter.ts",
95
95
  "isDynamicEntry": true,
96
96
  "imports": [
97
+ "src/utils/applyQueryOptions.ts",
97
98
  "src/utils/batchOnNextTick.ts",
99
+ "src/utils/deepClone.ts",
100
+ "src/utils/match.ts",
101
+ "src/utils/modify.ts",
98
102
  "src/utils/queryId.ts",
99
103
  "src/utils/randomId.ts"
100
104
  ]
101
105
  },
102
106
  "src/WorkerDataAdapterHost.ts": {
103
- "file": "index33.cjs.js",
107
+ "file": "index34.cjs.js",
104
108
  "name": "WorkerDataAdapterHost",
105
109
  "src": "src/WorkerDataAdapterHost.ts",
106
110
  "isDynamicEntry": true,
@@ -186,6 +190,17 @@
186
190
  "src": "src/utils/EventEmitter.ts",
187
191
  "isDynamicEntry": true
188
192
  },
193
+ "src/utils/applyQueryOptions.ts": {
194
+ "file": "index31.cjs.js",
195
+ "name": "utils/applyQueryOptions",
196
+ "src": "src/utils/applyQueryOptions.ts",
197
+ "isDynamicEntry": true,
198
+ "imports": [
199
+ "src/utils/match.ts",
200
+ "src/utils/project.ts",
201
+ "src/utils/sortItems.ts"
202
+ ]
203
+ },
189
204
  "src/utils/batchOnNextTick.ts": {
190
205
  "file": "index30.cjs.js",
191
206
  "name": "utils/batchOnNextTick",
@@ -193,7 +208,7 @@
193
208
  "isDynamicEntry": true
194
209
  },
195
210
  "src/utils/compact.ts": {
196
- "file": "index32.cjs.js",
211
+ "file": "index33.cjs.js",
197
212
  "name": "utils/compact",
198
213
  "src": "src/utils/compact.ts",
199
214
  "isDynamicEntry": true
@@ -7,9 +7,26 @@ import { ObserveCallbacks } from './Observer';
7
7
  * @returns A boolean indicating if the current scope is reactive.
8
8
  */
9
9
  export declare function isInReactiveScope(reactivity: ReactivityAdapter | undefined | false): boolean;
10
+ /**
11
+ * Reports whether the query a cursor stands for has produced an outcome yet.
12
+ * Supplied by the collection, which owns the query registration; a cursor
13
+ * built without one simply never reports itself as loading.
14
+ */
15
+ export interface QueryStateAccessor {
16
+ /**
17
+ * Whether the query has settled — completed or failed — at least once
18
+ * since it was registered.
19
+ */
20
+ hasSettled: () => boolean;
21
+ /**
22
+ * Subscribes to the query settling. Returns a cleanup function.
23
+ */
24
+ onSettled: (callback: () => void) => () => void;
25
+ }
10
26
  export interface CursorOptions<T extends BaseItem, U = T, Async extends boolean = false> extends FindOptions<T, Async> {
11
27
  transform?: Transform<T, U>;
12
28
  bindEvents?: (requery: () => void) => () => void;
29
+ queryState?: QueryStateAccessor;
13
30
  }
14
31
  /**
15
32
  * Represents a cursor for querying and observing a filtered, sorted, and transformed
@@ -90,6 +107,31 @@ export default class Cursor<T extends BaseItem, U = T, Async extends boolean = f
90
107
  * @returns The total number of items in the result set.
91
108
  */
92
109
  count(): Async extends true ? Promise<number> : number;
110
+ /**
111
+ * Whether this cursor's query has yet to deliver a first result.
112
+ * ⚡️ this function is reactive!
113
+ *
114
+ * An asynchronous data adapter answers a newly registered query only after a
115
+ * round trip, and serves a neutral empty result until it does — which a
116
+ * consumer cannot otherwise tell apart from "there is nothing to show". This
117
+ * is that distinction, per query rather than per collection, so one screen
118
+ * waiting on its own data says nothing about any other query.
119
+ *
120
+ * Follows the usual `isLoading`/`isFetching` split: it reports "no result
121
+ * yet", not "an execution is in flight". A write that re-runs an
122
+ * already-settled query drives it through `'active'` again while this stays
123
+ * `false`, so a list does not fall back to a loading state every time one of
124
+ * its rows changes.
125
+ *
126
+ * A query that fails counts as settled — the `query.error` event on the
127
+ * collection is what surfaces the failure, and a loading state that never
128
+ * ends is the worse answer. Reading this registers the query if nothing else
129
+ * has, so it cannot wait on something nobody asked for. It is always `false`
130
+ * for an `{ async: true }` cursor, whose `fetch()` awaits the real result
131
+ * anyway, and for a data adapter that answers synchronously.
132
+ * @returns A boolean indicating whether the first result is still pending.
133
+ */
134
+ isLoading(): boolean;
93
135
  /**
94
136
  * Observes changes to the cursor's result set and triggers the specified callbacks
95
137
  * when items are added, removed, or updated. Supports reactivity and transformation.
@@ -7,7 +7,7 @@ import { default as StorageAdapter } from '../types/StorageAdapter';
7
7
  import { default as Cursor } from './Cursor';
8
8
  import { AsyncFindOptions, BaseItem, FindOptions, SyncFindOptions, Transform, TransformAll } from './types';
9
9
  export type { AnyFindOptions, AsyncFindOptions, BaseItem, Transform, TransformAll, SortSpecifier, FieldSpecifier, FindOptions, SyncFindOptions, } from './types';
10
- export type { CursorOptions } from './Cursor';
10
+ export type { CursorOptions, QueryStateAccessor } from './Cursor';
11
11
  export type { ObserveCallbacks } from './Observer';
12
12
  export { default as createIndex } from '../createIndex';
13
13
  export interface CollectionOptions<T extends BaseItem<I>, I, E extends BaseItem = T, U = E> {
@@ -109,6 +109,7 @@ export default class Collection<T extends BaseItem<I> = BaseItem, I = any, E ext
109
109
  private postBatchCallbacks;
110
110
  private fieldTracking;
111
111
  private queryListenersMap;
112
+ private settledQueriesSet;
112
113
  /**
113
114
  * Initializes a new instance of the `Collection` class with optional configuration.
114
115
  * Sets up memory, persistence, reactivity, and indices as specified in the options.
@@ -4,6 +4,12 @@ interface WorkerDataAdapterOptions {
4
4
  id?: string;
5
5
  log?: (message: string, ...args: any[]) => void;
6
6
  }
7
+ export interface WorkerDataAdapterEndpoint {
8
+ addEventListener: (type: 'message', listener: (event: MessageEvent) => void) => void;
9
+ removeEventListener: (type: 'message', listener: (event: MessageEvent) => void) => void;
10
+ postMessage: (message: unknown) => void;
11
+ terminate?: () => void;
12
+ }
7
13
  export default class WorkerDataAdapter implements DataAdapter {
8
14
  private worker;
9
15
  private options;
@@ -14,8 +20,28 @@ export default class WorkerDataAdapter implements DataAdapter {
14
20
  private collectionReady;
15
21
  private batchExecutionHelpers;
16
22
  private queries;
17
- constructor(worker: Worker, options: WorkerDataAdapterOptions);
23
+ private pendingWrites;
24
+ private pendingWriteSeq;
25
+ constructor(worker: WorkerDataAdapterEndpoint, options: WorkerDataAdapterOptions);
18
26
  private exec;
27
+ private observableItems;
28
+ private mergePendingWrites;
29
+ /**
30
+ * Registers a write's effect locally and notifies every active query it
31
+ * touches, then returns a function that drops it again once the write
32
+ * settles.
33
+ * @param collectionName - The collection the write targets.
34
+ * @param upserts - Items inserted or updated by the write.
35
+ * @param deletes - Ids removed by the write.
36
+ * @returns A function that drops the pending write and re-notifies.
37
+ */
38
+ private applyPendingWrite;
39
+ private notifyAffectedQueries;
40
+ private matchObservableItems;
41
+ private resolveUpdate;
42
+ private resolveRemoval;
43
+ private resolveReplacement;
44
+ private withPendingWrite;
19
45
  private enqueueBatched;
20
46
  private updateQuery;
21
47
  createCollectionBackend<T extends BaseItem<I>, I = any, E extends BaseItem = T, U = E>(collection: Collection<T, I, E, U>, indices: string[]): CollectionBackend<T, I>;
@@ -3,7 +3,7 @@ import { QueryOptions } from './DataAdapter';
3
3
  import { default as Modifier } from './types/Modifier';
4
4
  import { default as StorageAdapter } from './types/StorageAdapter';
5
5
  import { default as Selector } from './types/Selector';
6
- interface WorkerContext {
6
+ export interface WorkerDataAdapterHostEndpoint {
7
7
  addEventListener: (type: 'message', listener: (event: MessageEvent) => any) => void;
8
8
  postMessage: (message: any) => void;
9
9
  }
@@ -37,7 +37,7 @@ export default class WorkerDataAdapterHost<T extends BaseItem<I>, I = any> {
37
37
  private collectionIndices;
38
38
  private queries;
39
39
  private onError;
40
- constructor(workerContext: WorkerContext, options: WorkerDataAdapterHostOptions);
40
+ constructor(workerContext: WorkerDataAdapterHostEndpoint, options: WorkerDataAdapterHostOptions);
41
41
  private respond;
42
42
  private handleMessage;
43
43
  private getIndexInfo;
package/dist/index.cjs.js CHANGED
@@ -12,9 +12,9 @@ const require_createStorageAdapter = require("./index26.cjs.js");
12
12
  const require_createReactivityAdapter = require("./index27.cjs.js");
13
13
  const require_reactiveOrAsync = require("./index28.cjs.js");
14
14
  const require_AsyncDataAdapter = require("./index29.cjs.js");
15
- const require_WorkerDataAdapter = require("./index31.cjs.js");
16
- const require_WorkerDataAdapterHost = require("./index33.cjs.js");
17
- const require_AutoFetchDataAdapter = require("./index34.cjs.js");
15
+ const require_WorkerDataAdapter = require("./index32.cjs.js");
16
+ const require_WorkerDataAdapterHost = require("./index34.cjs.js");
17
+ const require_AutoFetchDataAdapter = require("./index35.cjs.js");
18
18
  exports.AsyncDataAdapter = require_AsyncDataAdapter.default;
19
19
  exports.AutoFetchDataAdapter = require_AutoFetchDataAdapter.default;
20
20
  exports.Collection = require_index.default;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export type { default as ReactivityAdapter } from './types/ReactivityAdapter';
2
2
  export type { default as StorageAdapter, Changeset, } from './types/StorageAdapter';
3
3
  export type { default as Selector } from './types/Selector';
4
4
  export type { default as Modifier } from './types/Modifier';
5
- export type { BaseItem, ObserveCallbacks, CursorOptions, Transform, TransformAll, SortSpecifier, FieldSpecifier, AnyFindOptions, AsyncFindOptions, FindOptions, SyncFindOptions, CollectionOptions, } from './Collection';
5
+ export type { BaseItem, ObserveCallbacks, CursorOptions, Transform, TransformAll, SortSpecifier, FieldSpecifier, AnyFindOptions, AsyncFindOptions, FindOptions, SyncFindOptions, CollectionOptions, QueryStateAccessor, } from './Collection';
6
6
  export type { default as DataAdapter } from './DataAdapter';
7
7
  export { default as Cursor } from './Collection/Cursor';
8
8
  export { default as Collection } from './Collection';
@@ -19,4 +19,6 @@ export { default as DefaultDataAdapter } from './DefaultDataAdapter';
19
19
  export { default as AsyncDataAdapter } from './AsyncDataAdapter';
20
20
  export { default as WorkerDataAdapter } from './WorkerDataAdapter';
21
21
  export { default as WorkerDataAdapterHost } from './WorkerDataAdapterHost';
22
+ export type { WorkerDataAdapterEndpoint } from './WorkerDataAdapter';
23
+ export type { WorkerDataAdapterHostEndpoint } from './WorkerDataAdapterHost';
22
24
  export { default as AutoFetchDataAdapter } from './AutoFetchDataAdapter';
package/dist/index.mjs CHANGED
@@ -11,7 +11,7 @@ import createStorageAdapter from "./index26.mjs";
11
11
  import createReactivityAdapter from "./index27.mjs";
12
12
  import reactiveOrAsync, { unwrap } from "./index28.mjs";
13
13
  import AsyncDataAdapter from "./index29.mjs";
14
- import WorkerDataAdapter from "./index31.mjs";
15
- import WorkerDataAdapterHost from "./index33.mjs";
16
- import AutoFetchDataAdapter from "./index34.mjs";
14
+ import WorkerDataAdapter from "./index32.mjs";
15
+ import WorkerDataAdapterHost from "./index34.mjs";
16
+ import AutoFetchDataAdapter from "./index35.mjs";
17
17
  export { AsyncDataAdapter, AutoFetchDataAdapter, Collection, Cursor, DefaultDataAdapter, EventEmitter, WorkerDataAdapter, WorkerDataAdapterHost, createReactivityAdapter, createStorageAdapter, get, isEqual, modify, randomId, reactiveOrAsync, serializeValue, unwrap };
@@ -84,6 +84,7 @@ var Collection = class Collection extends require_EventEmitter.default {
84
84
  postBatchCallbacks = /* @__PURE__ */ new Set();
85
85
  fieldTracking = false;
86
86
  queryListenersMap = /* @__PURE__ */ new Map();
87
+ settledQueriesSet = /* @__PURE__ */ new Set();
87
88
  constructor(nameOrOptions, maybeDataAdapter, maybeOptions) {
88
89
  super();
89
90
  const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions?.name || `${this.constructor.name}-${require_randomId.default()}`;
@@ -265,6 +266,18 @@ var Collection = class Collection extends require_EventEmitter.default {
265
266
  fieldTracking: this.fieldTracking,
266
267
  ...options,
267
268
  transform: this.transform.bind(this),
269
+ queryState: {
270
+ hasSettled: () => {
271
+ if (this.settledQueriesSet.has(require_queryId.default(selector, options))) return true;
272
+ const state = this.backend.getQueryState(selector, options || {});
273
+ return state === "complete" || state === "error";
274
+ },
275
+ onSettled: (callback) => this.backend.onQueryStateChange(selector, options || {}, (state) => {
276
+ if (state !== "complete" && state !== "error") return;
277
+ this.settledQueriesSet.add(require_queryId.default(selector, options));
278
+ callback();
279
+ })
280
+ },
268
281
  bindEvents: (requery) => {
269
282
  const handleRequery = () => {
270
283
  if (this.batchOperationInProgress) {
@@ -299,7 +312,10 @@ var Collection = class Collection extends require_EventEmitter.default {
299
312
  selector,
300
313
  options
301
314
  }) - 1);
302
- if (newListeners === 0 && didRegister) this.backend.unregisterQuery(selector, options || {});
315
+ if (newListeners === 0 && didRegister) {
316
+ this.backend.unregisterQuery(selector, options || {});
317
+ this.settledQueriesSet.delete(require_queryId.default(selector, options));
318
+ }
303
319
  this.queryListeners({
304
320
  selector,
305
321
  options
package/dist/index25.mjs CHANGED
@@ -84,6 +84,7 @@ var Collection = class Collection extends EventEmitter {
84
84
  postBatchCallbacks = /* @__PURE__ */ new Set();
85
85
  fieldTracking = false;
86
86
  queryListenersMap = /* @__PURE__ */ new Map();
87
+ settledQueriesSet = /* @__PURE__ */ new Set();
87
88
  constructor(nameOrOptions, maybeDataAdapter, maybeOptions) {
88
89
  super();
89
90
  const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions?.name || `${this.constructor.name}-${randomId()}`;
@@ -265,6 +266,18 @@ var Collection = class Collection extends EventEmitter {
265
266
  fieldTracking: this.fieldTracking,
266
267
  ...options,
267
268
  transform: this.transform.bind(this),
269
+ queryState: {
270
+ hasSettled: () => {
271
+ if (this.settledQueriesSet.has(queryId(selector, options))) return true;
272
+ const state = this.backend.getQueryState(selector, options || {});
273
+ return state === "complete" || state === "error";
274
+ },
275
+ onSettled: (callback) => this.backend.onQueryStateChange(selector, options || {}, (state) => {
276
+ if (state !== "complete" && state !== "error") return;
277
+ this.settledQueriesSet.add(queryId(selector, options));
278
+ callback();
279
+ })
280
+ },
268
281
  bindEvents: (requery) => {
269
282
  const handleRequery = () => {
270
283
  if (this.batchOperationInProgress) {
@@ -299,7 +312,10 @@ var Collection = class Collection extends EventEmitter {
299
312
  selector,
300
313
  options
301
314
  }) - 1);
302
- if (newListeners === 0 && didRegister) this.backend.unregisterQuery(selector, options || {});
315
+ if (newListeners === 0 && didRegister) {
316
+ this.backend.unregisterQuery(selector, options || {});
317
+ this.settledQueriesSet.delete(queryId(selector, options));
318
+ }
303
319
  this.queryListeners({
304
320
  selector,
305
321
  options
@@ -239,7 +239,8 @@ var AsyncDataAdapter = class {
239
239
  if (!rec) return;
240
240
  rec.state = state;
241
241
  rec.error = error;
242
- for (const callback of rec.listeners) try {
242
+ const subscribers = [...rec.listeners];
243
+ for (const callback of subscribers) try {
243
244
  callback(state);
244
245
  } catch (error_) {
245
246
  this.onError(error_);
package/dist/index29.mjs CHANGED
@@ -239,7 +239,8 @@ var AsyncDataAdapter = class {
239
239
  if (!rec) return;
240
240
  rec.state = state;
241
241
  rec.error = error;
242
- for (const callback of rec.listeners) try {
242
+ const subscribers = [...rec.listeners];
243
+ for (const callback of subscribers) try {
243
244
  callback(state);
244
245
  } catch (error_) {
245
246
  this.onError(error_);
@@ -1,191 +1,32 @@
1
- const require_randomId = require("./index8.cjs.js");
2
- const require_queryId = require("./index22.cjs.js");
3
- const require_batchOnNextTick = require("./index30.cjs.js");
4
- //#region src/WorkerDataAdapter.ts
5
- var WorkerDataAdapter = class {
6
- worker;
7
- options;
8
- id;
9
- isDisposed = false;
10
- workerReady;
11
- log = () => {};
12
- collectionReady = /* @__PURE__ */ new Map();
13
- batchExecutionHelpers = /* @__PURE__ */ new Map();
14
- queries = {};
15
- constructor(worker, options) {
16
- this.worker = worker;
17
- this.options = options;
18
- this.id = this.options.id || "default-worker-data-adapter";
19
- if (this.options.log) this.log = this.options.log;
20
- this.workerReady = new Promise((resolve, reject) => {
21
- const timeoutId = setTimeout(() => {
22
- reject(/* @__PURE__ */ new Error("WorkerDataAdapter initialization timed out"));
23
- }, 5e3);
24
- const handleMessage = (event) => {
25
- const { type, workerId } = event.data;
26
- if (workerId !== this.id) return;
27
- if (type === "ready") {
28
- resolve();
29
- clearTimeout(timeoutId);
30
- this.worker.removeEventListener("message", handleMessage);
31
- }
32
- };
33
- this.worker.addEventListener("message", handleMessage);
34
- });
35
- }
36
- async exec(method, collectionName, ...args) {
37
- await this.workerReady;
38
- if (method !== "isReady") {
39
- const collectionReady = this.collectionReady.get(collectionName);
40
- if (!collectionReady) throw new Error(`Collection "${collectionName}" is not registered in WorkerDataAdapter`);
41
- await collectionReady;
42
- }
43
- if (this.isDisposed) throw new Error("WorkerDataAdapter is disposed");
44
- return new Promise((resolve, reject) => {
45
- const messageId = require_randomId.default();
46
- const handleMessage = (event) => {
47
- const { id, workerId, type, data, error } = event.data;
48
- if (workerId !== this.id) return;
49
- if (type !== "response") return;
50
- if (id !== messageId) return;
51
- this.log(method, "result", data ?? error);
52
- if (error) reject(error);
53
- else resolve(data);
54
- this.worker.removeEventListener("message", handleMessage);
55
- };
56
- this.worker.addEventListener("message", handleMessage);
57
- this.worker.postMessage({
58
- id: messageId,
59
- workerId: this.id,
60
- method,
61
- args: [collectionName, ...args]
62
- });
63
- });
64
- }
65
- enqueueBatched(collectionName, method, args) {
66
- const helper = this.batchExecutionHelpers.get(collectionName);
67
- if (!helper) throw new Error(`Collection "${collectionName}" is not registered in WorkerDataAdapter`);
68
- return helper.enqueue(method, args);
69
- }
70
- updateQuery(collectionName, query, update) {
71
- const id = require_queryId.default(query.selector, query.options);
72
- const collectionQueries = this.queries[collectionName];
73
- if (!collectionQueries) return;
74
- const existing = collectionQueries.get(id);
75
- const newState = {
76
- state: "active",
77
- error: null,
78
- items: [],
79
- stateChangeCallbacks: [],
80
- eventHandler: existing?.eventHandler,
81
- ...existing,
82
- ...update
83
- };
84
- collectionQueries.set(id, newState);
85
- this.queries[collectionName] = collectionQueries;
86
- }
87
- createCollectionBackend(collection, indices) {
88
- this.queries[collection.name] = /* @__PURE__ */ new Map();
89
- this.exec("registerCollection", collection.name, indices);
90
- this.collectionReady.set(collection.name, this.exec("isReady", collection.name));
91
- this.batchExecutionHelpers.set(collection.name, require_batchOnNextTick.default(async (method, args) => this.exec(method, collection.name, args)));
1
+ const require_match = require("./index18.cjs.js");
2
+ const require_project = require("./index21.cjs.js");
3
+ const require_sortItems = require("./index23.cjs.js");
4
+ //#region src/utils/applyQueryOptions.ts
5
+ /**
6
+ * Filters, sorts, paginates and projects a plain in-memory array the same way
7
+ * DefaultDataAdapter and WorkerDataAdapterHost apply a selector/QueryOptions
8
+ * pair to their stored items. Used to re-derive a query's result locally after
9
+ * a write, without asking the backing store again.
10
+ * @template T - The type of the items.
11
+ * @param items - The items to filter, sort, paginate and project.
12
+ * @param selector - The selector to match items against.
13
+ * @param options - Sort, skip, limit and field projection options.
14
+ * @returns The resulting items.
15
+ */
16
+ function applyQueryOptions(items, selector, options) {
17
+ const matched = selector == null ? [] : items.filter((item) => require_match.default(item, selector));
18
+ const { sort, skip, limit, fields } = options || {};
19
+ const sorted = sort ? require_sortItems.default(matched, sort) : matched;
20
+ const skipped = skip ? sorted.slice(skip) : sorted;
21
+ const limited = limit ? skipped.slice(0, limit) : skipped;
22
+ const idExcluded = fields && fields.id === 0;
23
+ return limited.map((item) => {
24
+ if (!fields) return item;
92
25
  return {
93
- insert: async (item) => {
94
- return this.enqueueBatched(collection.name, "insert", [item]);
95
- },
96
- updateOne: async (selector, modifier) => {
97
- return this.enqueueBatched(collection.name, "updateOne", [selector, modifier]);
98
- },
99
- updateMany: async (selector, modifier) => {
100
- return this.enqueueBatched(collection.name, "updateMany", [selector, modifier]);
101
- },
102
- replaceOne: async (selector, replacement) => {
103
- return this.enqueueBatched(collection.name, "replaceOne", [selector, replacement]);
104
- },
105
- removeOne: async (selector) => {
106
- return this.enqueueBatched(collection.name, "removeOne", [selector]);
107
- },
108
- removeMany: async (selector) => {
109
- return this.enqueueBatched(collection.name, "removeMany", [selector]);
110
- },
111
- registerQuery: (selector, options) => {
112
- this.updateQuery(collection.name, {
113
- selector,
114
- options
115
- }, {
116
- state: "active",
117
- error: null,
118
- items: []
119
- });
120
- this.exec("registerQuery", collection.name, selector, options);
121
- const handler = (event) => {
122
- const { type, data, workerId, error } = event.data;
123
- if (type !== "queryUpdate") return;
124
- if (data == null) return;
125
- const { collectionName, selector: responseSelector, options: responseOptions, state, items } = data;
126
- if (workerId !== this.id) return;
127
- if (collectionName !== collection.name) return;
128
- if (require_queryId.default(responseSelector, responseOptions) !== require_queryId.default(selector, options)) return;
129
- this.log("queryUpdate", responseSelector, responseOptions, state, data ?? error);
130
- this.updateQuery(collection.name, {
131
- selector: responseSelector,
132
- options: responseOptions
133
- }, {
134
- state,
135
- error,
136
- items
137
- });
138
- const query = this.queries[collection.name]?.get(require_queryId.default(selector, options));
139
- if (!query) return;
140
- query.stateChangeCallbacks.forEach((callback) => callback(state));
141
- };
142
- this.worker.addEventListener("message", handler);
143
- this.updateQuery(collection.name, {
144
- selector,
145
- options
146
- }, { eventHandler: handler });
147
- },
148
- unregisterQuery: (selector, options) => {
149
- const qid = require_queryId.default(selector, options);
150
- const query = this.queries[collection.name]?.get(qid);
151
- if (query?.eventHandler) this.worker.removeEventListener("message", query.eventHandler);
152
- this.queries[collection.name]?.delete(qid);
153
- this.exec("unregisterQuery", collection.name, selector, options);
154
- },
155
- getQueryState: (selector, options) => {
156
- return (this.queries[collection.name]?.get(require_queryId.default(selector, options)))?.state || "active";
157
- },
158
- getQueryError: (selector, options) => {
159
- return (this.queries[collection.name]?.get(require_queryId.default(selector, options)))?.error || null;
160
- },
161
- getQueryResult: (selector, options) => {
162
- return (this.queries[collection.name]?.get(require_queryId.default(selector, options)))?.items || [];
163
- },
164
- onQueryStateChange: (selector, options, callback) => {
165
- this.updateQuery(collection.name, {
166
- selector,
167
- options
168
- }, { stateChangeCallbacks: [...this.queries[collection.name]?.get(require_queryId.default(selector, options))?.stateChangeCallbacks || [], callback] });
169
- return () => {
170
- const currentCallbacks = this.queries[collection.name]?.get(require_queryId.default(selector, options))?.stateChangeCallbacks;
171
- if (!currentCallbacks) throw new Error("State change callbacks are not defined!");
172
- this.updateQuery(collection.name, {
173
- selector,
174
- options
175
- }, { stateChangeCallbacks: currentCallbacks.filter((existingCallback) => existingCallback !== callback) });
176
- };
177
- },
178
- executeQuery: (selector, options) => this.exec("executeQuery", collection.name, selector, options),
179
- dispose: async () => {
180
- await this.exec("unregisterCollection", collection.name);
181
- this.isDisposed = true;
182
- this.worker.terminate();
183
- },
184
- isReady: async () => {
185
- await this.exec("isReady", collection.name);
186
- }
26
+ ...idExcluded ? {} : { id: item.id },
27
+ ...require_project.default(item, fields)
187
28
  };
188
- }
189
- };
29
+ });
30
+ }
190
31
  //#endregion
191
- exports.default = WorkerDataAdapter;
32
+ exports.default = applyQueryOptions;