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
@@ -8,16 +8,19 @@ const FUNCTION = getTypeOf(getTypeOf);
8
8
  const TYPE = 'type';
9
9
  const DEFAULT = 'default';
10
10
 
11
- const arrayPair = (value) => [value, value];
12
11
  const arrayHas = (array, value) => array.includes(value);
12
+ const arrayEvery = (array, cb) => array.every(cb);
13
+ const arrayIsEqual = (array1, array2) =>
14
+ arrayLength(array1) === arrayLength(array2) &&
15
+ arrayEvery(array1, (value1, index) => array2[index] === value1);
16
+ const arraySort = (array, sorter) => array.sort(sorter);
13
17
  const arrayForEach = (array, cb) => array.forEach(cb);
14
18
  const arrayMap = (array, cb) => array.map(cb);
15
19
  const arrayLength = (array) => array.length;
16
20
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
17
21
  const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
18
22
  const arrayFilter = (array, cb) => array.filter(cb);
19
- const arrayFromSecond = (ids) => ids.slice(1);
20
- const arrayPush = (array, value) => array.push(value);
23
+ const arrayPush = (array, ...values) => array.push(...values);
21
24
  const arrayPop = (array) => array.pop();
22
25
 
23
26
  const jsonString = (obj) =>
@@ -48,7 +51,6 @@ const collSize = (coll) => coll.size;
48
51
  const collSize2 = collSizeN(collSize);
49
52
  const collSize3 = collSizeN(collSize2);
50
53
  const collSize4 = collSizeN(collSize3);
51
- const collPairSize = (pair, func = collSize) => func(pair[0]) + func(pair[1]);
52
54
  const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
53
55
  const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
54
56
  const collValues = (coll) => [...(coll?.values() ?? [])];
@@ -57,7 +59,6 @@ const collForEach = (coll, cb) => coll?.forEach(cb);
57
59
  const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
58
60
 
59
61
  const mapNew = (entries) => new Map(entries);
60
- const mapNewPair = (newFunction = mapNew) => [newFunction(), newFunction()];
61
62
  const mapKeys = (map) => [...(map?.keys() ?? [])];
62
63
  const mapGet = (map, key) => map?.get(key);
63
64
  const mapForEach = (map, cb) =>
@@ -87,6 +88,27 @@ const mapClone = (map, childMapper) => {
87
88
  return map2;
88
89
  };
89
90
  const mapClone2 = (map) => mapClone(map, mapClone);
91
+ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
92
+ ifNotUndefined(
93
+ (ensureLeaf ? mapEnsure : mapGet)(
94
+ node,
95
+ path[p],
96
+ p > arrayLength(path) - 2 ? ensureLeaf : mapNew,
97
+ ),
98
+ (nodeOrLeaf) => {
99
+ if (p > arrayLength(path) - 2) {
100
+ if (pruneLeaf?.(nodeOrLeaf)) {
101
+ mapSet(node, path[p]);
102
+ }
103
+ return nodeOrLeaf;
104
+ }
105
+ const leaf = visitTree(nodeOrLeaf, path, ensureLeaf, pruneLeaf, p + 1);
106
+ if (collIsEmpty(nodeOrLeaf)) {
107
+ mapSet(node, path[p]);
108
+ }
109
+ return leaf;
110
+ },
111
+ );
90
112
 
91
113
  const object = Object;
92
114
  const objIds = object.keys;
@@ -104,64 +126,51 @@ const objIsEmpty = (obj) => arrayIsEmpty(objIds(obj));
104
126
  const setNew = (entries) => new Set(entries);
105
127
  const setAdd = (set, value) => set?.add(value);
106
128
 
