tinybase 1.3.6 → 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 (61) hide show
  1. package/lib/checkpoints.d.ts +4 -3
  2. package/lib/checkpoints.js +1 -1
  3. package/lib/checkpoints.js.gz +0 -0
  4. package/lib/debug/checkpoints.d.ts +4 -3
  5. package/lib/debug/checkpoints.js +69 -56
  6. package/lib/debug/indexes.d.ts +4 -2
  7. package/lib/debug/indexes.js +106 -69
  8. package/lib/debug/metrics.d.ts +1 -1
  9. package/lib/debug/metrics.js +187 -131
  10. package/lib/debug/persisters.d.ts +6 -0
  11. package/lib/debug/persisters.js +2 -1
  12. package/lib/debug/queries.d.ts +3251 -0
  13. package/lib/debug/queries.js +900 -0
  14. package/lib/debug/relationships.d.ts +12 -10
  15. package/lib/debug/relationships.js +104 -68
  16. package/lib/debug/store.d.ts +415 -74
  17. package/lib/debug/store.js +295 -120
  18. package/lib/debug/tinybase.d.ts +1 -0
  19. package/lib/debug/tinybase.js +985 -176
  20. package/lib/debug/ui-react.d.ts +4325 -1754
  21. package/lib/debug/ui-react.js +413 -85
  22. package/lib/indexes.d.ts +4 -2
  23. package/lib/indexes.js +1 -1
  24. package/lib/indexes.js.gz +0 -0
  25. package/lib/metrics.d.ts +1 -1
  26. package/lib/metrics.js +1 -1
  27. package/lib/metrics.js.gz +0 -0
  28. package/lib/persisters.d.ts +6 -0
  29. package/lib/queries.d.ts +3251 -0
  30. package/lib/queries.js +1 -0
  31. package/lib/queries.js.gz +0 -0
  32. package/lib/relationships.d.ts +12 -10
  33. package/lib/relationships.js +1 -1
  34. package/lib/relationships.js.gz +0 -0
  35. package/lib/store.d.ts +415 -74
  36. package/lib/store.js +1 -1
  37. package/lib/store.js.gz +0 -0
  38. package/lib/tinybase.d.ts +1 -0
  39. package/lib/tinybase.js +1 -1
  40. package/lib/tinybase.js.gz +0 -0
  41. package/lib/ui-react.d.ts +4325 -1754
  42. package/lib/ui-react.js +1 -1
  43. package/lib/ui-react.js.gz +0 -0
  44. package/lib/umd/checkpoints.js +1 -1
  45. package/lib/umd/checkpoints.js.gz +0 -0
  46. package/lib/umd/indexes.js +1 -1
  47. package/lib/umd/indexes.js.gz +0 -0
  48. package/lib/umd/metrics.js +1 -1
  49. package/lib/umd/metrics.js.gz +0 -0
  50. package/lib/umd/queries.js +1 -0
  51. package/lib/umd/queries.js.gz +0 -0
  52. package/lib/umd/relationships.js +1 -1
  53. package/lib/umd/relationships.js.gz +0 -0
  54. package/lib/umd/store.js +1 -1
  55. package/lib/umd/store.js.gz +0 -0
  56. package/lib/umd/tinybase.js +1 -1
  57. package/lib/umd/tinybase.js.gz +0 -0
  58. package/lib/umd/ui-react.js +1 -1
  59. package/lib/umd/ui-react.js.gz +0 -0
  60. package/package.json +4 -4
  61. package/readme.md +2 -2
@@ -15,10 +15,14 @@ const AVG = 'avg';
15
15
  const MIN = 'min';
16
16
  const MAX = 'max';
17
17
 
18
- const arrayPair = (value) => [value, value];
19
18
  const arrayHas = (array, value) => array.includes(value);
19
+ const arrayEvery = (array, cb) => array.every(cb);
20
+ const arrayIsEqual = (array1, array2) =>
21
+ arrayLength(array1) === arrayLength(array2) &&
22
+ arrayEvery(array1, (value1, index) => array2[index] === value1);
20
23
  const arrayIsSorted = (array, sorter) =>
21
- array.every(
24
+ arrayEvery(
25
+ array,
22
26
  (value, index) => index == 0 || sorter(array[index - 1], value) <= 0,
23
27
  );
24
28
  const arraySort = (array, sorter) => array.sort(sorter);
@@ -29,9 +33,9 @@ const arrayLength = (array) => array.length;
29
33
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
30
34
  const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
31
35
  const arrayFilter = (array, cb) => array.filter(cb);
32
- const arrayFromSecond = (ids) => ids.slice(1);
36
+ const arraySlice = (array, start, end) => array.slice(start, end);
33
37
  const arrayClear = (array, to) => array.splice(0, to);
34
- const arrayPush = (array, value) => array.push(value);
38
+ const arrayPush = (array, ...values) => array.push(...values);
35
39
  const arrayPop = (array) => array.pop();
36
40
 
37
41
  const jsonString = (obj) =>
@@ -66,7 +70,6 @@ const collSize = (coll) => coll.size;
66
70
  const collSize2 = collSizeN(collSize);
67
71
  const collSize3 = collSizeN(collSize2);
68
72
  const collSize4 = collSizeN(collSize3);
69
- const collPairSize = (pair, func = collSize) => func(pair[0]) + func(pair[1]);
70
73
  const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
71
74
  const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
72
75
  const collValues = (coll) => [...(coll?.values() ?? [])];
@@ -75,7 +78,6 @@ const collForEach = (coll, cb) => coll?.forEach(cb);
75
78
  const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
76
79
 
77
80
  const mapNew = (entries) => new Map(entries);
78
- const mapNewPair = (newFunction = mapNew) => [newFunction(), newFunction()];
79
81
  const mapKeys = (map) => [...(map?.keys() ?? [])];
80
82
  const mapGet = (map, key) => map?.get(key);
81
83
  const mapForEach = (map, cb) =>
@@ -105,6 +107,27 @@ const mapClone = (map, childMapper) => {
105
107
  return map2;
106
108
  };
107
109
  const mapClone2 = (map) => mapClone(map, mapClone);
110
+ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
111
+ ifNotUndefined(
112
+ (ensureLeaf ? mapEnsure : mapGet)(
113
+ node,
114
+ path[p],
115
+ p > arrayLength(path) - 2 ? ensureLeaf : mapNew,
116
+ ),
117
+ (nodeOrLeaf) => {
118
+ if (p > arrayLength(path) - 2) {
119
+ if (pruneLeaf?.(nodeOrLeaf)) {
120
+ mapSet(node, path[p]);
121
+ }
122
+ return nodeOrLeaf;
123
+ }
124
+ const leaf = visitTree(nodeOrLeaf, path, ensureLeaf, pruneLeaf, p + 1);
125
+ if (collIsEmpty(nodeOrLeaf)) {
126
+ mapSet(node, path[p]);
127
+ }
128
+ return leaf;
129
+ },
130
+ );
108
131
 
109
132
  const setNew = (entries) => new Set(entries);
110
133
  const setAdd = (set, value) => set?.add(value);
@@ -123,20 +146,46 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
123
146
  const getTableId = (id) => mapGet(tableIds, id);
124
147
  const getThing = (id) => mapGet(things, id);
125
148
  const setThing = (id, thing) => mapSet(things, id, thing);
126
- const removeStoreListeners = (id) =>
127
- ifNotUndefined(mapGet(storeListenerIds, id), (listenerIds) => {
128
- collForEach(listenerIds, store.delListener);
129
- mapSet(storeListenerIds, id);
149
+ const addStoreListeners = (id, andCall, ...listenerIds) => {
150
+ const set = mapEnsure(storeListenerIds, id, setNew);
151
+ arrayForEach(
152
+ listenerIds,
153
+ (listenerId) =>
154
+ setAdd(set, listenerId) && andCall && store.callListener(listenerId),
155
+ );
156
+ return listenerIds;
157
+ };
158
+ const delStoreListeners = (id, ...listenerIds) =>
159
+ ifNotUndefined(mapGet(storeListenerIds, id), (allListenerIds) => {
160
+ arrayForEach(
161
+ arrayIsEmpty(listenerIds) ? collValues(allListenerIds) : listenerIds,
162
+ (listenerId) => {
163
+ store.delListener(listenerId);
164
+ collDel(allListenerIds, listenerId);
165
+ },
166
+ );
167
+ if (collIsEmpty(allListenerIds)) {
168
+ mapSet(storeListenerIds, id);
169
+ }
130
170
  });
131
- const setDefinition = (id, tableId, onChanged, getRowValue, getSortKey) => {
132
- const changedRowValues = mapNew();
133
- const changedSortKeys = mapNew();
171
+ const setDefinition = (id, tableId) => {
134
172
  mapSet(tableIds, id, tableId);
135
173
  if (!collHas(things, id)) {
136
174
  mapSet(things, id, getDefaultThing());
137
175
  mapSet(allRowValues, id, mapNew());
138
176
  mapSet(allSortKeys, id, mapNew());
139
177
  }
178
+ };
179
+ const setDefinitionAndListen = (
180
+ id,
181
+ tableId,
182
+ onChanged,
183
+ getRowValue,
184
+ getSortKey,
185
+ ) => {
186
+ setDefinition(id, tableId);
187
+ const changedRowValues = mapNew();
188
+ const changedSortKeys = mapNew();
140
189
  const rowValues = mapGet(allRowValues, id);
141
190
  const sortKeys = mapGet(allSortKeys, id);
142
191
  const processRow = (rowId) => {
@@ -186,16 +235,14 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
186
235
  });
187
236
  }
188
237
  processTable(true);
189
- removeStoreListeners(id);
190
- mapSet(
191
- storeListenerIds,
238
+ delStoreListeners(id);
239
+ addStoreListeners(
192
240
  id,
193
- setNew([
194
- store.addRowListener(tableId, null, (_store, _tableId, rowId) =>
195
- processRow(rowId),
196
- ),
197
- store.addTableListener(tableId, () => processTable()),
198
- ]),
241
+ 0,
242
+ store.addRowListener(tableId, null, (_store, _tableId, rowId) =>
243
+ processRow(rowId),
244
+ ),
245
+ store.addTableListener(tableId, () => processTable()),
199
246
  );
200
247
  };
201
248
  const delDefinition = (id) => {
@@ -203,7 +250,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
203
250
  mapSet(things, id);
204
251
  mapSet(allRowValues, id);
205
252
  mapSet(allSortKeys, id);
206
- removeStoreListeners(id);
253
+ delStoreListeners(id);
207
254
  };
208
255
  const destroy = () => mapForEach(storeListenerIds, delDefinition);
209
256
  return [
@@ -215,8 +262,11 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
215
262
  getThing,
216
263
  setThing,
217
264
  setDefinition,
265
+ setDefinitionAndListen,
218
266
  delDefinition,
219
267
  destroy,
268
+ addStoreListeners,
269
+ delStoreListeners,
220
270
  ];
221
271
  };
222
272
  const getRowCellFunction = (getRowCell, defaultCellValue) =>
@@ -233,64 +283,51 @@ const getCreateFunction = (getFunction) => {
233
283
  };
234
284
  };
235
285
 
236
- const addDeepSet = (deepSet, value, ids) =>
237
- arrayLength(ids) < 2
238
- ? setAdd(
239
- arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew),
240
- value,
241
- )
242
- : addDeepSet(
243
- mapEnsure(deepSet, ids[0], mapNew),
244
- value,
245
- arrayFromSecond(ids),
246
- );
247
- const forDeepSet = (valueDo) => {
248
- const deep = (deepIdSet, arg, ...ids) =>
249
- ifNotUndefined(deepIdSet, (deepIdSet2) =>
250
- arrayIsEmpty(ids)
251
- ? valueDo(deepIdSet2, arg)
252
- : arrayForEach([ids[0], null], (id) =>
253
- deep(mapGet(deepIdSet2, id), arg, ...arrayFromSecond(ids)),
254
- ),
255
- );
256
- return deep;
286
+ const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
287
+ const leaves = [];
288
+ const deep = (node, p) =>
289
+ p == arrayLength(path)
290
+ ? arrayPush(leaves, node)
291
+ : path[p] === null
292
+ ? collForEach(node, (node2) => deep(node2, p + 1))
293
+ : arrayForEach([path[p], null], (id) => deep(mapGet(node, id), p + 1));
294
+ deep(deepIdSet, 0);
295
+ return leaves;
257
296
  };
