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

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 (52) hide show
  1. package/dist/.vite/manifest.json +25 -12
  2. package/dist/AutoFetchDataAdapter.d.ts +0 -1
  3. package/dist/Collection/index.d.ts +2 -0
  4. package/dist/DataAdapter.d.ts +7 -6
  5. package/dist/DefaultDataAdapter.d.ts +1 -0
  6. package/dist/WorkerDataAdapter.d.ts +4 -1
  7. package/dist/WorkerDataAdapterHost.d.ts +9 -6
  8. package/dist/index.cjs12.js +32 -21
  9. package/dist/index.cjs13.js +25 -13
  10. package/dist/index.cjs14.js +31 -37
  11. package/dist/index.cjs15.js +120 -75
  12. package/dist/index.cjs16.js +45 -36
  13. package/dist/index.cjs17.js +1 -1
  14. package/dist/index.cjs2.js +5 -2
  15. package/dist/index.cjs20.js +5 -102
  16. package/dist/index.cjs21.js +93 -118
  17. package/dist/index.cjs22.js +127 -5
  18. package/dist/index.cjs23.js +5 -25
  19. package/dist/index.cjs24.js +25 -5
  20. package/dist/index.cjs26.js +1 -1
  21. package/dist/index.cjs27.js +44 -3
  22. package/dist/index.cjs28.js +6 -5
  23. package/dist/index.cjs29.js +7 -27
  24. package/dist/index.cjs3.js +25 -21
  25. package/dist/index.cjs30.js +3 -40
  26. package/dist/index.cjs31.js +5 -7
  27. package/dist/index.cjs32.js +29 -0
  28. package/dist/index.cjs33.js +42 -0
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index12.mjs +32 -21
  31. package/dist/index13.mjs +25 -13
  32. package/dist/index14.mjs +31 -37
  33. package/dist/index15.mjs +120 -75
  34. package/dist/index16.mjs +45 -36
  35. package/dist/index17.mjs +1 -1
  36. package/dist/index2.mjs +5 -2
  37. package/dist/index20.mjs +5 -102
  38. package/dist/index21.mjs +93 -117
  39. package/dist/index22.mjs +126 -5
  40. package/dist/index23.mjs +5 -25
  41. package/dist/index24.mjs +25 -5
  42. package/dist/index26.mjs +1 -1
  43. package/dist/index27.mjs +44 -3
  44. package/dist/index28.mjs +6 -5
  45. package/dist/index29.mjs +7 -27
  46. package/dist/index3.mjs +25 -21
  47. package/dist/index30.mjs +3 -40
  48. package/dist/index31.mjs +5 -7
  49. package/dist/index32.mjs +30 -0
  50. package/dist/index33.mjs +43 -0
  51. package/dist/utils/batchOnNextTick.d.ts +16 -0
  52. package/package.json +1 -1
@@ -1,129 +1,104 @@
1
1
  "use strict";