107
- const addDeepSet = (deepSet, value, ids) =>
108
- arrayLength(ids) < 2
109
- ? setAdd(
110
- arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew),
111
- value,
112
- )
113
- : addDeepSet(
114
- mapEnsure(deepSet, ids[0], mapNew),
115
- value,
116
- arrayFromSecond(ids),
117
- );
118
- const forDeepSet = (valueDo) => {
119
- const deep = (deepIdSet, arg, ...ids) =>
120
- ifNotUndefined(deepIdSet, (deepIdSet2) =>
121
- arrayIsEmpty(ids)
122
- ? valueDo(deepIdSet2, arg)
123
- : arrayForEach([ids[0], null], (id) =>
124
- deep(mapGet(deepIdSet2, id), arg, ...arrayFromSecond(ids)),
125
- ),
126
- );
127
- return deep;
129
+ const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
130
+ const leaves = [];
131
+ const deep = (node, p) =>
132
+ p == arrayLength(path)
133
+ ? arrayPush(leaves, node)
134
+ : path[p] === null
135
+ ? collForEach(node, (node2) => deep(node2, p + 1))
136
+ : arrayForEach([path[p], null], (id) => deep(mapGet(node, id), p + 1));
137
+ deep(deepIdSet, 0);
138
+ return leaves;
128
139
  };
129
140
  const getListenerFunctions = (getThing) => {
130
141
  let thing;
131
142
  let nextId = 0;
132
143
  const listenerPool = [];
133
144
  const allListeners = mapNew();
134
- const addListener = (listener, deepSet, idOrNulls = []) => {
145
+ const addListener = (listener, idSetNode, path) => {
135
146
  thing ??= getThing();
136
- const id = arrayPop(listenerPool) ?? '' + nextId++;
137
- mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
138
- addDeepSet(deepSet, id, idOrNulls);
147
+ const id = arrayPop(listenerPool) ?? EMPTY_STRING + nextId++;
148
+ mapSet(allListeners, id, [listener, idSetNode, path]);
149
+ setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
139
150
  return id;
140
151
  };
141
- const callListeners = (deepSet, ids = [], ...extraArgs) =>
142
- forDeepSet(collForEach)(
143
- deepSet,
144
- (id) =>
145
- ifNotUndefined(mapGet(allListeners, id), ([listener]) =>
146
- listener(thing, ...ids, ...extraArgs),
147
- ),
148
- ...ids,
152
+ const callListeners = (idSetNode, ids, ...extraArgs) =>
153
+ arrayForEach(getWildcardedLeaves(idSetNode, ids), (set) =>
154
+ collForEach(set, (id) =>
155
+ mapGet(allListeners, id)[0](thing, ...(ids ?? []), ...extraArgs),
156
+ ),
149
157
  );
150
158
  const delListener = (id) =>
151
- ifNotUndefined(
152
- mapGet(allListeners, id),
153
- ([, deepSet, idOrNulls]) => {
154
- forDeepSet(collDel)(deepSet, id, ...idOrNulls);
155
- mapSet(allListeners, id);
156
- if (arrayLength(listenerPool) < 1e3) {
157
- arrayPush(listenerPool, id);
158
- }
159
- return idOrNulls;
160
- },
161
- () => [],
162
- );
159
+ ifNotUndefined(mapGet(allListeners, id), ([, idSetNode, idOrNulls]) => {
160
+ visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], void 0, (idSet) => {
161
+ collDel(idSet, id);
162
+ return collIsEmpty(idSet) ? 1 : 0;
163
+ });
164
+ mapSet(allListeners, id);
165
+ if (arrayLength(listenerPool) < 1e3) {
166
+ arrayPush(listenerPool, id);
167
+ }
168
+ return idOrNulls;
169
+ });
170
+ const hasListeners = (idSetNode, ids) =>
171
+ !arrayEvery(getWildcardedLeaves(idSetNode, ids), isUndefined);
163
172
  const callListener = (id, idNullGetters, extraArgsGetter) =>
164
- ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls]) => {
173
+ ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls = []]) => {
165
174
  const callWithIds = (...ids) => {
166
175
  const index = arrayLength(ids);
167
176
  index == arrayLength(idOrNulls)
@@ -174,9 +183,29 @@ const getListenerFunctions = (getThing) => {
174
183
  };
175
184
  callWithIds();
176
185
  });
177
- return [addListener, callListeners, delListener, callListener];
186
+ return [addListener, callListeners, delListener, hasListeners, callListener];
187
+ };
188
+
189
+ const pairNew = (value) => [value, value];
190
+ const pairCollSize2 = (pair, func = collSize2) => func(pair[0]) + func(pair[1]);
191
+ const pairCollIsEmpty = (pair) => pairCollSize2(pair) == 0;
192
+ const pairNewMap = () => [mapNew(), mapNew()];
193
+ const pair2CollSize2 = (pair2, func = collSize2) =>
194
+ pairCollSize2(pair2[0], func) + pairCollSize2(pair2[1], func);
195
+ const pair2NewMap = () => [pairNewMap(), pairNewMap()];
196
+
197
+ const getCellType = (cell) => {
198
+ const type = getTypeOf(cell);
199
+ return isTypeStringOrBoolean(type) || (type == NUMBER && isFiniteNumber(cell))
200
+ ? type
201
+ : void 0;
178
202
  };