258
297
  const getListenerFunctions = (getThing) => {
259
298
  let thing;
260
299
  let nextId = 0;
261
300
  const listenerPool = [];
262
301
  const allListeners = mapNew();
263
- const addListener = (listener, deepSet, idOrNulls = []) => {
302
+ const addListener = (listener, idSetNode, path) => {
264
303
  thing ??= getThing();
265
- const id = arrayPop(listenerPool) ?? '' + nextId++;
266
- mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
267
- addDeepSet(deepSet, id, idOrNulls);
304
+ const id = arrayPop(listenerPool) ?? EMPTY_STRING + nextId++;
305
+ mapSet(allListeners, id, [listener, idSetNode, path]);
306
+ setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
268
307
  return id;
269
308
  };
270
- const callListeners = (deepSet, ids = [], ...extraArgs) =>
271
- forDeepSet(collForEach)(
272
- deepSet,
273
- (id) =>
274
- ifNotUndefined(mapGet(allListeners, id), ([listener]) =>
275
- listener(thing, ...ids, ...extraArgs),
276
- ),
277
- ...ids,
309
+ const callListeners = (idSetNode, ids, ...extraArgs) =>
310
+ arrayForEach(getWildcardedLeaves(idSetNode, ids), (set) =>
311
+ collForEach(set, (id) =>
312
+ mapGet(allListeners, id)[0](thing, ...(ids ?? []), ...extraArgs),
313
+ ),
278
314
  );
279
315
  const delListener = (id) =>
280
- ifNotUndefined(
281
- mapGet(allListeners, id),
282
- ([, deepSet, idOrNulls]) => {
283
- forDeepSet(collDel)(deepSet, id, ...idOrNulls);
284
- mapSet(allListeners, id);
285
- if (arrayLength(listenerPool) < 1e3) {
286
- arrayPush(listenerPool, id);
287
- }
288
- return idOrNulls;
289
- },
290
- () => [],
291
- );
316
+ ifNotUndefined(mapGet(allListeners, id), ([, idSetNode, idOrNulls]) => {
317
+ visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], void 0, (idSet) => {
318
+ collDel(idSet, id);
319
+ return collIsEmpty(idSet) ? 1 : 0;
320
+ });
321
+ mapSet(allListeners, id);
322
+ if (arrayLength(listenerPool) < 1e3) {
323
+ arrayPush(listenerPool, id);
324
+ }
325
+ return idOrNulls;
326
+ });
327
+ const hasListeners = (idSetNode, ids) =>
328
+ !arrayEvery(getWildcardedLeaves(idSetNode, ids), isUndefined);
292
329
  const callListener = (id, idNullGetters, extraArgsGetter) =>
293
- ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls]) => {
330
+ ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls = []]) => {
294
331
  const callWithIds = (...ids) => {
295
332
  const index = arrayLength(ids);
296
333
  index == arrayLength(idOrNulls)
@@ -303,7 +340,7 @@ const getListenerFunctions = (getThing) => {
303
340
  };
304
341
  callWithIds();
305
342
  });
306
- return [addListener, callListeners, delListener, callListener];
343
+ return [addListener, callListeners, delListener, hasListeners, callListener];
307
344
  };
308
345
 
309
346
  const object = Object;
@@ -319,6 +356,17 @@ const objForEach = (obj, cb) =>
319
356
  arrayForEach(object.entries(obj), ([id, value]) => cb(value, id));
320
357
  const objIsEmpty = (obj) => arrayIsEmpty(objIds(obj));
321
358
 