2
- Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
- const intersection = require("./index.cjs28.js");
4
- function getMergedIndexInfo(queryFunctions, selector) {
5
- return queryFunctions.reduce((memoOrPromise, queryFunction) => {
6
- const resultOrPromise = queryFunction(selector);
7
- const processResult = (memo2, result) => {
8
- if (!result.matched)
9
- return memo2;
10
- const optimizedSelector = result.keepSelector ? memo2.optimizedSelector : Object.fromEntries(Object.entries(memo2.optimizedSelector).filter(([key]) => !result.fields.includes(key)));
11
- return {
12
- matched: true,
13
- ids: [...new Set(memo2.matched ? intersection(memo2.ids, result.ids) : result.ids)],
14
- optimizedSelector
15
- };
16
- };
17
- if (resultOrPromise instanceof Promise) {
18
- return resultOrPromise.then(async (result) => {
19
- const memo2 = memoOrPromise instanceof Promise ? await memoOrPromise : memoOrPromise;
20
- return processResult(memo2, result);
21
- });
2
+ const createIndexProvider = require("./index.cjs30.js");
3
+ const get = require("./index.cjs10.js");
4
+ const getMatchingKeys = require("./index.cjs26.js");
5
+ const serializeValue = require("./index.cjs11.js");
6
+ function createIndex(field) {
7
+ const index = /* @__PURE__ */ new Map();
8
+ const ensureSet = (key) => {
9
+ let set = index.get(key);
10
+ if (!set) {
11
+ set = /* @__PURE__ */ new Set();
12
+ index.set(key, set);
22
13
  }
23
- const memo = memoOrPromise;
24
- if (memo instanceof Promise)
25
- throw new Error("Mixing async and sync index providers is not supported");
26
- return processResult(memo, resultOrPromise);
27
- }, {
28
- matched: false,
29
- ids: [],
30
- optimizedSelector: { ...selector }
31
- });
32
- }
33
- function optimizeLogicGate(queryFunctions, logicGate, idsCallback) {
34
- return logicGate.reduce((memoOrPromise, sel) => {
35
- const getSelector = (indexInfo) => {
36
- const { matched: selMatched, ids: selIds, optimizedSelector: optimizedSelector2 } = indexInfo;
37
- if (selMatched) {
38
- idsCallback(true, selIds);
39
- if (Object.keys(optimizedSelector2).length > 0) {
40
- return optimizedSelector2;
14
+ return set;
15
+ };
16
+ return createIndexProvider({
17
+ query(selector) {
18
+ if (!Object.hasOwnProperty.call(selector, field)) {
19
+ return { matched: false };
20
+ }
21
+ const fieldSelector = selector[field];
22
+ const filteresForNull = fieldSelector == null || fieldSelector.$exists === false;
23
+ const keys = filteresForNull ? { include: null, exclude: [...index.keys()].filter((key) => key != null) } : getMatchingKeys(field, selector);
24
+ if (keys.include == null && keys.exclude == null)
25
+ return { matched: false };
26
+ let includedIds = [];
27
+ if (keys.include == null) {
28
+ for (const set of index.values()) {
29
+ for (const pos of set) {
30
+ includedIds.push(pos);
31
+ }
41
32
  }
42
33
  } else {
43
- idsCallback(false, []);
44
- return sel;
34
+ for (const key of keys.include) {
35
+ const posSet = index.get(key);
36
+ if (posSet) {
37
+ for (const pos of posSet) {
38
+ includedIds.push(pos);
39
+ }
40
+ }
41
+ }
45
42
  }
46
- };
47
- const indexInfoOrPromise = getIndexInfo(queryFunctions, sel);
48
- if (indexInfoOrPromise instanceof Promise) {
49
- return indexInfoOrPromise.then(async (indexInfo) => {
50
- const memo2 = memoOrPromise instanceof Promise ? await memoOrPromise : memoOrPromise;
51
- const optimizedSelector2 = getSelector(indexInfo);
52
- if (optimizedSelector2)
53
- memo2.push(optimizedSelector2);
54
- return memo2;
55
- });
56
- }
57
- const memo = memoOrPromise;
58
- if (memo instanceof Promise)
59
- throw new Error("Mixing async and sync index providers is not supported");
60
- const optimizedSelector = getSelector(indexInfoOrPromise);
61
- if (optimizedSelector)
62
- memo.push(optimizedSelector);
63
- return memo;
64
- }, []);
65
- }
66
- function getIndexInfo(queryFunctions, selector) {
67
- if (selector == null || Object.keys(selector).length <= 0) {
68
- return {
69
- matched: false,
70
- ids: [],
71
- optimizedSelector: selector
72
- };
73
- }
74
- const { $and, $or, ...rest } = selector;
75
- const flatInfoOrPromise = getMergedIndexInfo(queryFunctions, rest);
76
- const processFlatInfo = (flatInfo) => {
77
- let { matched, ids } = flatInfo;
78
- const newSelector = flatInfo.optimizedSelector;
79
- const $andNewOrPromise = Array.isArray($and) ? optimizeLogicGate(queryFunctions, $and, (match, selIds) => {
80
- if (!match)
81
- return;
82
- ids = matched ? intersection(ids, selIds) : selIds;
83
- matched = true;
84
- }) : void 0;
85
- const process$and = ($andNew) => {
86
- if ($andNew && $andNew.length > 0)
87
- newSelector.$and = $andNew;
88
- let hasNonIndexField = false;
89
- const matchedBefore = matched;
90
- const idsBefore = ids;
91
- const process$or = ($orNew) => {
92
- if ($orNew && $orNew.length > 0)
93
- newSelector.$or = $orNew;
94
- if (hasNonIndexField) {
95
- newSelector.$or = $or;
96
- matched = matchedBefore;
97
- ids = idsBefore;
43
+ if (keys.exclude != null) {
44
+ const excludeIds = /* @__PURE__ */ new Set();
45
+ for (const key of keys.exclude) {
46
+ const posSet = index.get(key);
47
+ if (posSet) {
48
+ for (const pos of posSet) {
49
+ excludeIds.add(pos);
50
+ }
51
+ }
98
52
  }
99
- return {
100
- matched,
101
- ids: ids || [],
102
- optimizedSelector: newSelector
103
- };
53
+ includedIds = includedIds.filter((pos) => !excludeIds.has(pos));
54
+ }
55
+ return {
56
+ matched: true,
57
+ ids: includedIds,
58
+ fields: [field],
59
+ keepSelector: filteresForNull
104
60
  };
105
- const $orNewOrPromise = Array.isArray($or) ? optimizeLogicGate(queryFunctions, $or, (match, selIds) => {
106
- if (match) {
107
- ids = [.../* @__PURE__ */ new Set([...ids, ...selIds])];
108
- matched = true;
109
- } else {
110
- hasNonIndexField = true;
61
+ },
62
+ rebuild(items) {
63
+ index.clear();
64
+ items.forEach((item) => {
65
+ const value = serializeValue(get(item, field));
66
+ ensureSet(value).add(item.id);
67
+ });
68
+ },
69
+ // NEW: delta methods
70
+ insert(items) {
71
+ for (const item of items) {
72
+ const value = serializeValue(get(item, field));
73
+ ensureSet(value).add(item.id);
74
+ }
75
+ },
76
+ remove(items) {
77
+ for (const item of items) {
78
+ const value = serializeValue(get(item, field));
79
+ const set = index.get(value);
80
+ if (!set)
81
+ continue;
82
+ set.delete(item.id);
83
+ if (set.size === 0)
84
+ index.delete(value);
85
+ }
86
+ },
87
+ update(pairs) {
88
+ for (const { oldItem, newItem } of pairs) {
89
+ const oldValue = serializeValue(get(oldItem, field));
90
+ const newValue = serializeValue(get(newItem, field));
91
+ if (oldValue === newValue)
92
+ continue;
93
+ const oldSet = index.get(oldValue);
94
+ if (oldSet) {
95
+ oldSet.delete(oldItem.id);
96
+ if (oldSet.size === 0)
97
+ index.delete(oldValue);
111
98
  }
112
- }) : void 0;
113
- if ($orNewOrPromise instanceof Promise) {
114
- return $orNewOrPromise.then(($orNew) => process$or($orNew));
99
+ ensureSet(newValue).add(newItem.id);
115
100
  }
116
- return process$or($orNewOrPromise);
117
- };
118
- if ($andNewOrPromise instanceof Promise) {
119
- return $andNewOrPromise.then(($andNew) => process$and($andNew));
120
101
  }
121
- return process$and($andNewOrPromise);
122
- };
123
- if (flatInfoOrPromise instanceof Promise) {
124
- return flatInfoOrPromise.then(processFlatInfo);
125
- }
126
- return processFlatInfo(flatInfoOrPromise);
102
+ });
127
103
  }
128
- exports.default = getIndexInfo;
129
- exports.getMergedIndexInfo = getMergedIndexInfo;
104
+ module.exports = createIndex;
@@ -1,7 +1,129 @@
1
1
  "use strict";
2
- const mingo = require("mingo");
3
- function match(item, selector) {
4
- const query = new mingo.Query(selector);
5
- return query.test(item);
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const intersection = require("./index.cjs31.js");
4
+ function getMergedIndexInfo(queryFunctions, selector) {
5
+ return queryFunctions.reduce((memoOrPromise, queryFunction) => {
6
+ const resultOrPromise = queryFunction(selector);
7
+ const processResult = (memo2, result) => {
8
+ if (!result.matched)
9
+ return memo2;
10
+ const optimizedSelector = result.keepSelector ? memo2.optimizedSelector : Object.fromEntries(Object.entries(memo2.optimizedSelector).filter(([key]) => !result.fields.includes(key)));
11
+ return {
12
+ matched: true,
13
+ ids: [...new Set(memo2.matched ? intersection(memo2.ids, result.ids) : result.ids)],
14
+ optimizedSelector
15
+ };
16
+ };
17
+ if (resultOrPromise instanceof Promise) {
18
+ return resultOrPromise.then(async (result) => {
19
+ const memo2 = memoOrPromise instanceof Promise ? await memoOrPromise : memoOrPromise;
20
+ return processResult(memo2, result);
21
+ });
22
+ }
23
+ const memo = memoOrPromise;
24
+ if (memo instanceof Promise)
25
+ throw new Error("Mixing async and sync index providers is not supported");
26
+ return processResult(memo, resultOrPromise);
27
+ }, {
28
+ matched: false,
29
+ ids: [],
30
+ optimizedSelector: { ...selector }
31
+ });
6
32
  }
7
- module.exports = match;
33
+ function optimizeLogicGate(queryFunctions, logicGate, idsCallback) {
34
+ return logicGate.reduce((memoOrPromise, sel) => {
35
+ const getSelector = (indexInfo) => {
36
+ const { matched: selMatched, ids: selIds, optimizedSelector: optimizedSelector2 } = indexInfo;
37
+ if (selMatched) {
38
+ idsCallback(true, selIds);
39
+ if (Object.keys(optimizedSelector2).length > 0) {
40
+ return optimizedSelector2;
41
+ }
42
+ } else {
43
+ idsCallback(false, []);
44
+ return sel;
45
+ }
46
+ };
47
+ const indexInfoOrPromise = getIndexInfo(queryFunctions, sel);
48
+ if (indexInfoOrPromise instanceof Promise) {
49
+ return indexInfoOrPromise.then(async (indexInfo) => {
50
+ const memo2 = memoOrPromise instanceof Promise ? await memoOrPromise : memoOrPromise;
51
+ const optimizedSelector2 = getSelector(indexInfo);
52
+ if (optimizedSelector2)
53
+ memo2.push(optimizedSelector2);
54
+ return memo2;
55
+ });
56
+ }
57
+ const memo = memoOrPromise;
58
+ if (memo instanceof Promise)
59
+ throw new Error("Mixing async and sync index providers is not supported");
60
+ const optimizedSelector = getSelector(indexInfoOrPromise);
61
+ if (optimizedSelector)
62
+ memo.push(optimizedSelector);
63
+ return memo;
64
+ }, []);
65
+ }
66
+ function getIndexInfo(queryFunctions, selector) {
67
+ if (selector == null || Object.keys(selector).length <= 0) {
68
+ return {
69
+ matched: false,
70
+ ids: [],
71
+ optimizedSelector: selector
72
+ };
73
+ }
74
+ const { $and, $or, ...rest } = selector;
75
+ const flatInfoOrPromise = getMergedIndexInfo(queryFunctions, rest);
76
+ const processFlatInfo = (flatInfo) => {
77
+ let { matched, ids } = flatInfo;
78
+ const newSelector = flatInfo.optimizedSelector;
79
+ const $andNewOrPromise = Array.isArray($and) ? optimizeLogicGate(queryFunctions, $and, (match, selIds) => {
80
+ if (!match)
81
+ return;
82
+ ids = matched ? intersection(ids, selIds) : selIds;
83
+ matched = true;
84
+ }) : void 0;
85
+ const process$and = ($andNew) => {
86
+ if ($andNew && $andNew.length > 0)
87
+ newSelector.$and = $andNew;
88
+ let hasNonIndexField = false;
89
+ const matchedBefore = matched;
90
+ const idsBefore = ids;
91
+ const process$or = ($orNew) => {
92
+ if ($orNew && $orNew.length > 0)
93
+ newSelector.$or = $orNew;
94
+ if (hasNonIndexField) {
95
+ newSelector.$or = $or;
96
+ matched = matchedBefore;
97
+ ids = idsBefore;
98
+ }
99
+ return {
100
+ matched,
101
+ ids: ids || [],
102
+ optimizedSelector: newSelector
103
+ };
104
+ };
105
+ const $orNewOrPromise = Array.isArray($or) ? optimizeLogicGate(queryFunctions, $or, (match, selIds) => {
106
+ if (match) {
107
+ ids = [.../* @__PURE__ */ new Set([...ids, ...selIds])];
108
+ matched = true;
109
+ } else {
110
+ hasNonIndexField = true;
111
+ }
112
+ }) : void 0;
113
+ if ($orNewOrPromise instanceof Promise) {
114
+ return $orNewOrPromise.then(($orNew) => process$or($orNew));
115
+ }
116
+ return process$or($orNewOrPromise);
117
+ };
118
+ if ($andNewOrPromise instanceof Promise) {
119
+ return $andNewOrPromise.then(($andNew) => process$and($andNew));
120
+ }
121
+ return process$and($andNewOrPromise);
122
+ };
123
+ if (flatInfoOrPromise instanceof Promise) {
124
+ return flatInfoOrPromise.then(processFlatInfo);
125
+ }
126
+ return processFlatInfo(flatInfoOrPromise);
127
+ }
128
+ exports.default = getIndexInfo;
129
+ exports.getMergedIndexInfo = getMergedIndexInfo;
@@ -1,27 +1,7 @@
1
1
  "use strict";
2
- const get = require("./index.cjs10.js");
3
- const set = require("./index.cjs29.js");
4
- function project(item, fields) {
5
- const allFieldsDeactivated = Object.values(fields).every((value) => value === 0);
6
- if (allFieldsDeactivated) {
7
- const result2 = { ...item };
8
- Object.keys(fields).forEach((key) => {
9
- const fieldValue = get(item, key);
10
- if (fieldValue === void 0)
11
- return;
12
- set(result2, key, void 0, true);
13
- });
14
- return result2;
15
- }
16
- const result = {};
17
- Object.entries(fields).forEach(([key, value]) => {
18
- const fieldValue = get(item, key);
19
- if (fieldValue === void 0)
20
- return;
21
- if (fieldValue == null && value !== 1)
22
- return;
23
- set(result, key, value === 1 ? fieldValue : void 0);
24
- });
25
- return result;
2
+ const mingo = require("mingo");
3
+ function match(item, selector) {
4
+ const query = new mingo.Query(selector);
5
+ return query.test(item);
26
6
  }
27
- module.exports = project;
7
+ module.exports = match;
@@ -1,7 +1,27 @@
1
1
  "use strict";
2
- function queryId(selector, options) {
3
- const selectorId = JSON.stringify(selector);
4
- const optionsId = options == null ? -1 : JSON.stringify(options);
5
- return `${selectorId}:${optionsId}`;
2
+ const get = require("./index.cjs10.js");
3
+ const set = require("./index.cjs32.js");
4
+ function project(item, fields) {
5
+ const allFieldsDeactivated = Object.values(fields).every((value) => value === 0);
6
+ if (allFieldsDeactivated) {
7
+ const result2 = { ...item };
8
+ Object.keys(fields).forEach((key) => {
9
+ const fieldValue = get(item, key);
10
+ if (fieldValue === void 0)
11
+ return;
12
+ set(result2, key, void 0, true);
13
+ });
14
+ return result2;
15
+ }
16
+ const result = {};
17
+ Object.entries(fields).forEach(([key, value]) => {
18
+ const fieldValue = get(item, key);
19
+ if (fieldValue === void 0)
20
+ return;
21
+ if (fieldValue == null && value !== 1)
22
+ return;
23
+ set(result, key, value === 1 ? fieldValue : void 0);
24
+ });
25
+ return result;
6
26
  }
7
- module.exports = queryId;
27
+ module.exports = project;
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const isFieldExpression = require("./index.cjs30.js");
2
+ const isFieldExpression = require("./index.cjs33.js");
3
3
  const serializeValue = require("./index.cjs11.js");
4
4
  function getMatchingKeys(field, selector) {
5
5
  const result = { include: null, exclude: null };
@@ -1,5 +1,46 @@
1
1
  "use strict";
2
- function createIndexProvider(definition) {
3
- return definition;
2
+ function batchOnNextTick(onFlush) {
3
+ const queues = /* @__PURE__ */ new Map();
4
+ function enqueue(key, args) {
5
+ return new Promise((resolve, reject) => {
6
+ let q = queues.get(key);
7
+ if (!q) {
8
+ q = {
9
+ timer: null,
10
+ items: [],
11
+ flush: () => flush(key)
12
+ };
13
+ queues.set(key, q);
14
+ }
15
+ q.items.push({ args, resolve, reject });
16
+ if (q.timer == null) {
17
+ q.timer = setTimeout(() => {
18
+ q.timer = null;
19
+ void q.flush();
20
+ }, 0);
21
+ }
22
+ });
23
+ }
24
+ async function flush(key) {
25
+ const q = queues.get(key);
26
+ if (!q || q.items.length === 0)
27
+ return;
28
+ if (q.timer != null) {
29
+ clearTimeout(q.timer);
30
+ q.timer = null;
31
+ }
32
+ const items = q.items.splice(0);
33
+ onFlush(key, items.map((i) => i.args)).then((results) => {
34
+ for (const [index, result] of results.entries()) {
35
+ const { resolve } = items[index];
36
+ resolve(result);
37
+ }
38
+ }).catch((error) => {
39
+ for (const { reject } of items) {
40
+ reject(error);
41
+ }
42
+ });
43
+ }
44
+ return { enqueue, flush };
4
45
  }
5
- module.exports = createIndexProvider;
46
+ module.exports = batchOnNextTick;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
- function intersection(...arrays) {
3
- if (arrays.length === 0)
4
- return [];
5
- return [...new Set(arrays.reduce((a, b) => a.filter((c) => b.includes(c))))];
2
+ function truthy(value) {
3
+ return !!value;
6
4
  }
7
- module.exports = intersection;
5
+ function compact(array) {
6
+ return array.filter(truthy);
7
+ }
8
+ module.exports = compact;
@@ -1,29 +1,9 @@
1
1
  "use strict";
2
- function set(object, path, value, deleteIfUndefined = false) {
3
- if (object == null)
4
- return object;
5
- const segments = path.split(/[.[\]]/g);
6
- if (segments[0] === "")
7
- segments.shift();
8
- if (segments.at(-1) === "")
9
- segments.pop();
10
- const apply = (node) => {
11
- if (segments.length > 1) {
12
- const key = segments.shift();
13
- const nextIsNumber = !Number.isNaN(Number.parseInt(segments[0], 10));
14
- if (node[key] === void 0) {
15
- node[key] = nextIsNumber ? [] : {};
16
- }
17
- apply(node[key]);
18
- } else {
19
- if (deleteIfUndefined && value === void 0) {
20
- delete node[segments[0]];
21
- return;
22
- }
23
- node[segments[0]] = value;
24
- }
25
- };
26
- apply(object);
27
- return object;
2
+ function uniqueBy(array, fn) {
3
+ const set = /* @__PURE__ */ new Set();
4
+ return array.filter((element) => {
5
+ const value = typeof fn === "function" ? fn(element) : element[fn];
6
+ return !set.has(value) && set.add(value);
7
+ });
28
8
  }
29
- module.exports = set;
9
+ module.exports = uniqueBy;
@@ -6,6 +6,7 @@ const randomId = require("./index.cjs8.js");
6
6
  const DefaultDataAdapter = require("./index.cjs12.js");
7
7
  const modify = require("./index.cjs7.js");
8
8
  const deepClone = require("./index.cjs19.js");
9
+ const queryId = require("./index.cjs20.js");
9
10
  const Cursor = require("./index.cjs2.js");
10
11
  class Collection extends EventEmitter {
11
12
  static collections = [];
@@ -68,6 +69,7 @@ class Collection extends EventEmitter {
68
69
  isDisposed = false;
69
70
  postBatchCallbacks = /* @__PURE__ */ new Set();
70
71
  fieldTracking = false;
72
+ queryListenersMap = /* @__PURE__ */ new Map();
71
73
  constructor(nameOrOptions, maybeDataAdapter, maybeOptions) {
72
74
  super();
73
75
  const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions?.name || `${this.constructor.name}-${randomId()}`;
@@ -206,21 +208,9 @@ class Collection extends EventEmitter {
206
208
  return this.profile(() => {
207
209
  if (!options?.async)
208
210
  return this.backend.getQueryResult(selector, options);
209
- return new Promise((resolve, reject) => {
210
- this.isPullingSignal.set(true);
211
- const cleanup = this.backend.onQueryStateChange(selector, options, (state) => {
212
- if (state === "error") {
213
- cleanup();
214
- reject(this.backend.getQueryError(selector, options) || new Error("Unknown error"));
215
- } else if (state === "complete") {
216
- cleanup();
217
- resolve(this.backend.getQueryResult(selector, options) || []);
218
- }
219
- });
220
- this.backend.registerQuery(selector, options);
221
- }).finally(() => {
211
+ this.isPullingSignal.set(true);
212
+ return this.backend.executeQuery(selector, options).finally(() => {
222
213
  this.isPullingSignal.set(false);
223
- this.backend.unregisterQuery(selector, options);
224
214
  });
225
215
  }, (measuredTime) => this.executeInDebugMode((callstack) => this.emit("_debug.getItems", callstack, selector, measuredTime)));
226
216
  }
@@ -232,6 +222,13 @@ class Collection extends EventEmitter {
232
222
  this.isPushingSignal.set(false);
233
223
  }
234
224
  }
225
+ queryListeners(query, listeners) {
226
+ const id = queryId(query.selector, query.options);
227
+ if (listeners != null) {
228
+ return this.queryListenersMap.set(id, listeners);
229
+ }
230
+ return this.queryListenersMap.get(id) ?? 0;
231
+ }
235
232
  /**
236
233
  * Disposes the collection, unregisters persistence adapters, clears memory, and
237
234
  * cleans up all resources used by the collection.
@@ -270,17 +267,25 @@ class Collection extends EventEmitter {
270
267
  }
271
268
  requery();
272
269
  };
273
- this.backend.registerQuery(selector, options);
274
- const queryStateChangeCleanup = this.backend.onQueryStateChange(selector, options, (state) => {
270
+ const listeners = this.queryListeners({ selector, options });
271
+ if (listeners === 0)
272
+ this.backend.registerQuery(selector, options || {});
273
+ this.queryListeners({ selector, options }, listeners + 1);
274
+ const queryStateChangeCleanup = this.backend.onQueryStateChange(selector, options || {}, (state) => {
275
275
  if (state !== "complete")
276
276
  return;
277
277
  handleRequery();
278
278
  });
279
279
  this.emit("observer.created", selector, options);
280
280
  return () => {
281
- this.backend.unregisterQuery(selector, options);
282
- queryStateChangeCleanup();
283
- this.emit("observer.disposed", selector, options);
281
+ setTimeout(() => {
282
+ const newListeners = Math.max(0, this.queryListeners({ selector, options }) - 1);
283
+ if (newListeners === 0)
284
+ this.backend.unregisterQuery(selector, options || {});
285
+ this.queryListeners({ selector, options }, newListeners);
286
+ queryStateChangeCleanup();
287
+ this.emit("observer.disposed", selector, options);
288
+ }, 0);
284
289
  };
285
290
  }
286
291
  });
@@ -373,9 +378,8 @@ class Collection extends EventEmitter {
373
378
  throw new Error("Collection is disposed");
374
379
  if (!items)
375
380
  throw new Error("Invalid items");
376
- if (items.length === 0) {
381
+ if (items.length === 0)
377
382
  return [];
378
- }
379
383
  const ids = [];
380
384
  await this.batch(async () => {
381
385
  await Promise.all(items.map(async (item) => {
@@ -1,42 +1,5 @@
1
1
  "use strict";
2
- const expressionKeys = /* @__PURE__ */ new Set([
3
- "$eq",
4
- "$gt",
5
- "$gte",
6
- "$lt",
7
- "$lte",
8
- "$in",
9
- "$nin",
10
- "$ne",
11
- "$exists",
12
- "$not",
13
- "$expr",
14
- "$jsonSchema",
15
- "$mod",
16
- "$regex",
17
- "$options",
18
- "$text",
19
- "$where",
20
- "$all",
21
- "$elemMatch",
22
- "$size",
23
- "$bitsAllClear",
24
- "$bitsAllSet",
25
- "$bitsAnyClear",
26
- "$bitsAnySet"
27
- ]);
28
- function isFieldExpression(expression) {
29
- if (typeof expression !== "object" || expression == null) {
30
- return false;
31
- }
32
- const keys = Object.keys(expression);
33
- if (keys.length === 0) {
34
- return false;
35
- }
36
- const hasInvalidKeys = keys.some((key) => !expressionKeys.has(key));
37
- if (hasInvalidKeys)
38
- return false;
39
- const hasValidKeys = keys.every((key) => expressionKeys.has(key));
40
- return hasValidKeys;
2
+ function createIndexProvider(definition) {
3
+ return definition;
41
4
  }
42
- module.exports = isFieldExpression;
5
+ module.exports = createIndexProvider;