203
+ const setOrDelCell = (store, tableId, rowId, cellId, cell) =>
204
+ isUndefined(cell)
205
+ ? store.delCell(tableId, rowId, cellId, true)
206
+ : store.setCell(tableId, rowId, cellId, cell);
179
207
 
208
+ const defaultSorter = (sortKey1, sortKey2) => (sortKey1 < sortKey2 ? -1 : 1);
180
209
  const id = (key) => EMPTY_STRING + key;
181
210
 
182
211
  const transformMap = (map, toBeLikeObject, setId, delId = mapSet) => {
@@ -190,12 +219,6 @@ const transformMap = (map, toBeLikeObject, setId, delId = mapSet) => {
190
219
  arrayForEach(idsToDelete, (id2) => delId(map, id2));
191
220
  return map;
192
221
  };
193
- const getCellType = (cell) => {
194
- const type = getTypeOf(cell);
195
- return isTypeStringOrBoolean(type) || (type == NUMBER && isFiniteNumber(cell))
196
- ? type
197
- : void 0;
198
- };
199
222
  const validate = (obj, validateChild, onInvalidObj) => {
200
223
  if (isUndefined(obj) || !isObject(obj) || objIsEmpty(obj) || objFrozen(obj)) {
201
224
  onInvalidObj?.();
@@ -208,8 +231,8 @@ const validate = (obj, validateChild, onInvalidObj) => {
208
231
  });
209
232
  return !objIsEmpty(obj);
210
233
  };
211
- const idsChanged = (ids, id2, added) =>
212
- mapSet(ids, id2, mapGet(ids, id2) == -added ? void 0 : added);
234
+ const idsChanged = (changedIds, id2, added) =>
235
+ mapSet(changedIds, id2, mapGet(changedIds, id2) == -added ? void 0 : added);
213
236
  const createStore = () => {
214
237
  let hasSchema;
215
238
  let cellsTouched;
@@ -223,17 +246,23 @@ const createStore = () => {
223
246
  const schemaMap = mapNew();
224
247
  const schemaRowCache = mapNew();
225
248
  const tablesMap = mapNew();
226
- const tablesListeners = mapNewPair(setNew);
227
- const tableIdsListeners = mapNewPair(setNew);
228
- const tableListeners = mapNewPair();
229
- const rowIdsListeners = mapNewPair();
230
- const rowListeners = mapNewPair();
231
- const cellIdsListeners = mapNewPair();
232
- const cellListeners = mapNewPair();
233
- const invalidCellListeners = mapNewPair();
234
- const finishTransactionListeners = mapNewPair(setNew);
235
- const [addListener, callListeners, delListenerImpl, callListenerImpl] =
236
- getListenerFunctions(() => store);
249
+ const tablesListeners = pairNewMap();
250
+ const tableIdsListeners = pair2NewMap();
251
+ const tableListeners = pairNewMap();
252
+ const rowIdsListeners = pair2NewMap();
253
+ const sortedRowIdsListeners = pairNewMap();
254
+ const rowListeners = pairNewMap();
255
+ const cellIdsListeners = pair2NewMap();
256
+ const cellListeners = pairNewMap();
257
+ const invalidCellListeners = pairNewMap();
258
+ const finishTransactionListeners = pairNewMap();
259
+ const [
260
+ addListener,
261
+ callListeners,
262
+ delListenerImpl,
263
+ hasListeners,
264
+ callListenerImpl,
265
+ ] = getListenerFunctions(() => store);
237
266
  const validateSchema = (schema) =>
238
267
  validate(schema, (tableSchema) =>
239
268
  validate(tableSchema, (cellSchema) => {
@@ -415,12 +444,49 @@ const createStore = () => {
415
444
  }
416
445
  };
417
446
  const tableIdsChanged = (tableId, added) =>
418
- idsChanged(changedTableIds, tableId, added);
447
+ idsChanged(
448
+ collIsEmpty(changedTableIds)
449
+ ? mapSet(
450
+ changedTableIds,
451
+ null,
452
+ hasListeners(tableIdsListeners[0][1]) ||
453
+ hasListeners(tableIdsListeners[1][1])
454
+ ? getTableIds()
455
+ : 0,
456
+ )
457
+ : changedTableIds,
458
+ tableId,
459
+ added,
460
+ );
419
461
  const rowIdsChanged = (tableId, rowId, added) =>
420
- idsChanged(mapEnsure(changedRowIds, tableId, mapNew), rowId, added);
462
+ idsChanged(
463
+ mapEnsure(changedRowIds, tableId, () =>
464
+ mapNew([
465
+ [
466
+ null,
467
+ hasListeners(rowIdsListeners[0][1], [tableId]) ||
468
+ hasListeners(rowIdsListeners[1][1], [tableId])
469
+ ? getRowIds(tableId)
470
+ : 0,
471
+ ],
472
+ ]),
473
+ ),
474
+ rowId,
475
+ added,
476
+ );
421
477
  const cellIdsChanged = (tableId, rowId, cellId, added) =>
422
478
  idsChanged(
423
- mapEnsure(mapEnsure(changedCellIds, tableId, mapNew), rowId, mapNew),
479
+ mapEnsure(mapEnsure(changedCellIds, tableId, mapNew), rowId, () =>
480
+ mapNew([
481
+ [
482
+ null,
483
+ hasListeners(cellIdsListeners[0][1], [tableId, rowId]) ||
484
+ hasListeners(cellIdsListeners[1][1], [tableId, rowId])
485
+ ? getCellIds(tableId, rowId)
486
+ : 0,
487
+ ],
488
+ ]),
489
+ ),
424
490
  cellId,
425
491
  added,
426
492
  );
@@ -445,7 +511,7 @@ const createStore = () => {
445
511
  ifNotUndefined(
446
512
  mapGet(mapGet(mapGet(changedCells, tableId), rowId), cellId),
447
513
  ([oldCell, newCell]) => [true, oldCell, newCell],
448
- () => [false, ...arrayPair(getCell(tableId, rowId, cellId))],
514
+ () => [false, ...pairNew(getCell(tableId, rowId, cellId))],
449
515
  );
450
516
  const callInvalidCellListeners = (mutator) =>
451
517
  !collIsEmpty(invalidCells) && !collIsEmpty(invalidCellListeners[mutator])
@@ -463,17 +529,36 @@ const createStore = () => {
463
529
  ),
464
530
  )
465
531
  : 0;
532
+ const callIdsListenersIfChanged = (listeners, changedIds, getIds, ids) => {
533
+ if (collSize(changedIds) > 1) {
534
+ callListeners(listeners[0], ids);
535
+ callListeners(listeners[1], ids);
536
+ return 1;
537
+ }
538
+ if (
539
+ !collIsEmpty(changedIds) &&
540
+ mapGet(changedIds, null) != 0 &&
541
+ !arrayIsEqual(mapGet(changedIds, null), getIds(...(ids ?? [])))
542
+ ) {
543
+ callListeners(listeners[1], ids);
544
+ return 1;
545
+ }
546
+ };
466
547
  const callListenersForChanges = (mutator) => {
548
+ const emptySortedRowIdListeners = collIsEmpty(
549
+ sortedRowIdsListeners[mutator],
550
+ );
467
551
  const emptyIdListeners =
468
- collIsEmpty(cellIdsListeners[mutator]) &&
469
- collIsEmpty(rowIdsListeners[mutator]) &&
470
- collIsEmpty(tableIdsListeners[mutator]);
552
+ pairCollIsEmpty(cellIdsListeners[mutator]) &&
553
+ pairCollIsEmpty(rowIdsListeners[mutator]) &&
554
+ emptySortedRowIdListeners &&
555
+ pairCollIsEmpty(tableIdsListeners[mutator]);
471
556
  const emptyOtherListeners =
472
557
  collIsEmpty(cellListeners[mutator]) &&
473
558
  collIsEmpty(rowListeners[mutator]) &&
474
559
  collIsEmpty(tableListeners[mutator]) &&
475
560
  collIsEmpty(tablesListeners[mutator]);
476
- if (!(emptyIdListeners && emptyOtherListeners)) {
561
+ if (!emptyIdListeners || !emptyOtherListeners) {
477
562
  const changes = mutator
478
563
  ? [
479
564
  mapClone(changedTableIds),
@@ -484,20 +569,55 @@ const createStore = () => {
484
569
  : [changedTableIds, changedRowIds, changedCellIds, changedCells];
485
570
  if (!emptyIdListeners) {
486
571
  collForEach(changes[2], (rowCellIds, tableId) =>
487
- collForEach(rowCellIds, (changedIds, rowId) => {
488
- if (!collIsEmpty(changedIds)) {
489
- callListeners(cellIdsListeners[mutator], [tableId, rowId]);
490
- }
491
- }),
572
+ collForEach(rowCellIds, (changedIds, rowId) =>
573
+ callIdsListenersIfChanged(
574
+ cellIdsListeners[mutator],
575
+ changedIds,
576
+ getCellIds,
577
+ [tableId, rowId],
578
+ ),
579
+ ),
492
580
  );
581
+ const calledSortableTableIds = setNew();
493
582
  collForEach(changes[1], (changedIds, tableId) => {
494
- if (!collIsEmpty(changedIds)) {
495
- callListeners(rowIdsListeners[mutator], [tableId]);
583
+ if (
584
+ callIdsListenersIfChanged(
585
+ rowIdsListeners[mutator],
586
+ changedIds,
587
+ getRowIds,
588
+ [tableId],
589
+ ) &&
590
+ !emptySortedRowIdListeners
591
+ ) {
592
+ callListeners(sortedRowIdsListeners[mutator], [tableId, null]);
593
+ setAdd(calledSortableTableIds, tableId);
496
594
  }
497
595
  });
498
- if (!collIsEmpty(changes[0])) {
499
- callListeners(tableIdsListeners[mutator]);
596
+ if (!emptySortedRowIdListeners) {
597
+ collForEach(changes[3], (rows, tableId) => {
598
+ if (!collHas(calledSortableTableIds, tableId)) {
599
+ const sortableCellIds = setNew();
600
+ collForEach(rows, (cells) =>
601
+ collForEach(cells, ([oldCell, newCell], cellId) =>
602
+ newCell !== oldCell
603
+ ? setAdd(sortableCellIds, cellId)
604
+ : collDel(cells, cellId),
605
+ ),
606
+ );
607
+ collForEach(sortableCellIds, (cellId) =>
608
+ callListeners(sortedRowIdsListeners[mutator], [
609
+ tableId,
610
+ cellId,
611
+ ]),
612
+ );
613
+ }
614
+ });
500
615
  }
616
+ callIdsListenersIfChanged(
617
+ tableIdsListeners[mutator],
618
+ changes[0],
619
+ getTableIds,
620
+ );
501
621
  }
502
622
  if (!emptyOtherListeners) {
503
623
  let tablesChanged;
@@ -530,7 +650,7 @@ const createStore = () => {
530
650
  }
531
651
  });
532
652
  if (tablesChanged) {
533
- callListeners(tablesListeners[mutator], [], getCellChange);
653
+ callListeners(tablesListeners[mutator], void 0, getCellChange);
534
654
  }
535
655
  }
536
656
  }
@@ -545,6 +665,23 @@ const createStore = () => {
545
665
  const getTable = (tableId) =>
546
666
  mapToObj(mapGet(tablesMap, id(tableId)), mapToObj);
547
667
  const getRowIds = (tableId) => mapKeys(mapGet(tablesMap, id(tableId)));
668
+ const getSortedRowIds = (tableId, cellId, descending) => {
669
+ const cells = [];
670
+ mapForEach(mapGet(tablesMap, id(tableId)), (rowId, row) =>
671
+ arrayPush(cells, [
672
+ isUndefined(cellId) ? rowId : mapGet(row, id(cellId)),
673
+ rowId,
674
+ ]),
675
+ );
676
+ return arrayMap(
677
+ arraySort(
678
+ cells,
679
+ ([cell1], [cell2]) =>
680
+ defaultSorter(cell1, cell2) * (descending ? -1 : 1),
681
+ ),
682
+ ([, rowId]) => rowId,
683
+ );
684
+ };
548
685
  const getRow = (tableId, rowId) =>
549
686
  mapToObj(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)));
550
687
  const getCellIds = (tableId, rowId) =>
@@ -583,17 +720,16 @@ const createStore = () => {
583
720
  tableId,
584
721
  rowId,
585
722
  );
586
- const addRow = (tableId, row) =>
723
+ const addRow = (tableId, row, forceId) =>
587
724
  transaction(() => {
588
- let rowId = void 0;
589
- if (validateRow(tableId, rowId, row)) {
590
- tableId = id(tableId);
591
- setValidRow(
592
- tableId,
593
- getOrCreateTable(tableId),
594
- (rowId = getNewRowId(mapGet(tablesMap, tableId))),
595
- row,
596
- );
725
+ tableId = id(tableId);
726
+ const isValidRow = validateRow(tableId, void 0, row);
727
+ const rowId =
728
+ isValidRow || forceId
729
+ ? getNewRowId(mapGet(tablesMap, tableId))
730
+ : void 0;
731
+ if (isValidRow) {
732
+ setValidRow(tableId, getOrCreateTable(tableId), rowId, row);
597
733
  }
598
734
  return rowId;
599
735
  });
@@ -742,21 +878,19 @@ const createStore = () => {
742
878
  collForEach(changedCells, (table, tableId) =>
743
879
  collForEach(table, (row, rowId) =>
744
880
  collForEach(row, ([oldCell], cellId) =>
745
- isUndefined(oldCell)
746
- ? delCell(tableId, rowId, cellId, true)
747
- : setCell(tableId, rowId, cellId, oldCell),
881
+ setOrDelCell(store, tableId, rowId, cellId, oldCell),
748
882
  ),
749
883
  ),
750
884
  );
751
885
  transactions = -1;
752
886
  cellsTouched = false;
753
887
  }
754
- callListeners(finishTransactionListeners[0], [], cellsTouched);
888
+ callListeners(finishTransactionListeners[0], void 0, cellsTouched);
755
889
  callInvalidCellListeners(0);
756
890
  if (cellsTouched) {
757
891
  callListenersForChanges(0);
758
892
  }
759
- callListeners(finishTransactionListeners[1], [], cellsTouched);
893
+ callListeners(finishTransactionListeners[1], void 0, cellsTouched);
760
894
  transactions = 0;
761
895
  arrayForEach(
762
896
  [
@@ -790,16 +924,53 @@ const createStore = () => {
790
924
  mapForEach(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)), cellCallback);
791
925
  const addTablesListener = (listener, mutator) =>
792
926
  addListener(listener, tablesListeners[mutator ? 1 : 0]);
793
- const addTableIdsListener = (listener, mutator) =>
794
- addListener(listener, tableIdsListeners[mutator ? 1 : 0]);
927
+ const addTableIdsListener = (listener, trackReorder, mutator) =>
928
+ addListener(
929
+ listener,
930
+ tableIdsListeners[mutator ? 1 : 0][trackReorder ? 1 : 0],
931
+ );
795
932
  const addTableListener = (tableId, listener, mutator) =>
796
933
  addListener(listener, tableListeners[mutator ? 1 : 0], [tableId]);
797
- const addRowIdsListener = (tableId, listener, mutator) =>
798
- addListener(listener, rowIdsListeners[mutator ? 1 : 0], [tableId]);
934
+ const addRowIdsListener = (tableId, listener, trackReorder, mutator) =>
935
+ addListener(
936
+ listener,
937
+ rowIdsListeners[mutator ? 1 : 0][trackReorder ? 1 : 0],
938
+ [tableId],
939
+ );
940
+ const addSortedRowIdsListener = (
941
+ tableId,
942
+ cellId,
943
+ descending,
944
+ listener,
945
+ mutator,
946
+ ) => {
947
+ let sortedRowIds = getSortedRowIds(tableId, cellId, descending);
948
+ return addListener(
949
+ () => {
950
+ const newSortedRowIds = getSortedRowIds(tableId, cellId, descending);
951
+ if (!arrayIsEqual(newSortedRowIds, sortedRowIds)) {
952
+ sortedRowIds = newSortedRowIds;
953
+ listener(store, tableId, cellId, descending, sortedRowIds);
954
+ }
955
+ },
956
+ sortedRowIdsListeners[mutator ? 1 : 0],
957
+ [tableId, cellId],
958
+ );
959
+ };
799
960
  const addRowListener = (tableId, rowId, listener, mutator) =>
800
961
  addListener(listener, rowListeners[mutator ? 1 : 0], [tableId, rowId]);
801
- const addCellIdsListener = (tableId, rowId, listener, mutator) =>
802
- addListener(listener, cellIdsListeners[mutator ? 1 : 0], [tableId, rowId]);
962
+ const addCellIdsListener = (
963
+ tableId,
964
+ rowId,
965
+ listener,
966
+ trackReorder,
967
+ mutator,
968
+ ) =>
969
+ addListener(
970
+ listener,
971
+ cellIdsListeners[mutator ? 1 : 0][trackReorder ? 1 : 0],
972
+ [tableId, rowId],
973
+ );
803
974
  const addCellListener = (tableId, rowId, cellId, listener, mutator) =>
804
975
  addListener(listener, cellListeners[mutator ? 1 : 0], [
805
976
  tableId,
@@ -818,7 +989,7 @@ const createStore = () => {
818
989
  addListener(listener, finishTransactionListeners[1]);
819
990
  const callListener = (listenerId) => {
820
991
  callListenerImpl(listenerId, [getTableIds, getRowIds, getCellIds], (ids) =>
821
- isUndefined(ids[2]) ? [] : arrayPair(getCell(...ids)),
992
+ isUndefined(ids[2]) ? [] : pairNew(getCell(...ids)),
822
993
  );
823
994
  return store;
824
995
  };
@@ -827,21 +998,23 @@ const createStore = () => {
827
998
  return store;
828
999
  };
829
1000
  const getListenerStats = () => ({
830
- tables: collPairSize(tablesListeners),
831
- tableIds: collPairSize(tableIdsListeners),
832
- table: collPairSize(tableListeners, collSize2),
833
- rowIds: collPairSize(rowIdsListeners, collSize2),
834
- row: collPairSize(rowListeners, collSize3),
835
- cellIds: collPairSize(cellIdsListeners, collSize3),
836
- cell: collPairSize(cellListeners, collSize4),
837
- invalidCell: collPairSize(invalidCellListeners, collSize4),
838
- transaction: collPairSize(finishTransactionListeners),
1001
+ tables: pairCollSize2(tablesListeners),
1002
+ tableIds: pair2CollSize2(tableIdsListeners),
1003
+ table: pairCollSize2(tableListeners),
1004
+ rowIds: pair2CollSize2(rowIdsListeners),
1005
+ sortedRowIds: pairCollSize2(sortedRowIdsListeners),
1006
+ row: pairCollSize2(rowListeners, collSize3),
1007
+ cellIds: pair2CollSize2(cellIdsListeners, collSize3),
1008
+ cell: pairCollSize2(cellListeners, collSize4),
1009
+ invalidCell: pairCollSize2(invalidCellListeners, collSize4),
1010
+ transaction: pairCollSize2(finishTransactionListeners),
839
1011
  });
840
1012
  const store = {
841
1013
  getTables,
842
1014
  getTableIds,
843
1015
  getTable,
844
1016
  getRowIds,
1017
+ getSortedRowIds,
845
1018
  getRow,
846
1019
  getCellIds,
847
1020
  getCell,
@@ -874,6 +1047,7 @@ const createStore = () => {
874
1047
  addTableIdsListener,
875
1048
  addTableListener,
876
1049
  addRowIdsListener,
1050
+ addSortedRowIdsListener,
877
1051
  addRowListener,
878
1052
  addCellIdsListener,
879
1053
  addCellListener,
@@ -883,6 +1057,7 @@ const createStore = () => {
883
1057
  callListener,
884
1058
  delListener,
885
1059
  getListenerStats,
1060
+ createStore,
886
1061
  };
887
1062
  return objFreeze(store);
888
1063
  };
@@ -9,5 +9,6 @@ export * from './common';
9
9
  export * from './indexes';
10
10
  export * from './metrics';
11
11
  export * from './persisters';
12
+ export * from './queries';
12
13
  export * from './relationships';
13
14
  export * from './store';