359
+ const getCellType = (cell) => {
360
+ const type = getTypeOf(cell);
361
+ return isTypeStringOrBoolean(type) || (type == NUMBER && isFiniteNumber(cell))
362
+ ? type
363
+ : void 0;
364
+ };
365
+ const setOrDelCell = (store, tableId, rowId, cellId, cell) =>
366
+ isUndefined(cell)
367
+ ? store.delCell(tableId, rowId, cellId, true)
368
+ : store.setCell(tableId, rowId, cellId, cell);
369
+
322
370
  const createCheckpoints = getCreateFunction((store) => {
323
371
  let backwardIdsSize = 100;
324
372
  let currentId;
@@ -326,7 +374,7 @@ const createCheckpoints = getCreateFunction((store) => {
326
374
  let listening = 1;
327
375
  let nextCheckpointId;
328
376
  let checkpointsChanged;
329
- const checkpointIdsListeners = setNew();
377
+ const checkpointIdsListeners = mapNew();
330
378
  const checkpointListeners = mapNew();
331
379
  const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
332
380
  () => checkpoints,
@@ -341,9 +389,7 @@ const createCheckpoints = getCreateFunction((store) => {
341
389
  collForEach(mapGet(deltas, checkpointId), (table, tableId) =>
342
390
  collForEach(table, (row, rowId) =>
343
391
  collForEach(row, (oldNew, cellId) =>
344
- isUndefined(oldNew[oldOrNew])
345
- ? store.delCell(tableId, rowId, cellId, true)
346
- : store.setCell(tableId, rowId, cellId, oldNew[oldOrNew]),
392
+ setOrDelCell(store, tableId, rowId, cellId, oldNew[oldOrNew]),
347
393
  ),
348
394
  ),
349
395
  ),
@@ -393,9 +439,9 @@ const createCheckpoints = getCreateFunction((store) => {
393
439
  }
394
440
  },
395
441
  );
396
- const addCheckpointImpl = (label = '') => {
442
+ const addCheckpointImpl = (label = EMPTY_STRING) => {
397
443
  if (isUndefined(currentId)) {
398
- currentId = '' + nextCheckpointId++;
444
+ currentId = EMPTY_STRING + nextCheckpointId++;
399
445
  mapSet(deltas, currentId, delta);
400
446
  setCheckpoint(currentId, label);
401
447
  delta = mapNew();
@@ -493,7 +539,7 @@ const createCheckpoints = getCreateFunction((store) => {
493
539
  store.delListener(listenerId);
494
540
  };
495
541
  const getListenerStats = () => ({
496
- checkpointIds: collSize(checkpointIdsListeners),
542
+ checkpointIds: collSize2(checkpointIdsListeners),
497
543
  checkpoint: collSize2(checkpointListeners),
498
544
  });
499
545
  const checkpoints = {
@@ -532,7 +578,8 @@ const createIndexes = getCreateFunction((store) => {
532
578
  getTableId,
533
579
  getIndex,
534
580
  setIndex,
535
- setDefinition,
581
+ ,
582
+ setDefinitionAndListen,
536
583
  delDefinition,
537
584
  destroy,
538
585
  ] = getDefinableFunctions(store, mapNew, (value) =>
@@ -553,7 +600,7 @@ const createIndexes = getCreateFunction((store) => {
553
600
  const sliceIdArraySorter = isUndefined(sliceIdSorter)
554
601
  ? void 0
555
602
  : ([id1], [id2]) => sliceIdSorter(id1, id2);
556
- setDefinition(
603
+ setDefinitionAndListen(
557
604
  indexId,
558
605
  tableId,
559
606
  (change, changedSliceIds, changedSortKeys, sliceIds, sortKeys, force) => {
@@ -697,7 +744,7 @@ const createIndexes = getCreateFunction((store) => {
697
744
  return objFreeze(indexes);
698
745
  });
699
746
 
700
- const aggregators = mapNew([
747
+ const numericAggregators = mapNew([
701
748
  [
702
749
  AVG,
703
750
  [
@@ -737,6 +784,35 @@ const aggregators = mapNew([
737
784
  ],
738
785
  ],
739
786
  ]);
787
+ const getAggregateValue = (
788
+ aggregateValue,
789
+ oldLength,
790
+ newValues,
791
+ changedValues,
792
+ aggregators,
793
+ force = false,
794
+ ) => {
795
+ if (collIsEmpty(newValues)) {
796
+ return void 0;
797
+ }
798
+ const [aggregate, aggregateAdd, aggregateRemove, aggregateReplace] =
799
+ aggregators;
800
+ force ||= isUndefined(aggregateValue);
801
+ collForEach(changedValues, ([oldValue, newValue]) => {
802
+ if (!force) {
803
+ aggregateValue = isUndefined(oldValue)
804
+ ? aggregateAdd?.(aggregateValue, newValue, oldLength++)
805
+ : isUndefined(newValue)
806
+ ? aggregateRemove?.(aggregateValue, oldValue, oldLength--)
807
+ : aggregateReplace?.(aggregateValue, newValue, oldValue, oldLength);
808
+ force ||= isUndefined(aggregateValue);
809
+ }
810
+ });
811
+ return force
812
+ ? aggregate(collValues(newValues), collSize(newValues))
813
+ : aggregateValue;
814
+ };
815
+
740
816
  const createMetrics = getCreateFunction((store) => {
741
817
  const metricListeners = mapNew();
742
818
  const [
@@ -747,7 +823,8 @@ const createMetrics = getCreateFunction((store) => {
747
823
  getTableId,
748
824
  getMetric,
749
825
  setMetric,
750
- setDefinition,
826
+ ,
827
+ setDefinitionAndListen,
751
828
  delDefinition,
752
829
  destroy,
753
830
  ] = getDefinableFunctions(store, getUndefined, (value) =>
@@ -771,38 +848,29 @@ const createMetrics = getCreateFunction((store) => {
771
848
  aggregateRemove,
772
849
  aggregateReplace,
773
850
  ) => {
774
- const metricAggregators = isFunction(aggregate)
851
+ const aggregators = isFunction(aggregate)
775
852
  ? [aggregate, aggregateAdd, aggregateRemove, aggregateReplace]
776
- : mapGet(aggregators, aggregate) ?? mapGet(aggregators, SUM);
777
- setDefinition(
853
+ : mapGet(numericAggregators, aggregate) ??
854
+ mapGet(numericAggregators, SUM);
855
+ setDefinitionAndListen(
778
856
  metricId,
779
857
  tableId,
780
858
  (change, changedNumbers, _changedSortKeys, numbers, _sortKeys, force) => {
781
- let newMetric = getMetric(metricId);
782
- let length = collSize(numbers);
783
- const [aggregate2, aggregateAdd2, aggregateRemove2, aggregateReplace2] =
784
- metricAggregators;
785
- force = force || isUndefined(newMetric);
786
- collForEach(changedNumbers, ([oldNumber, newNumber]) => {
787
- if (!force) {
788
- newMetric = isUndefined(oldNumber)
789
- ? aggregateAdd2?.(newMetric, newNumber, length++)
790
- : isUndefined(newNumber)
791
- ? aggregateRemove2?.(newMetric, oldNumber, length--)
792
- : aggregateReplace2?.(newMetric, newNumber, oldNumber, length);
793
- }
794
- force = force || isUndefined(newMetric);
795
- });
859
+ const oldMetric = getMetric(metricId);
860
+ const oldLength = collSize(numbers);
861
+ force ||= isUndefined(oldMetric);
796
862
  change();
797
- if (collIsEmpty(numbers)) {
798
- newMetric = void 0;
799
- } else if (force) {
800
- newMetric = aggregate2(collValues(numbers), collSize(numbers));
801
- }
863
+ let newMetric = getAggregateValue(
864
+ oldMetric,
865
+ oldLength,
866
+ numbers,
867
+ changedNumbers,
868
+ aggregators,
869
+ force,
870
+ );
802
871
  if (!isFiniteNumber(newMetric)) {
803
872
  newMetric = void 0;
804
873
  }
805
- const oldMetric = getMetric(metricId);
806
874
  if (newMetric != oldMetric) {
807
875
  setMetric(metricId, newMetric);
808
876
  callListeners(metricListeners, [metricId], newMetric, oldMetric);
@@ -860,7 +928,7 @@ const createCustomPersister = (
860
928
  loads++;
861
929
  }
862
930
  const body = await getPersisted();
863
- if (!isUndefined(body) && body != '') {
931
+ if (!isUndefined(body) && body != EMPTY_STRING) {
864
932
  store.setJson(body);
865
933
  } else {
866
934
  store.setTables(initialTables);
@@ -1013,6 +1081,591 @@ const createRemotePersister = (
1013
1081
  );
1014
1082
  };
1015
1083
 
1084
+ const createQueries = getCreateFunction((store) => {
1085
+ const createStore = store.createStore;
1086
+ const [
1087
+ getStore,
1088
+ getQueryIds,
1089
+ forEachQuery,
1090
+ hasQuery,
1091
+ getTableId,
1092
+ ,
1093
+ ,
1094
+ setDefinition,
1095
+ ,
1096
+ delDefinition,
1097
+ destroy,
1098
+ addStoreListeners,
1099
+ delStoreListeners,
1100
+ ] = getDefinableFunctions(store, () => true, getUndefined);
1101
+ const preStore1 = createStore();
1102
+ const preStore2 = createStore();
1103
+ const resultStore = createStore();
1104
+ const preStoreListenerIds = mapNew();
1105
+ const addPreStoreListener = (preStore, queryId, ...listenerIds) =>
1106
+ arrayForEach(listenerIds, (listenerId) =>
1107
+ setAdd(
1108
+ mapEnsure(
1109
+ mapEnsure(preStoreListenerIds, queryId, mapNew),
1110
+ preStore,
1111
+ setNew,
1112
+ ),
1113
+ listenerId,
1114
+ ),
1115
+ );
1116
+ const cleanPreStores = (queryId) =>
1117
+ arrayForEach([resultStore, preStore2, preStore1], (store2) =>
1118
+ store2.delTable(queryId),
1119
+ );
1120
+ const synchronizeTransactions = (queryId, fromStore, toStore) =>
1121
+ addPreStoreListener(
1122
+ fromStore,
1123
+ queryId,
1124
+ fromStore.addWillFinishTransactionListener(toStore.startTransaction),
1125
+ fromStore.addDidFinishTransactionListener(() =>
1126
+ toStore.finishTransaction(),
1127
+ ),
1128
+ );
1129
+ const setQueryDefinition = (queryId, tableId, build) => {
1130
+ setDefinition(queryId, tableId);
1131
+ cleanPreStores(queryId);
1132
+ let offsetLimit;
1133
+ const selectEntries = [];
1134
+ const joinEntries = [[null, [tableId, null, null, [], mapNew()]]];
1135
+ const wheres = [];
1136
+ const groupEntries = [];
1137
+ const havings = [];
1138
+ const orders = [];
1139
+ const select = (arg1, arg2) => {
1140
+ const selectEntry = isFunction(arg1)
1141
+ ? [arrayLength(selectEntries) + EMPTY_STRING, arg1]
1142
+ : [
1143
+ isUndefined(arg2) ? arg1 : arg2,
1144
+ (getTableCell) => getTableCell(arg1, arg2),
1145
+ ];
1146
+ arrayPush(selectEntries, selectEntry);
1147
+ return {as: (selectedCellId) => (selectEntry[0] = selectedCellId)};
1148
+ };
1149
+ const join = (joinedTableId, arg1, arg2) => {
1150
+ const fromIntermediateJoinedTableId =
1151
+ isUndefined(arg2) || isFunction(arg1) ? null : arg1;
1152
+ const onArg = isUndefined(fromIntermediateJoinedTableId) ? arg1 : arg2;
1153
+ const joinEntry = [
1154
+ joinedTableId,
1155
+ [
1156
+ joinedTableId,
1157
+ fromIntermediateJoinedTableId,
1158
+ isFunction(onArg) ? onArg : (getCell) => getCell(onArg),
1159
+ [],
1160
+ mapNew(),
1161
+ ],
1162
+ ];
1163
+ arrayPush(joinEntries, joinEntry);
1164
+ return {as: (joinedTableId2) => (joinEntry[0] = joinedTableId2)};
1165
+ };
1166
+ const where = (arg1, arg2, arg3) =>
1167
+ arrayPush(
1168
+ wheres,
1169
+ isFunction(arg1)
1170
+ ? arg1
1171
+ : isUndefined(arg3)
1172
+ ? (getTableCell) => getTableCell(arg1) === arg2
1173
+ : (getTableCell) => getTableCell(arg1, arg2) === arg3,
1174
+ );
1175
+ const group = (
1176
+ selectedCellId,
1177
+ aggregate,
1178
+ aggregateAdd,
1179
+ aggregateRemove,
1180
+ aggregateReplace,
1181
+ ) => {
1182
+ const groupEntry = [
1183
+ selectedCellId,
1184
+ [
1185
+ selectedCellId,
1186
+ isFunction(aggregate)
1187
+ ? [aggregate, aggregateAdd, aggregateRemove, aggregateReplace]
1188
+ : mapGet(numericAggregators, aggregate) ?? [
1189
+ (_cells, length) => length,
1190
+ ],
1191
+ ],
1192
+ ];
1193
+ arrayPush(groupEntries, groupEntry);
1194
+ return {as: (groupedCellId) => (groupEntry[0] = groupedCellId)};
1195
+ };
1196
+ const having = (arg1, arg2) =>
1197
+ arrayPush(
1198
+ havings,
1199
+ isFunction(arg1)
1200
+ ? arg1
1201
+ : (getSelectedOrGroupedCell) =>
1202
+ getSelectedOrGroupedCell(arg1) === arg2,
1203
+ );
1204
+ const order = (arg1, descending) =>
1205
+ arrayPush(orders, [
1206
+ isFunction(arg1)
1207
+ ? arg1
1208
+ : (getSelectedOrGroupedCell) => getSelectedOrGroupedCell(arg1) ?? 0,
1209
+ descending,
1210
+ ]);
1211
+ const limit = (arg1, arg2) => {
1212
+ offsetLimit = isUndefined(arg2) ? [0, arg1] : [arg1, arg2];
1213
+ };
1214
+ build({select, join, where, group, having, order, limit});
1215
+ const selects = mapNew(selectEntries);
1216
+ if (collIsEmpty(selects)) {
1217
+ return queries;
1218
+ }
1219
+ const joins = mapNew(joinEntries);
1220
+ mapForEach(joins, (asTableId, [, fromAsTableId]) =>
1221
+ ifNotUndefined(mapGet(joins, fromAsTableId), ({3: toAsTableIds}) =>
1222
+ isUndefined(asTableId) ? 0 : arrayPush(toAsTableIds, asTableId),
1223
+ ),
1224
+ );
1225
+ const groups = mapNew(groupEntries);
1226
+ let selectJoinWhereStore = preStore1;
1227
+ let groupHavingStore = preStore2;
1228
+ if (arrayIsEmpty(orders) && isUndefined(offsetLimit)) {
1229
+ groupHavingStore = resultStore;
1230
+ } else {
1231
+ synchronizeTransactions(queryId, groupHavingStore, resultStore);
1232
+ const groupRowIdSorter = (rowId1, rowId2) => {
1233
+ const sortKeys1 = mapGet(sortKeysByGroupRowId, rowId1) ?? [];
1234
+ const sortKeys2 = mapGet(sortKeysByGroupRowId, rowId2) ?? [];
1235
+ const orderIndex = orders.findIndex(
1236
+ (_order, index) => sortKeys1[index] !== sortKeys2[index],
1237
+ );
1238
+ return orderIndex < 0
1239
+ ? 0
1240
+ : defaultSorter(sortKeys1[orderIndex], sortKeys2[orderIndex]) *
1241
+ (orders[orderIndex][1] ? -1 : 1);
1242
+ };
1243
+ const sortKeysByGroupRowId = mapNew();
1244
+ const sortedGroupRowIds = mapNew();
1245
+ addPreStoreListener(
1246
+ groupHavingStore,
1247
+ queryId,
1248
+ arrayIsEmpty(orders)
1249
+ ? groupHavingStore.addRowIdsListener(queryId, () =>
1250
+ collClear(sortedGroupRowIds),
1251
+ )
1252
+ : groupHavingStore.addRowListener(
1253
+ queryId,
1254
+ null,
1255
+ (_store, _tableId, groupRowId) => {
1256
+ let newSortKeys = null;
1257
+ if (groupHavingStore.hasRow(queryId, groupRowId)) {
1258
+ const oldSortKeys =
1259
+ mapGet(sortKeysByGroupRowId, groupRowId) ?? [];
1260
+ const groupRow = groupHavingStore.getRow(queryId, groupRowId);
1261
+ const getCell = (getSelectedOrGroupedCell) =>
1262
+ groupRow[getSelectedOrGroupedCell];
1263
+ newSortKeys = arrayMap(orders, ([getSortKey]) =>
1264
+ getSortKey(getCell, groupRowId),
1265
+ );
1266
+ if (arrayIsEqual(oldSortKeys, newSortKeys)) {
1267
+ if (mapGet(sortedGroupRowIds, groupRowId)) {
1268
+ resultStore.setRow(queryId, groupRowId, groupRow);
1269
+ }
1270
+ return;
1271
+ }
1272
+ }
1273
+ mapSet(sortKeysByGroupRowId, groupRowId, newSortKeys);
1274
+ collClear(sortedGroupRowIds);
1275
+ },
1276
+ ),
1277
+ groupHavingStore.addTableListener(queryId, () => {
1278
+ if (collIsEmpty(sortedGroupRowIds)) {
1279
+ resultStore.delTable(queryId);
1280
+ if (groupHavingStore.hasTable(queryId)) {
1281
+ const groupTable = groupHavingStore.getTable(queryId);
1282
+ arrayForEach(
1283
+ arraySort(objIds(groupTable), groupRowIdSorter),
1284
+ (id) => mapSet(sortedGroupRowIds, id, 0),
1285
+ );
1286
+ arrayForEach(
1287
+ ifNotUndefined(
1288
+ offsetLimit,
1289
+ ([offset, limit2]) =>
1290
+ arraySlice(
1291
+ mapKeys(sortedGroupRowIds),
1292
+ offset,
1293
+ offset + limit2,
1294
+ ),
1295
+ () => mapKeys(sortedGroupRowIds),
1296
+ ),
1297
+ (groupRowId) => {
1298
+ resultStore.setRow(
1299
+ queryId,
1300
+ groupRowId,
1301
+ groupTable[groupRowId],
1302
+ );
1303
+ mapSet(sortedGroupRowIds, groupRowId, 1);
1304
+ },
1305
+ );
1306
+ }
1307
+ }
1308
+ }),
1309
+ );
1310
+ }
1311
+ if (collIsEmpty(groups) && arrayIsEmpty(havings)) {
1312
+ selectJoinWhereStore = groupHavingStore;
1313
+ } else {
1314
+ synchronizeTransactions(queryId, selectJoinWhereStore, groupHavingStore);
1315
+ const groupedSelectedCellIds = mapNew();
1316
+ mapForEach(groups, (groupedCellId, [selectedCellId, aggregators]) =>
1317
+ setAdd(mapEnsure(groupedSelectedCellIds, selectedCellId, setNew), [
1318
+ groupedCellId,
1319
+ aggregators,
1320
+ ]),
1321
+ );
1322
+ const groupBySelectedCellIds = setNew();
1323
+ mapForEach(selects, (selectedCellId) =>
1324
+ collHas(groupedSelectedCellIds, selectedCellId)
1325
+ ? 0
1326
+ : setAdd(groupBySelectedCellIds, selectedCellId),
1327
+ );
1328
+ const tree = mapNew();
1329
+ const writeGroupRow = (
1330
+ leaf,
1331
+ changedGroupedSelectedCells,
1332
+ selectedRowId,
1333
+ forceRemove,
1334
+ ) =>
1335
+ ifNotUndefined(
1336
+ leaf,
1337
+ ([selectedCells, selectedRowIds, groupRowId, groupRow]) => {
1338
+ mapForEach(
1339
+ changedGroupedSelectedCells,
1340
+ (selectedCellId, [newCell]) => {
1341
+ const selectedCell = mapEnsure(
1342
+ selectedCells,
1343
+ selectedCellId,
1344
+ mapNew,
1345
+ );
1346
+ const oldLeafCell = mapGet(selectedCell, selectedRowId);
1347
+ const newLeafCell = forceRemove ? void 0 : newCell;
1348
+ if (oldLeafCell !== newLeafCell) {
1349
+ const oldNewSet = setNew([[oldLeafCell, newLeafCell]]);
1350
+ const oldLength = collSize(selectedCell);
1351
+ mapSet(selectedCell, selectedRowId, newLeafCell);
1352
+ collForEach(
1353
+ mapGet(groupedSelectedCellIds, selectedCellId),
1354
+ ([groupedCellId, aggregators]) => {
1355
+ const aggregateValue = getAggregateValue(
1356
+ groupRow[groupedCellId],
1357
+ oldLength,
1358
+ selectedCell,
1359
+ oldNewSet,
1360
+ aggregators,
1361
+ );
1362
+ groupRow[groupedCellId] = isUndefined(
1363
+ getCellType(aggregateValue),
1364
+ )
1365
+ ? null
1366
+ : aggregateValue;
1367
+ },
1368
+ );
1369
+ }
1370
+ },
1371
+ );
1372
+ (collIsEmpty(selectedRowIds) ||
1373
+ !arrayEvery(havings, (having2) =>
1374
+ having2((cellId) => groupRow[cellId]),
1375
+ )
1376
+ ? groupHavingStore.delRow
1377
+ : groupHavingStore.setRow)(queryId, groupRowId, groupRow);
1378
+ },
1379
+ );
1380
+ addPreStoreListener(
1381
+ selectJoinWhereStore,
1382
+ queryId,
1383
+ selectJoinWhereStore.addRowListener(
1384
+ queryId,
1385
+ null,
1386
+ (_store, _tableId, selectedRowId, getCellChange) => {
1387
+ const oldPath = [];
1388
+ const newPath = [];
1389
+ const changedGroupedSelectedCells = mapNew();
1390
+ const rowExists = selectJoinWhereStore.hasRow(
1391
+ queryId,
1392
+ selectedRowId,
1393
+ );
1394
+ let changedLeaf = !rowExists;
1395
+ collForEach(groupBySelectedCellIds, (selectedCellId) => {
1396
+ const [changed, oldCell, newCell] = getCellChange(
1397
+ queryId,
1398
+ selectedRowId,
1399
+ selectedCellId,
1400
+ );
1401
+ arrayPush(oldPath, oldCell);
1402
+ arrayPush(newPath, newCell);
1403
+ changedLeaf ||= changed;
1404
+ });
1405
+ mapForEach(groupedSelectedCellIds, (selectedCellId) => {
1406
+ const [changed, , newCell] = getCellChange(
1407
+ queryId,
1408
+ selectedRowId,
1409
+ selectedCellId,
1410
+ );
1411
+ if (changedLeaf || changed) {
1412
+ mapSet(changedGroupedSelectedCells, selectedCellId, [newCell]);
1413
+ }
1414
+ });
1415
+ if (changedLeaf) {
1416
+ writeGroupRow(
1417
+ visitTree(
1418
+ tree,
1419
+ oldPath,
1420
+ void 0,
1421
+ ([, selectedRowIds, groupRowId]) => {
1422
+ collDel(selectedRowIds, selectedRowId);
1423
+ if (collIsEmpty(selectedRowIds)) {
1424
+ groupHavingStore.delRow(queryId, groupRowId);
1425
+ return 1;
1426
+ }
1427
+ },
1428
+ ),
1429
+ changedGroupedSelectedCells,
1430
+ selectedRowId,
1431
+ 1,
1432
+ );
1433
+ }
1434
+ if (rowExists) {
1435
+ writeGroupRow(
1436
+ visitTree(
1437
+ tree,
1438
+ newPath,
1439
+ () => {
1440
+ const groupRow = {};
1441
+ collForEach(
1442
+ groupBySelectedCellIds,
1443
+ (selectedCellId) =>
1444
+ (groupRow[selectedCellId] =
1445
+ selectJoinWhereStore.getCell(
1446
+ queryId,
1447
+ selectedRowId,
1448
+ selectedCellId,
1449
+ )),
1450
+ );
1451
+ return [
1452
+ mapNew(),
1453
+ setNew(),
1454
+ groupHavingStore.addRow(queryId, groupRow, 1),
1455
+ groupRow,
1456
+ ];
1457
+ },
1458
+ ([, selectedRowIds]) => {
1459
+ setAdd(selectedRowIds, selectedRowId);
1460
+ },
1461
+ ),
1462
+ changedGroupedSelectedCells,
1463
+ selectedRowId,
1464
+ );
1465
+ }
1466
+ },
1467
+ ),
1468
+ );
1469
+ }
1470
+ synchronizeTransactions(queryId, store, selectJoinWhereStore);
1471
+ const writeSelectRow = (rootRowId) => {
1472
+ const getTableCell = (arg1, arg2) =>
1473
+ store.getCell(
1474
+ ...(isUndefined(arg2)
1475
+ ? [tableId, rootRowId, arg1]
1476
+ : arg1 === tableId
1477
+ ? [tableId, rootRowId, arg2]
1478
+ : [
1479
+ mapGet(joins, arg1)?.[0],
1480
+ mapGet(mapGet(joins, arg1)?.[4], rootRowId)?.[0],
1481
+ arg2,
1482
+ ]),
1483
+ );
1484
+ selectJoinWhereStore.transaction(() =>
1485
+ arrayEvery(wheres, (where2) => where2(getTableCell))
1486
+ ? mapForEach(selects, (asCellId, tableCellGetter) =>
1487
+ setOrDelCell(
1488
+ selectJoinWhereStore,
1489
+ queryId,
1490
+ rootRowId,
1491
+ asCellId,
1492
+ tableCellGetter(getTableCell, rootRowId),
1493
+ ),
1494
+ )
1495
+ : selectJoinWhereStore.delRow(queryId, rootRowId),
1496
+ );
1497
+ };
1498
+ const listenToTable = (rootRowId, tableId2, rowId, joinedTableIds2) => {
1499
+ const getCell = (cellId) => store.getCell(tableId2, rowId, cellId);
1500
+ arrayForEach(joinedTableIds2, (remoteAsTableId) => {
1501
+ const [realJoinedTableId, , on, nextJoinedTableIds, remoteIdPair] =
1502
+ mapGet(joins, remoteAsTableId);
1503
+ const remoteRowId = on?.(getCell, rootRowId);
1504
+ const [previousRemoteRowId, previousRemoteListenerId] =
1505
+ mapGet(remoteIdPair, rootRowId) ?? [];
1506
+ if (remoteRowId != previousRemoteRowId) {
1507
+ if (!isUndefined(previousRemoteListenerId)) {
1508
+ delStoreListeners(queryId, previousRemoteListenerId);
1509
+ }
1510
+ mapSet(
1511
+ remoteIdPair,
1512
+ rootRowId,
1513
+ isUndefined(remoteRowId)
1514
+ ? null
1515
+ : [
1516
+ remoteRowId,
1517
+ ...addStoreListeners(
1518
+ queryId,
1519
+ 1,
1520
+ store.addRowListener(realJoinedTableId, remoteRowId, () =>
1521
+ listenToTable(
1522
+ rootRowId,
1523
+ realJoinedTableId,
1524
+ remoteRowId,
1525
+ nextJoinedTableIds,
1526
+ ),
1527
+ ),
1528
+ ),
1529
+ ],
1530
+ );
1531
+ }
1532
+ });
1533
+ writeSelectRow(rootRowId);
1534
+ };
1535
+ const {3: joinedTableIds} = mapGet(joins, null);
1536
+ selectJoinWhereStore.transaction(() =>
1537
+ addStoreListeners(
1538
+ queryId,
1539
+ 1,
1540
+ store.addRowListener(tableId, null, (_store, _tableId, rootRowId) => {
1541
+ if (store.hasRow(tableId, rootRowId)) {
1542
+ listenToTable(rootRowId, tableId, rootRowId, joinedTableIds);
1543
+ } else {
1544
+ selectJoinWhereStore.delRow(queryId, rootRowId);
1545
+ collForEach(joins, ({4: idsByRootRowId}) =>
1546
+ ifNotUndefined(
1547
+ mapGet(idsByRootRowId, rootRowId),
1548
+ ([, listenerId]) => {
1549
+ delStoreListeners(queryId, listenerId);
1550
+ mapSet(idsByRootRowId, rootRowId);
1551
+ },
1552
+ ),
1553
+ );
1554
+ }
1555
+ }),
1556
+ ),
1557
+ );
1558
+ return queries;
1559
+ };
1560
+ const delQueryDefinition = (queryId) => {
1561
+ mapForEach(mapGet(preStoreListenerIds, queryId), (preStore, listenerIds) =>
1562
+ collForEach(listenerIds, (listenerId) =>
1563
+ preStore.delListener(listenerId),
1564
+ ),
1565
+ );
1566
+ cleanPreStores(queryId);
1567
+ delDefinition(queryId);
1568
+ return queries;
1569
+ };
1570
+ const getResultTable = (queryId) => resultStore.getTable(queryId);
1571
+ const getResultRowIds = (queryId) => resultStore.getRowIds(queryId);
1572
+ const getResultSortedRowIds = (queryId, cellId, descending) =>
1573
+ resultStore.getSortedRowIds(queryId, cellId, descending);
1574
+ const getResultRow = (queryId, rowId) => resultStore.getRow(queryId, rowId);
1575
+ const getResultCellIds = (queryId, rowId) =>
1576
+ resultStore.getCellIds(queryId, rowId);
1577
+ const getResultCell = (queryId, rowId, cellId) =>
1578
+ resultStore.getCell(queryId, rowId, cellId);
1579
+ const hasResultTable = (queryId) => resultStore.hasTable(queryId);
1580
+ const hasResultRow = (queryId, rowId) => resultStore.hasRow(queryId, rowId);
1581
+ const hasResultCell = (queryId, rowId, cellId) =>
1582
+ resultStore.hasCell(queryId, rowId, cellId);
1583
+ const forEachResultTable = (tableCallback) =>
1584
+ resultStore.forEachTable(tableCallback);
1585
+ const forEachResultRow = (queryId, rowCallback) =>
1586
+ resultStore.forEachRow(queryId, rowCallback);
1587
+ const forEachResultCell = (queryId, rowId, cellCallback) =>
1588
+ resultStore.forEachCell(queryId, rowId, cellCallback);
1589
+ const addResultTableListener = (queryId, listener) =>
1590
+ resultStore.addTableListener(queryId, (_store, ...args) =>
1591
+ listener(queries, ...args),
1592
+ );
1593
+ const addResultRowIdsListener = (queryId, listener, trackReorder) =>
1594
+ resultStore.addRowIdsListener(
1595
+ queryId,
1596
+ (_store, ...args) => listener(queries, ...args),
1597
+ trackReorder,
1598
+ );
1599
+ const addResultSortedRowIdsListener = (
1600
+ queryId,
1601
+ cellId,
1602
+ descending,
1603
+ listener,
1604
+ ) =>
1605
+ resultStore.addSortedRowIdsListener(
1606
+ queryId,
1607
+ cellId,
1608
+ descending,
1609
+ (_store, ...args) => listener(queries, ...args),
1610
+ );
1611
+ const addResultRowListener = (queryId, rowId, listener) =>
1612
+ resultStore.addRowListener(queryId, rowId, (_store, ...args) =>
1613
+ listener(queries, ...args),
1614
+ );
1615
+ const addResultCellIdsListener = (queryId, rowId, listener) =>
1616
+ resultStore.addCellIdsListener(queryId, rowId, (_store, ...args) =>
1617
+ listener(queries, ...args),
1618
+ );
1619
+ const addResultCellListener = (queryId, rowId, cellId, listener) =>
1620
+ resultStore.addCellListener(queryId, rowId, cellId, (_store, ...args) =>
1621
+ listener(queries, ...args),
1622
+ );
1623
+ const delListener = (listenerId) => {
1624
+ resultStore.delListener(listenerId);
1625
+ return queries;
1626
+ };
1627
+ const getListenerStats = () => {
1628
+ const {
1629
+ tables: _1,
1630
+ tableIds: _2,
1631
+ transaction: _3,
1632
+ ...stats
1633
+ } = resultStore.getListenerStats();
1634
+ return stats;
1635
+ };
1636
+ const queries = {
1637
+ setQueryDefinition,
1638
+ delQueryDefinition,
1639
+ getStore,
1640
+ getQueryIds,
1641
+ forEachQuery,
1642
+ hasQuery,
1643
+ getTableId,
1644
+ getResultTable,
1645
+ getResultRowIds,
1646
+ getResultSortedRowIds,
1647
+ getResultRow,
1648
+ getResultCellIds,
1649
+ getResultCell,
1650
+ hasResultTable,
1651
+ hasResultRow,
1652
+ hasResultCell,
1653
+ forEachResultTable,
1654
+ forEachResultRow,
1655
+ forEachResultCell,
1656
+ addResultTableListener,
1657
+ addResultRowIdsListener,
1658
+ addResultSortedRowIdsListener,
1659
+ addResultRowListener,
1660
+ addResultCellIdsListener,
1661
+ addResultCellListener,
1662
+ delListener,
1663
+ destroy,
1664
+ getListenerStats,
1665
+ };
1666
+ return objFreeze(queries);
1667
+ });
1668
+
1016
1669
  const createRelationships = getCreateFunction((store) => {
1017
1670
  const remoteTableIds = mapNew();
1018
1671
  const remoteRowIdListeners = mapNew();
@@ -1026,7 +1679,8 @@ const createRelationships = getCreateFunction((store) => {
1026
1679
  getLocalTableId,
1027
1680
  getRelationship,
1028
1681
  ,
1029
- setDefinition,
1682
+ ,
1683
+ setDefinitionAndListen,
1030
1684
  delDefinition,
1031
1685
  destroy,
1032
1686
  ] = getDefinableFunctions(
@@ -1073,7 +1727,7 @@ const createRelationships = getCreateFunction((store) => {
1073
1727
  getRemoteRowId2,
1074
1728
  ) => {
1075
1729
  mapSet(remoteTableIds, relationshipId, remoteTableId);
1076
- setDefinition(
1730
+ setDefinitionAndListen(
1077
1731
  relationshipId,
1078
1732
  localTableId,
1079
1733
  (change, changedRemoteRowIds) => {
@@ -1199,6 +1853,14 @@ const createRelationships = getCreateFunction((store) => {
1199
1853
  return objFreeze(relationships);
1200
1854
  });
1201
1855
 
1856
+ const pairNew = (value) => [value, value];
1857
+ const pairCollSize2 = (pair, func = collSize2) => func(pair[0]) + func(pair[1]);
1858
+ const pairCollIsEmpty = (pair) => pairCollSize2(pair) == 0;
1859
+ const pairNewMap = () => [mapNew(), mapNew()];
1860
+ const pair2CollSize2 = (pair2, func = collSize2) =>
1861
+ pairCollSize2(pair2[0], func) + pairCollSize2(pair2[1], func);
1862
+ const pair2NewMap = () => [pairNewMap(), pairNewMap()];
1863
+
1202
1864
  const transformMap = (map, toBeLikeObject, setId, delId = mapSet) => {
1203
1865
  const idsToDelete = arrayFilter(
1204
1866
  mapKeys(map),
@@ -1210,12 +1872,6 @@ const transformMap = (map, toBeLikeObject, setId, delId = mapSet) => {
1210
1872
  arrayForEach(idsToDelete, (id2) => delId(map, id2));
1211
1873
  return map;
1212
1874
  };
1213
- const getCellType = (cell) => {
1214
- const type = getTypeOf(cell);
1215
- return isTypeStringOrBoolean(type) || (type == NUMBER && isFiniteNumber(cell))
1216
- ? type
1217
- : void 0;
1218
- };
1219
1875
  const validate = (obj, validateChild, onInvalidObj) => {
1220
1876
  if (isUndefined(obj) || !isObject(obj) || objIsEmpty(obj) || objFrozen(obj)) {
1221
1877
  onInvalidObj?.();
@@ -1228,8 +1884,8 @@ const validate = (obj, validateChild, onInvalidObj) => {
1228
1884
  });
1229
1885
  return !objIsEmpty(obj);
1230
1886
  };
1231
- const idsChanged = (ids, id2, added) =>
1232
- mapSet(ids, id2, mapGet(ids, id2) == -added ? void 0 : added);
1887
+ const idsChanged = (changedIds, id2, added) =>
1888
+ mapSet(changedIds, id2, mapGet(changedIds, id2) == -added ? void 0 : added);
1233
1889
  const createStore = () => {
1234
1890
  let hasSchema;
1235
1891
  let cellsTouched;
@@ -1243,17 +1899,23 @@ const createStore = () => {
1243
1899
  const schemaMap = mapNew();
1244
1900
  const schemaRowCache = mapNew();
1245
1901
  const tablesMap = mapNew();
1246
- const tablesListeners = mapNewPair(setNew);
1247
- const tableIdsListeners = mapNewPair(setNew);
1248
- const tableListeners = mapNewPair();
1249
- const rowIdsListeners = mapNewPair();
1250
- const rowListeners = mapNewPair();
1251
- const cellIdsListeners = mapNewPair();
1252
- const cellListeners = mapNewPair();
1253
- const invalidCellListeners = mapNewPair();
1254
- const finishTransactionListeners = mapNewPair(setNew);
1255
- const [addListener, callListeners, delListenerImpl, callListenerImpl] =
1256
- getListenerFunctions(() => store);
1902
+ const tablesListeners = pairNewMap();
1903
+ const tableIdsListeners = pair2NewMap();
1904
+ const tableListeners = pairNewMap();
1905
+ const rowIdsListeners = pair2NewMap();
1906
+ const sortedRowIdsListeners = pairNewMap();
1907
+ const rowListeners = pairNewMap();
1908
+ const cellIdsListeners = pair2NewMap();
1909
+ const cellListeners = pairNewMap();
1910
+ const invalidCellListeners = pairNewMap();
1911
+ const finishTransactionListeners = pairNewMap();
1912
+ const [
1913
+ addListener,
1914
+ callListeners,
1915
+ delListenerImpl,
1916
+ hasListeners,
1917
+ callListenerImpl,
1918
+ ] = getListenerFunctions(() => store);
1257
1919
  const validateSchema = (schema) =>
1258
1920
  validate(schema, (tableSchema) =>
1259
1921
  validate(tableSchema, (cellSchema) => {
@@ -1435,12 +2097,49 @@ const createStore = () => {
1435
2097
  }
1436
2098
  };
1437
2099
  const tableIdsChanged = (tableId, added) =>
1438
- idsChanged(changedTableIds, tableId, added);
2100
+ idsChanged(
2101
+ collIsEmpty(changedTableIds)
2102
+ ? mapSet(
2103
+ changedTableIds,
2104
+ null,
2105
+ hasListeners(tableIdsListeners[0][1]) ||
2106
+ hasListeners(tableIdsListeners[1][1])
2107
+ ? getTableIds()
2108
+ : 0,
2109
+ )
2110
+ : changedTableIds,
2111
+ tableId,
2112
+ added,
2113
+ );
1439
2114
  const rowIdsChanged = (tableId, rowId, added) =>
1440
- idsChanged(mapEnsure(changedRowIds, tableId, mapNew), rowId, added);
2115
+ idsChanged(
2116
+ mapEnsure(changedRowIds, tableId, () =>
2117
+ mapNew([
2118
+ [
2119
+ null,
2120
+ hasListeners(rowIdsListeners[0][1], [tableId]) ||
2121
+ hasListeners(rowIdsListeners[1][1], [tableId])
2122
+ ? getRowIds(tableId)
2123
+ : 0,
2124
+ ],
2125
+ ]),
2126
+ ),
2127
+ rowId,
2128
+ added,
2129
+ );
1441
2130
  const cellIdsChanged = (tableId, rowId, cellId, added) =>
1442
2131
  idsChanged(
1443
- mapEnsure(mapEnsure(changedCellIds, tableId, mapNew), rowId, mapNew),
2132
+ mapEnsure(mapEnsure(changedCellIds, tableId, mapNew), rowId, () =>
2133
+ mapNew([
2134
+ [
2135
+ null,
2136
+ hasListeners(cellIdsListeners[0][1], [tableId, rowId]) ||
2137
+ hasListeners(cellIdsListeners[1][1], [tableId, rowId])
2138
+ ? getCellIds(tableId, rowId)
2139
+ : 0,
2140
+ ],
2141
+ ]),
2142
+ ),
1444
2143
  cellId,
1445
2144
  added,
1446
2145
  );
@@ -1465,7 +2164,7 @@ const createStore = () => {
1465
2164
  ifNotUndefined(
1466
2165
  mapGet(mapGet(mapGet(changedCells, tableId), rowId), cellId),
1467
2166
  ([oldCell, newCell]) => [true, oldCell, newCell],
1468
- () => [false, ...arrayPair(getCell(tableId, rowId, cellId))],
2167
+ () => [false, ...pairNew(getCell(tableId, rowId, cellId))],
1469
2168
  );
1470
2169
  const callInvalidCellListeners = (mutator) =>
1471
2170
  !collIsEmpty(invalidCells) && !collIsEmpty(invalidCellListeners[mutator])
@@ -1483,17 +2182,36 @@ const createStore = () => {
1483
2182
  ),
1484
2183
  )
1485
2184
  : 0;
2185
+ const callIdsListenersIfChanged = (listeners, changedIds, getIds, ids) => {
2186
+ if (collSize(changedIds) > 1) {
2187
+ callListeners(listeners[0], ids);
2188
+ callListeners(listeners[1], ids);
2189
+ return 1;
2190
+ }
2191
+ if (
2192
+ !collIsEmpty(changedIds) &&
2193
+ mapGet(changedIds, null) != 0 &&
2194
+ !arrayIsEqual(mapGet(changedIds, null), getIds(...(ids ?? [])))
2195
+ ) {
2196
+ callListeners(listeners[1], ids);
2197
+ return 1;
2198
+ }
2199
+ };
1486
2200
  const callListenersForChanges = (mutator) => {
2201
+ const emptySortedRowIdListeners = collIsEmpty(
2202
+ sortedRowIdsListeners[mutator],
2203
+ );
1487
2204
  const emptyIdListeners =
1488
- collIsEmpty(cellIdsListeners[mutator]) &&
1489
- collIsEmpty(rowIdsListeners[mutator]) &&
1490
- collIsEmpty(tableIdsListeners[mutator]);
2205
+ pairCollIsEmpty(cellIdsListeners[mutator]) &&
2206
+ pairCollIsEmpty(rowIdsListeners[mutator]) &&
2207
+ emptySortedRowIdListeners &&
2208
+ pairCollIsEmpty(tableIdsListeners[mutator]);
1491
2209
  const emptyOtherListeners =
1492
2210
  collIsEmpty(cellListeners[mutator]) &&
1493
2211
  collIsEmpty(rowListeners[mutator]) &&
1494
2212
  collIsEmpty(tableListeners[mutator]) &&
1495
2213
  collIsEmpty(tablesListeners[mutator]);
1496
- if (!(emptyIdListeners && emptyOtherListeners)) {
2214
+ if (!emptyIdListeners || !emptyOtherListeners) {
1497
2215
  const changes = mutator
1498
2216
  ? [
1499
2217
  mapClone(changedTableIds),
@@ -1504,20 +2222,55 @@ const createStore = () => {
1504
2222
  : [changedTableIds, changedRowIds, changedCellIds, changedCells];
1505
2223
  if (!emptyIdListeners) {
1506
2224
  collForEach(changes[2], (rowCellIds, tableId) =>
1507
- collForEach(rowCellIds, (changedIds, rowId) => {
1508
- if (!collIsEmpty(changedIds)) {
1509
- callListeners(cellIdsListeners[mutator], [tableId, rowId]);
1510
- }
1511
- }),
2225
+ collForEach(rowCellIds, (changedIds, rowId) =>
2226
+ callIdsListenersIfChanged(
2227
+ cellIdsListeners[mutator],
2228
+ changedIds,
2229
+ getCellIds,
2230
+ [tableId, rowId],
2231
+ ),
2232
+ ),
1512
2233
  );
2234
+ const calledSortableTableIds = setNew();
1513
2235
  collForEach(changes[1], (changedIds, tableId) => {
1514
- if (!collIsEmpty(changedIds)) {
1515
- callListeners(rowIdsListeners[mutator], [tableId]);
2236
+ if (
2237
+ callIdsListenersIfChanged(
2238
+ rowIdsListeners[mutator],
2239
+ changedIds,
2240
+ getRowIds,
2241
+ [tableId],
2242
+ ) &&
2243
+ !emptySortedRowIdListeners
2244
+ ) {
2245
+ callListeners(sortedRowIdsListeners[mutator], [tableId, null]);
2246
+ setAdd(calledSortableTableIds, tableId);
1516
2247
  }
1517
2248
  });
1518
- if (!collIsEmpty(changes[0])) {
1519
- callListeners(tableIdsListeners[mutator]);
2249
+ if (!emptySortedRowIdListeners) {
2250
+ collForEach(changes[3], (rows, tableId) => {
2251
+ if (!collHas(calledSortableTableIds, tableId)) {
2252
+ const sortableCellIds = setNew();
2253
+ collForEach(rows, (cells) =>
2254
+ collForEach(cells, ([oldCell, newCell], cellId) =>
2255
+ newCell !== oldCell
2256
+ ? setAdd(sortableCellIds, cellId)
2257
+ : collDel(cells, cellId),
2258
+ ),
2259
+ );
2260
+ collForEach(sortableCellIds, (cellId) =>
2261
+ callListeners(sortedRowIdsListeners[mutator], [
2262
+ tableId,
2263
+ cellId,
2264
+ ]),
2265
+ );
2266
+ }
2267
+ });
1520
2268
  }
2269
+ callIdsListenersIfChanged(
2270
+ tableIdsListeners[mutator],
2271
+ changes[0],
2272
+ getTableIds,
2273
+ );
1521
2274
  }
1522
2275
  if (!emptyOtherListeners) {
1523
2276
  let tablesChanged;
@@ -1550,7 +2303,7 @@ const createStore = () => {
1550
2303
  }
1551
2304
  });
1552
2305
  if (tablesChanged) {
1553
- callListeners(tablesListeners[mutator], [], getCellChange);
2306
+ callListeners(tablesListeners[mutator], void 0, getCellChange);
1554
2307
  }
1555
2308
  }
1556
2309
  }
@@ -1565,6 +2318,23 @@ const createStore = () => {
1565
2318
  const getTable = (tableId) =>
1566
2319
  mapToObj(mapGet(tablesMap, id(tableId)), mapToObj);
1567
2320
  const getRowIds = (tableId) => mapKeys(mapGet(tablesMap, id(tableId)));
2321
+ const getSortedRowIds = (tableId, cellId, descending) => {
2322
+ const cells = [];
2323
+ mapForEach(mapGet(tablesMap, id(tableId)), (rowId, row) =>
2324
+ arrayPush(cells, [
2325
+ isUndefined(cellId) ? rowId : mapGet(row, id(cellId)),
2326
+ rowId,
2327
+ ]),
2328
+ );
2329
+ return arrayMap(
2330
+ arraySort(
2331
+ cells,
2332
+ ([cell1], [cell2]) =>
2333
+ defaultSorter(cell1, cell2) * (descending ? -1 : 1),
2334
+ ),
2335
+ ([, rowId]) => rowId,
2336
+ );
2337
+ };
1568
2338
  const getRow = (tableId, rowId) =>
1569
2339
  mapToObj(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)));
1570
2340
  const getCellIds = (tableId, rowId) =>
@@ -1603,17 +2373,16 @@ const createStore = () => {
1603
2373
  tableId,
1604
2374
  rowId,
1605
2375
  );
1606
- const addRow = (tableId, row) =>
2376
+ const addRow = (tableId, row, forceId) =>
1607
2377
  transaction(() => {
1608
- let rowId = void 0;
1609
- if (validateRow(tableId, rowId, row)) {
1610
- tableId = id(tableId);
1611
- setValidRow(
1612
- tableId,
1613
- getOrCreateTable(tableId),
1614
- (rowId = getNewRowId(mapGet(tablesMap, tableId))),
1615
- row,
1616
- );
2378
+ tableId = id(tableId);
2379
+ const isValidRow = validateRow(tableId, void 0, row);
2380
+ const rowId =
2381
+ isValidRow || forceId
2382
+ ? getNewRowId(mapGet(tablesMap, tableId))
2383
+ : void 0;
2384
+ if (isValidRow) {
2385
+ setValidRow(tableId, getOrCreateTable(tableId), rowId, row);
1617
2386
  }
1618
2387
  return rowId;
1619
2388
  });
@@ -1762,21 +2531,19 @@ const createStore = () => {
1762
2531
  collForEach(changedCells, (table, tableId) =>
1763
2532
  collForEach(table, (row, rowId) =>
1764
2533
  collForEach(row, ([oldCell], cellId) =>
1765
- isUndefined(oldCell)
1766
- ? delCell(tableId, rowId, cellId, true)
1767
- : setCell(tableId, rowId, cellId, oldCell),
2534
+ setOrDelCell(store, tableId, rowId, cellId, oldCell),
1768
2535
  ),
1769
2536
  ),
1770
2537
  );
1771
2538
  transactions = -1;
1772
2539
  cellsTouched = false;
1773
2540
  }
1774
- callListeners(finishTransactionListeners[0], [], cellsTouched);
2541
+ callListeners(finishTransactionListeners[0], void 0, cellsTouched);
1775
2542
  callInvalidCellListeners(0);
1776
2543
  if (cellsTouched) {
1777
2544
  callListenersForChanges(0);
1778
2545
  }
1779
- callListeners(finishTransactionListeners[1], [], cellsTouched);
2546
+ callListeners(finishTransactionListeners[1], void 0, cellsTouched);
1780
2547
  transactions = 0;
1781
2548
  arrayForEach(
1782
2549
  [
@@ -1810,16 +2577,53 @@ const createStore = () => {
1810
2577
  mapForEach(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)), cellCallback);
1811
2578
  const addTablesListener = (listener, mutator) =>
1812
2579
  addListener(listener, tablesListeners[mutator ? 1 : 0]);
1813
- const addTableIdsListener = (listener, mutator) =>
1814
- addListener(listener, tableIdsListeners[mutator ? 1 : 0]);
2580
+ const addTableIdsListener = (listener, trackReorder, mutator) =>
2581
+ addListener(
2582
+ listener,
2583
+ tableIdsListeners[mutator ? 1 : 0][trackReorder ? 1 : 0],
2584
+ );
1815
2585
  const addTableListener = (tableId, listener, mutator) =>
1816
2586
  addListener(listener, tableListeners[mutator ? 1 : 0], [tableId]);
1817
- const addRowIdsListener = (tableId, listener, mutator) =>
1818
- addListener(listener, rowIdsListeners[mutator ? 1 : 0], [tableId]);
2587
+ const addRowIdsListener = (tableId, listener, trackReorder, mutator) =>
2588
+ addListener(
2589
+ listener,
2590
+ rowIdsListeners[mutator ? 1 : 0][trackReorder ? 1 : 0],
2591
+ [tableId],
2592
+ );
2593
+ const addSortedRowIdsListener = (
2594
+ tableId,
2595
+ cellId,
2596
+ descending,
2597
+ listener,
2598
+ mutator,
2599
+ ) => {
2600
+ let sortedRowIds = getSortedRowIds(tableId, cellId, descending);
2601
+ return addListener(
2602
+ () => {
2603
+ const newSortedRowIds = getSortedRowIds(tableId, cellId, descending);
2604
+ if (!arrayIsEqual(newSortedRowIds, sortedRowIds)) {
2605
+ sortedRowIds = newSortedRowIds;
2606
+ listener(store, tableId, cellId, descending, sortedRowIds);
2607
+ }
2608
+ },
2609
+ sortedRowIdsListeners[mutator ? 1 : 0],
2610
+ [tableId, cellId],
2611
+ );
2612
+ };
1819
2613
  const addRowListener = (tableId, rowId, listener, mutator) =>
1820
2614
  addListener(listener, rowListeners[mutator ? 1 : 0], [tableId, rowId]);
1821
- const addCellIdsListener = (tableId, rowId, listener, mutator) =>
1822
- addListener(listener, cellIdsListeners[mutator ? 1 : 0], [tableId, rowId]);
2615
+ const addCellIdsListener = (
2616
+ tableId,
2617
+ rowId,
2618
+ listener,
2619
+ trackReorder,
2620
+ mutator,
2621
+ ) =>
2622
+ addListener(
2623
+ listener,
2624
+ cellIdsListeners[mutator ? 1 : 0][trackReorder ? 1 : 0],
2625
+ [tableId, rowId],
2626
+ );
1823
2627
  const addCellListener = (tableId, rowId, cellId, listener, mutator) =>
1824
2628
  addListener(listener, cellListeners[mutator ? 1 : 0], [
1825
2629
  tableId,
@@ -1838,7 +2642,7 @@ const createStore = () => {
1838
2642
  addListener(listener, finishTransactionListeners[1]);
1839
2643
  const callListener = (listenerId) => {
1840
2644
  callListenerImpl(listenerId, [getTableIds, getRowIds, getCellIds], (ids) =>
1841
- isUndefined(ids[2]) ? [] : arrayPair(getCell(...ids)),
2645
+ isUndefined(ids[2]) ? [] : pairNew(getCell(...ids)),
1842
2646
  );
1843
2647
  return store;
1844
2648
  };
@@ -1847,21 +2651,23 @@ const createStore = () => {
1847
2651
  return store;
1848
2652
  };
1849
2653
  const getListenerStats = () => ({
1850
- tables: collPairSize(tablesListeners),
1851
- tableIds: collPairSize(tableIdsListeners),
1852
- table: collPairSize(tableListeners, collSize2),
1853
- rowIds: collPairSize(rowIdsListeners, collSize2),
1854
- row: collPairSize(rowListeners, collSize3),
1855
- cellIds: collPairSize(cellIdsListeners, collSize3),
1856
- cell: collPairSize(cellListeners, collSize4),
1857
- invalidCell: collPairSize(invalidCellListeners, collSize4),
1858
- transaction: collPairSize(finishTransactionListeners),
2654
+ tables: pairCollSize2(tablesListeners),
2655
+ tableIds: pair2CollSize2(tableIdsListeners),
2656
+ table: pairCollSize2(tableListeners),
2657
+ rowIds: pair2CollSize2(rowIdsListeners),
2658
+ sortedRowIds: pairCollSize2(sortedRowIdsListeners),
2659
+ row: pairCollSize2(rowListeners, collSize3),
2660
+ cellIds: pair2CollSize2(cellIdsListeners, collSize3),
2661
+ cell: pairCollSize2(cellListeners, collSize4),
2662
+ invalidCell: pairCollSize2(invalidCellListeners, collSize4),
2663
+ transaction: pairCollSize2(finishTransactionListeners),
1859
2664
  });
1860
2665
  const store = {
1861
2666
  getTables,
1862
2667
  getTableIds,
1863
2668
  getTable,
1864
2669
  getRowIds,
2670
+ getSortedRowIds,
1865
2671
  getRow,
1866
2672
  getCellIds,
1867
2673
  getCell,
@@ -1894,6 +2700,7 @@ const createStore = () => {
1894
2700
  addTableIdsListener,
1895
2701
  addTableListener,
1896
2702
  addRowIdsListener,
2703
+ addSortedRowIdsListener,
1897
2704
  addRowListener,
1898
2705
  addCellIdsListener,
1899
2706
  addCellListener,
@@ -1903,6 +2710,7 @@ const createStore = () => {
1903
2710
  callListener,
1904
2711
  delListener,
1905
2712
  getListenerStats,
2713
+ createStore,
1906
2714
  };
1907
2715
  return objFreeze(store);
1908
2716
  };
@@ -1914,6 +2722,7 @@ export {
1914
2722
  createIndexes,
1915
2723
  createLocalPersister,
1916
2724
  createMetrics,
2725
+ createQueries,
1917
2726
  createRelationships,
1918
2727
  createRemotePersister,
1919
2728
  createSessionPersister,