tinybase 3.2.0-beta.0 → 3.3.0

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 (139) hide show
  1. package/bin/cli.js +1 -1
  2. package/lib/checkpoints.js +1 -1
  3. package/lib/checkpoints.js.gz +0 -0
  4. package/lib/cjs/checkpoints.cjs +1 -1
  5. package/lib/cjs/checkpoints.cjs.gz +0 -0
  6. package/lib/cjs/indexes.cjs +1 -1
  7. package/lib/cjs/indexes.cjs.gz +0 -0
  8. package/lib/cjs/metrics.cjs +1 -1
  9. package/lib/cjs/metrics.cjs.gz +0 -0
  10. package/lib/cjs/persisters.cjs +1 -1
  11. package/lib/cjs/persisters.cjs.gz +0 -0
  12. package/lib/cjs/queries.cjs +1 -1
  13. package/lib/cjs/queries.cjs.gz +0 -0
  14. package/lib/cjs/relationships.cjs +1 -1
  15. package/lib/cjs/relationships.cjs.gz +0 -0
  16. package/lib/cjs/store.cjs +1 -1
  17. package/lib/cjs/store.cjs.gz +0 -0
  18. package/lib/cjs/tinybase.cjs +1 -1
  19. package/lib/cjs/tinybase.cjs.gz +0 -0
  20. package/lib/cjs/tools.cjs +1 -1
  21. package/lib/cjs/tools.cjs.gz +0 -0
  22. package/lib/cjs/ui-react.cjs +1 -1
  23. package/lib/cjs/ui-react.cjs.gz +0 -0
  24. package/lib/cjs-es6/checkpoints.cjs +1 -1
  25. package/lib/cjs-es6/checkpoints.cjs.gz +0 -0
  26. package/lib/cjs-es6/indexes.cjs +1 -1
  27. package/lib/cjs-es6/indexes.cjs.gz +0 -0
  28. package/lib/cjs-es6/metrics.cjs +1 -1
  29. package/lib/cjs-es6/metrics.cjs.gz +0 -0
  30. package/lib/cjs-es6/persisters.cjs +1 -1
  31. package/lib/cjs-es6/persisters.cjs.gz +0 -0
  32. package/lib/cjs-es6/queries.cjs +1 -1
  33. package/lib/cjs-es6/queries.cjs.gz +0 -0
  34. package/lib/cjs-es6/relationships.cjs +1 -1
  35. package/lib/cjs-es6/relationships.cjs.gz +0 -0
  36. package/lib/cjs-es6/store.cjs +1 -1
  37. package/lib/cjs-es6/store.cjs.gz +0 -0
  38. package/lib/cjs-es6/tinybase.cjs +1 -1
  39. package/lib/cjs-es6/tinybase.cjs.gz +0 -0
  40. package/lib/cjs-es6/tools.cjs +1 -1
  41. package/lib/cjs-es6/tools.cjs.gz +0 -0
  42. package/lib/cjs-es6/ui-react.cjs +1 -1
  43. package/lib/cjs-es6/ui-react.cjs.gz +0 -0
  44. package/lib/debug/checkpoints.js +2 -2
  45. package/lib/debug/indexes.js +2 -2
  46. package/lib/debug/metrics.js +2 -2
  47. package/lib/debug/persisters.js +2 -2
  48. package/lib/debug/queries.js +1 -1
  49. package/lib/debug/relationships.js +2 -2
  50. package/lib/debug/store.js +89 -48
  51. package/lib/debug/tinybase.js +92 -51
  52. package/lib/debug/tools.js +106 -5
  53. package/lib/debug/ui-react.js +27 -2
  54. package/lib/es6/checkpoints.js +1 -1
  55. package/lib/es6/checkpoints.js.gz +0 -0
  56. package/lib/es6/indexes.js +1 -1
  57. package/lib/es6/indexes.js.gz +0 -0
  58. package/lib/es6/metrics.js +1 -1
  59. package/lib/es6/metrics.js.gz +0 -0
  60. package/lib/es6/persisters.js +1 -1
  61. package/lib/es6/persisters.js.gz +0 -0
  62. package/lib/es6/queries.js +1 -1
  63. package/lib/es6/queries.js.gz +0 -0
  64. package/lib/es6/relationships.js +1 -1
  65. package/lib/es6/relationships.js.gz +0 -0
  66. package/lib/es6/store.js +1 -1
  67. package/lib/es6/store.js.gz +0 -0
  68. package/lib/es6/tinybase.js +1 -1
  69. package/lib/es6/tinybase.js.gz +0 -0
  70. package/lib/es6/tools.js +1 -1
  71. package/lib/es6/tools.js.gz +0 -0
  72. package/lib/es6/ui-react.js +1 -1
  73. package/lib/es6/ui-react.js.gz +0 -0
  74. package/lib/indexes.js +1 -1
  75. package/lib/indexes.js.gz +0 -0
  76. package/lib/metrics.js +1 -1
  77. package/lib/metrics.js.gz +0 -0
  78. package/lib/persisters.js +1 -1
  79. package/lib/persisters.js.gz +0 -0
  80. package/lib/queries.js +1 -1
  81. package/lib/queries.js.gz +0 -0
  82. package/lib/relationships.js +1 -1
  83. package/lib/relationships.js.gz +0 -0
  84. package/lib/store.js +1 -1
  85. package/lib/store.js.gz +0 -0
  86. package/lib/tinybase.js +1 -1
  87. package/lib/tinybase.js.gz +0 -0
  88. package/lib/tools.js +1 -1
  89. package/lib/tools.js.gz +0 -0
  90. package/lib/types/store.d.ts +386 -30
  91. package/lib/types/tools.d.ts +2 -2
  92. package/lib/types/ui-react.d.ts +167 -0
  93. package/lib/types/with-schemas/store.d.ts +496 -37
  94. package/lib/types/with-schemas/tools.d.ts +2 -2
  95. package/lib/types/with-schemas/ui-react.d.ts +193 -5
  96. package/lib/ui-react.js +1 -1
  97. package/lib/ui-react.js.gz +0 -0
  98. package/lib/umd/checkpoints.js +1 -1
  99. package/lib/umd/checkpoints.js.gz +0 -0
  100. package/lib/umd/indexes.js +1 -1
  101. package/lib/umd/indexes.js.gz +0 -0
  102. package/lib/umd/metrics.js +1 -1
  103. package/lib/umd/metrics.js.gz +0 -0
  104. package/lib/umd/persisters.js +1 -1
  105. package/lib/umd/persisters.js.gz +0 -0
  106. package/lib/umd/queries.js +1 -1
  107. package/lib/umd/queries.js.gz +0 -0
  108. package/lib/umd/relationships.js +1 -1
  109. package/lib/umd/relationships.js.gz +0 -0
  110. package/lib/umd/store.js +1 -1
  111. package/lib/umd/store.js.gz +0 -0
  112. package/lib/umd/tinybase.js +1 -1
  113. package/lib/umd/tinybase.js.gz +0 -0
  114. package/lib/umd/tools.js +1 -1
  115. package/lib/umd/tools.js.gz +0 -0
  116. package/lib/umd/ui-react.js +1 -1
  117. package/lib/umd/ui-react.js.gz +0 -0
  118. package/lib/umd-es6/checkpoints.js +1 -1
  119. package/lib/umd-es6/checkpoints.js.gz +0 -0
  120. package/lib/umd-es6/indexes.js +1 -1
  121. package/lib/umd-es6/indexes.js.gz +0 -0
  122. package/lib/umd-es6/metrics.js +1 -1
  123. package/lib/umd-es6/metrics.js.gz +0 -0
  124. package/lib/umd-es6/persisters.js +1 -1
  125. package/lib/umd-es6/persisters.js.gz +0 -0
  126. package/lib/umd-es6/queries.js +1 -1
  127. package/lib/umd-es6/queries.js.gz +0 -0
  128. package/lib/umd-es6/relationships.js +1 -1
  129. package/lib/umd-es6/relationships.js.gz +0 -0
  130. package/lib/umd-es6/store.js +1 -1
  131. package/lib/umd-es6/store.js.gz +0 -0
  132. package/lib/umd-es6/tinybase.js +1 -1
  133. package/lib/umd-es6/tinybase.js.gz +0 -0
  134. package/lib/umd-es6/tools.js +1 -1
  135. package/lib/umd-es6/tools.js.gz +0 -0
  136. package/lib/umd-es6/ui-react.js +1 -1
  137. package/lib/umd-es6/ui-react.js.gz +0 -0
  138. package/package.json +52 -28
  139. package/readme.md +14 -14
@@ -32,7 +32,6 @@ const arrayMap = (array, cb) => array.map(cb);
32
32
  const arrayLength = (array) => array.length;
33
33
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
34
34
  const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
35
- const arrayFilter = (array, cb) => array.filter(cb);
36
35
  const arraySlice = (array, start, end) => array.slice(start, end);
37
36
  const arrayPush = (array, ...values) => array.push(...values);
38
37
  const arrayShift = (array) => array.shift();
@@ -141,7 +140,7 @@ const getPoolFunctions = () => {
141
140
  const pool = [];
142
141
  let nextId = 0;
143
142
  return [
144
- () => arrayShift(pool) ?? EMPTY_STRING + nextId++,
143
+ (reuse) => (reuse ? arrayShift(pool) : null) ?? EMPTY_STRING + nextId++,
145
144
  (id) => {
146
145
  if (test(INTEGER, id) && arrayLength(pool) < 1e3) {
147
146
  arrayPush(pool, id);
@@ -173,7 +172,7 @@ const getListenerFunctions = (getThing) => {
173
172
  extraArgsGetter = () => [],
174
173
  ) => {
175
174
  thing ??= getThing();
176
- const id = getId();
175
+ const id = getId(1);
177
176
  mapSet(allListeners, id, [
178
177
  listener,
179
178
  idSetNode,
@@ -252,15 +251,9 @@ const setOrDelValue = (store, valueId, value) =>
252
251
 
253
252
  const defaultSorter = (sortKey1, sortKey2) => (sortKey1 < sortKey2 ? -1 : 1);
254
253
 
255
- const transformMap = (map, toBeLikeObject, setId, delId = mapSet) => {
256
- const idsToDelete = arrayFilter(
257
- mapKeys(map),
258
- (id2) => !objHas(toBeLikeObject, id2),
259
- );
260
- arrayForEach(objIds(toBeLikeObject), (id2) =>
261
- setId(map, id2, toBeLikeObject[id2]),
262
- );
263
- arrayForEach(idsToDelete, (id2) => delId(map, id2));
254
+ const mapMatch = (map, obj, set, del = mapSet) => {
255
+ objMap(obj, (value, id2) => set(map, id2, value));
256
+ mapForEach(map, (id2) => (objHas(obj, id2) ? 0 : del(map, id2)));
264
257
  return map;
265
258
  };
266
259
  const validate = (obj, validateChild, onInvalidObj) => {
@@ -284,6 +277,7 @@ const createStore = () => {
284
277
  let valuesTouched;
285
278
  let transactions = 0;
286
279
  const changedTableIds = mapNew();
280
+ const changedTableCellIds = mapNew();
287
281
  const changedRowIds = mapNew();
288
282
  const changedCellIds = mapNew();
289
283
  const changedCells = mapNew();
@@ -297,11 +291,13 @@ const createStore = () => {
297
291
  const valuesDefaulted = mapNew();
298
292
  const valuesNonDefaulted = setNew();
299
293
  const tablePoolFunctions = mapNew();
294
+ const tableCellIds = mapNew();
300
295
  const tablesMap = mapNew();
301
296
  const valuesMap = mapNew();
302
297
  const tablesListeners = pairNewMap();
303
298
  const tableIdsListeners = pairNewMap();
304
299
  const tableListeners = pairNewMap();
300
+ const tableCellIdsListeners = pairNewMap();
305
301
  const rowIdsListeners = pairNewMap();
306
302
  const sortedRowIdsListeners = pairNewMap();
307
303
  const rowListeners = pairNewMap();
@@ -312,6 +308,7 @@ const createStore = () => {
312
308
  const valuesListeners = pairNewMap();
313
309
  const valueIdsListeners = pairNewMap();
314
310
  const valueListeners = pairNewMap();
311
+ const startTransactionListeners = mapNew();
315
312
  const finishTransactionListeners = pairNewMap();
316
313
  const [addListener, callListeners, delListenerImpl, callListenerImpl] =
317
314
  getListenerFunctions(() => store);
@@ -433,13 +430,13 @@ const createStore = () => {
433
430
  return values;
434
431
  };
435
432
  const setValidTablesSchema = (tablesSchema) =>
436
- transformMap(
433
+ mapMatch(
437
434
  tablesSchemaMap,
438
435
  tablesSchema,
439
436
  (_tablesSchema, tableId, tableSchema) => {
440
437
  const rowDefaulted = mapNew();
441
438
  const rowNonDefaulted = setNew();
442
- transformMap(
439
+ mapMatch(
443
440
  mapEnsure(tablesSchemaMap, tableId, mapNew),
444
441
  tableSchema,
445
442
  (tableSchemaMap, cellId, cellSchema) => {
@@ -459,7 +456,7 @@ const createStore = () => {
459
456
  },
460
457
  );
461
458
  const setValidValuesSchema = (valuesSchema) =>
462
- transformMap(
459
+ mapMatch(
463
460
  valuesSchemaMap,
464
461
  valuesSchema,
465
462
  (_valuesSchema, valueId, valueSchema) => {
@@ -479,16 +476,18 @@ const createStore = () => {
479
476
  const setOrDelTables = (tables) =>
480
477
  objIsEmpty(tables) ? delTables() : setTables(tables);
481
478
  const setValidTables = (tables) =>
482
- transformMap(
479
+ mapMatch(
483
480
  tablesMap,
484
481
  tables,
485
482
  (_tables, tableId, table) => setValidTable(tableId, table),
486
483
  (_tables, tableId) => delValidTable(tableId),
487
484
  );
488
485
  const setValidTable = (tableId, table) =>
489
- transformMap(
486
+ mapMatch(
490
487
  mapEnsure(tablesMap, tableId, () => {
491
488
  tableIdsChanged(tableId, 1);
489
+ mapSet(tablePoolFunctions, tableId, getPoolFunctions());
490
+ mapSet(tableCellIds, tableId, mapNew());
492
491
  return mapNew();
493
492
  }),
494
493
  table,
@@ -496,7 +495,7 @@ const createStore = () => {
496
495
  (tableMap, rowId) => delValidRow(tableId, tableMap, rowId),
497
496
  );
498
497
  const setValidRow = (tableId, tableMap, rowId, row, forceDel) =>
499
- transformMap(
498
+ mapMatch(
500
499
  mapEnsure(tableMap, rowId, () => {
501
500
  rowIdsChanged(tableId, rowId, 1);
502
501
  return mapNew();
@@ -532,7 +531,7 @@ const createStore = () => {
532
531
  const setOrDelValues = (values) =>
533
532
  objIsEmpty(values) ? delValues() : setValues(values);
534
533
  const setValidValues = (values) =>
535
- transformMap(
534
+ mapMatch(
536
535
  valuesMap,
537
536
  values,
538
537
  (_valuesMap, valueId, value) => setValidValue(valueId, value),
@@ -548,23 +547,19 @@ const createStore = () => {
548
547
  mapSet(valuesMap, valueId, value);
549
548
  }
550
549
  };
551
- const getNewRowId = (tableId) => {
552
- const [getId] = mapEnsure(tablePoolFunctions, tableId, getPoolFunctions);
553
- const rowId = getId();
550
+ const getNewRowId = (tableId, reuse) => {
551
+ const [getId] = mapGet(tablePoolFunctions, tableId);
552
+ const rowId = getId(reuse);
554
553
  if (!collHas(mapGet(tablesMap, tableId), rowId)) {
555
554
  return rowId;
556
555
  }
557
- return getNewRowId(tableId);
556
+ return getNewRowId(tableId, reuse);
558
557
  };
559
558
  const getOrCreateTable = (tableId) =>
560
559
  mapGet(tablesMap, tableId) ?? setValidTable(tableId, {});
561
560
  const delValidTable = (tableId) => setValidTable(tableId, {});
562
561
  const delValidRow = (tableId, tableMap, rowId) => {
563
- const [, releaseId] = mapEnsure(
564
- tablePoolFunctions,
565
- tableId,
566
- getPoolFunctions,
567
- );
562
+ const [, releaseId] = mapGet(tablePoolFunctions, tableId);
568
563
  releaseId(rowId);
569
564
  setValidRow(tableId, tableMap, rowId, {}, true);
570
565
  };
@@ -588,6 +583,7 @@ const createStore = () => {
588
583
  tableIdsChanged(tableId, -1);
589
584
  mapSet(tablesMap, tableId);
590
585
  mapSet(tablePoolFunctions, tableId);
586
+ mapSet(tableCellIds, tableId);
591
587
  }
592
588
  }
593
589
  };
@@ -604,12 +600,23 @@ const createStore = () => {
604
600
  idsChanged(changedTableIds, tableId, added);
605
601
  const rowIdsChanged = (tableId, rowId, added) =>
606
602
  idsChanged(mapEnsure(changedRowIds, tableId, mapNew), rowId, added);
607
- const cellIdsChanged = (tableId, rowId, cellId, added) =>
603
+ const cellIdsChanged = (tableId, rowId, cellId, added) => {
604
+ const cellIds = mapGet(tableCellIds, tableId);
605
+ const count = mapGet(cellIds, cellId) ?? 0;
606
+ if ((count == 0 && added == 1) || (count == 1 && added == -1)) {
607
+ idsChanged(
608
+ mapEnsure(changedTableCellIds, tableId, mapNew),
609
+ cellId,
610
+ added,
611
+ );
612
+ }
613
+ mapSet(cellIds, cellId, count != -added ? count + added : null);
608
614
  idsChanged(
609
615
  mapEnsure(mapEnsure(changedCellIds, tableId, mapNew), rowId, mapNew),
610
616
  cellId,
611
617
  added,
612
618
  );
619
+ };
613
620
  const cellChanged = (tableId, rowId, cellId, oldCell, newCell) =>
614
621
  (mapEnsure(
615
622
  mapEnsure(mapEnsure(changedCells, tableId, mapNew), rowId, mapNew),
@@ -680,7 +687,7 @@ const createStore = () => {
680
687
  : 0;
681
688
  const callIdsListenersIfChanged = (listeners, changedIds, ids) => {
682
689
  if (!collIsEmpty(changedIds)) {
683
- callListeners(listeners, ids);
690
+ callListeners(listeners, ids, () => mapToObj(changedIds));
684
691
  return 1;
685
692
  }
686
693
  };
@@ -690,6 +697,7 @@ const createStore = () => {
690
697
  );
691
698
  const emptyIdListeners =
692
699
  collIsEmpty(cellIdsListeners[mutator]) &&
700
+ collIsEmpty(tableCellIdsListeners[mutator]) &&
693
701
  collIsEmpty(rowIdsListeners[mutator]) &&
694
702
  emptySortedRowIdListeners &&
695
703
  collIsEmpty(tableIdsListeners[mutator]);
@@ -702,13 +710,27 @@ const createStore = () => {
702
710
  const changes = mutator
703
711
  ? [
704
712
  mapClone(changedTableIds),
713
+ mapClone2(changedTableCellIds),
705
714
  mapClone2(changedRowIds),
706
715
  mapClone(changedCellIds, mapClone2),
707
716
  mapClone(changedCells, mapClone2),
708
717
  ]
709
- : [changedTableIds, changedRowIds, changedCellIds, changedCells];
718
+ : [
719
+ changedTableIds,
720
+ changedTableCellIds,
721
+ changedRowIds,
722
+ changedCellIds,
723
+ changedCells,
724
+ ];
710
725
  if (!emptyIdListeners) {
711
- collForEach(changes[2], (rowCellIds, tableId) =>
726
+ collForEach(changes[1], (changedIds, tableId) =>
727
+ callIdsListenersIfChanged(
728
+ tableCellIdsListeners[mutator],
729
+ changedIds,
730
+ [tableId],
731
+ ),
732
+ );
733
+ collForEach(changes[3], (rowCellIds, tableId) =>
712
734
  collForEach(rowCellIds, (changedIds, rowId) =>
713
735
  callIdsListenersIfChanged(cellIdsListeners[mutator], changedIds, [
714
736
  tableId,
@@ -717,7 +739,7 @@ const createStore = () => {
717
739
  ),
718
740
  );
719
741
  const calledSortableTableIds = setNew();
720
- collForEach(changes[1], (changedIds, tableId) => {
742
+ collForEach(changes[2], (changedIds, tableId) => {
721
743
  if (
722
744
  callIdsListenersIfChanged(rowIdsListeners[mutator], changedIds, [
723
745
  tableId,
@@ -729,7 +751,7 @@ const createStore = () => {
729
751
  }
730
752
  });
731
753
  if (!emptySortedRowIdListeners) {
732
- collForEach(changes[3], (rows, tableId) => {
754
+ collForEach(changes[4], (rows, tableId) => {
733
755
  if (!collHas(calledSortableTableIds, tableId)) {
734
756
  const sortableCellIds = setNew();
735
757
  collForEach(rows, (cells) =>
@@ -752,7 +774,7 @@ const createStore = () => {
752
774
  }
753
775
  if (!emptyOtherListeners) {
754
776
  let tablesChanged;
755
- collForEach(changes[3], (rows, tableId) => {
777
+ collForEach(changes[4], (rows, tableId) => {
756
778
  let tableChanged;
757
779
  collForEach(rows, (cells, rowId) => {
758
780
  let rowChanged;
@@ -827,6 +849,8 @@ const createStore = () => {
827
849
  const getTableIds = () => mapKeys(tablesMap);
828
850
  const getTable = (tableId) =>
829
851
  mapToObj(mapGet(tablesMap, id(tableId)), mapToObj);
852
+ const getTableCellIds = (tableId) =>
853
+ mapKeys(mapGet(tableCellIds, id(tableId)));
830
854
  const getRowIds = (tableId) => mapKeys(mapGet(tablesMap, id(tableId)));
831
855
  const getSortedRowIds = (tableId, cellId, descending, offset = 0, limit) =>
832
856
  arrayMap(
@@ -855,6 +879,8 @@ const createStore = () => {
855
879
  const getValue = (valueId) => mapGet(valuesMap, id(valueId));
856
880
  const hasTables = () => !collIsEmpty(tablesMap);
857
881
  const hasTable = (tableId) => collHas(tablesMap, id(tableId));
882
+ const hasTableCell = (tableId, cellId) =>
883
+ collHas(mapGet(tableCellIds, id(tableId)), id(cellId));
858
884
  const hasRow = (tableId, rowId) =>
859
885
  collHas(mapGet(tablesMap, id(tableId)), id(rowId));
860
886
  const hasCell = (tableId, rowId, cellId) =>
@@ -886,7 +912,7 @@ const createStore = () => {
886
912
  tableId,
887
913
  rowId,
888
914
  );
889
- const addRow = (tableId, row) =>
915
+ const addRow = (tableId, row, reuseRowIds = true) =>
890
916
  transaction(() => {
891
917
  let rowId = void 0;
892
918
  if (validateRow(tableId, rowId, row)) {
@@ -894,7 +920,7 @@ const createStore = () => {
894
920
  setValidRow(
895
921
  tableId,
896
922
  getOrCreateTable(tableId),
897
- (rowId = getNewRowId(tableId)),
923
+ (rowId = getNewRowId(tableId, reuseRowIds ? 1 : 0)),
898
924
  row,
899
925
  );
900
926
  }
@@ -1071,16 +1097,20 @@ const createStore = () => {
1071
1097
  delValuesSchema();
1072
1098
  });
1073
1099
  const transaction = (actions, doRollback) => {
1074
- if (transactions == -1) {
1075
- return;
1100
+ if (transactions != -1) {
1101
+ startTransaction();
1102
+ const result = actions();
1103
+ finishTransaction(doRollback);
1104
+ return result;
1076
1105
  }
1077
- startTransaction();
1078
- const result = actions();
1079
- finishTransaction(doRollback);
1080
- return result;
1081
1106
  };
1082
1107
  const startTransaction = () => {
1083
- transactions++;
1108
+ if (transactions != -1) {
1109
+ transactions++;
1110
+ }
1111
+ if (transactions == 1) {
1112
+ callListeners(startTransactionListeners, void 0, false, false);
1113
+ }
1084
1114
  return store;
1085
1115
  };
1086
1116
  const finishTransaction = (doRollback) => {
@@ -1098,7 +1128,6 @@ const createStore = () => {
1098
1128
  if (valuesTouched) {
1099
1129
  callKeyedValuesListenersForChanges(1);
1100
1130
  }
1101
- transactions = -1;
1102
1131
  if (
1103
1132
  doRollback?.(
1104
1133
  mapToObj(
@@ -1125,7 +1154,6 @@ const createStore = () => {
1125
1154
  mapToObj(invalidValues),
1126
1155
  )
1127
1156
  ) {
1128
- transactions = 1;
1129
1157
  collForEach(changedCells, (table, tableId) =>
1130
1158
  collForEach(table, (row, rowId) =>
1131
1159
  collForEach(row, ([oldCell], cellId) =>
@@ -1136,7 +1164,6 @@ const createStore = () => {
1136
1164
  collForEach(changedValues, ([oldValue], valueId) =>
1137
1165
  setOrDelValue(store, valueId, oldValue),
1138
1166
  );
1139
- transactions = -1;
1140
1167
  cellsTouched = valuesTouched = false;
1141
1168
  }
1142
1169
  callListeners(
@@ -1145,6 +1172,7 @@ const createStore = () => {
1145
1172
  cellsTouched,
1146
1173
  valuesTouched,
1147
1174
  );
1175
+ transactions = -1;
1148
1176
  callInvalidCellListeners(0);
1149
1177
  if (cellsTouched) {
1150
1178
  callTabularListenersForChanges(0);
@@ -1163,6 +1191,7 @@ const createStore = () => {
1163
1191
  arrayForEach(
1164
1192
  [
1165
1193
  changedTableIds,
1194
+ changedTableCellIds,
1166
1195
  changedRowIds,
1167
1196
  changedCellIds,
1168
1197
  changedCells,
@@ -1187,6 +1216,8 @@ const createStore = () => {
1187
1216
  ),
1188
1217
  ),
1189
1218
  );
1219
+ const forEachTableCell = (tableId, tableCellCallback) =>
1220
+ mapForEach(mapGet(tableCellIds, id(tableId)), tableCellCallback);
1190
1221
  const forEachRow = (tableId, rowCallback) =>
1191
1222
  collForEach(mapGet(tablesMap, id(tableId)), (rowMap, rowId) =>
1192
1223
  rowCallback(rowId, (cellCallback) => mapForEach(rowMap, cellCallback)),
@@ -1237,6 +1268,8 @@ const createStore = () => {
1237
1268
  [getTableIds],
1238
1269
  );
1239
1270
  };
1271
+ const addStartTransactionListener = (listener) =>
1272
+ addListener(listener, startTransactionListeners);
1240
1273
  const addWillFinishTransactionListener = (listener) =>
1241
1274
  addListener(listener, finishTransactionListeners[0]);
1242
1275
  const addDidFinishTransactionListener = (listener) =>
@@ -1252,6 +1285,7 @@ const createStore = () => {
1252
1285
  const getListenerStats = () => ({
1253
1286
  tables: pairCollSize2(tablesListeners),
1254
1287
  tableIds: pairCollSize2(tableIdsListeners),
1288
+ tableCellIds: pairCollSize2(tableCellIdsListeners),
1255
1289
  table: pairCollSize2(tableListeners),
1256
1290
  rowIds: pairCollSize2(rowIdsListeners),
1257
1291
  sortedRowIds: pairCollSize2(sortedRowIdsListeners),
@@ -1263,12 +1297,15 @@ const createStore = () => {
1263
1297
  valueIds: pairCollSize2(valueIdsListeners),
1264
1298
  value: pairCollSize2(valueListeners),
1265
1299
  invalidValue: pairCollSize2(invalidValueListeners),
1266
- transaction: pairCollSize2(finishTransactionListeners),
1300
+ transaction:
1301
+ collSize2(startTransactionListeners) +
1302
+ pairCollSize2(finishTransactionListeners),
1267
1303
  });
1268
1304
  const store = {
1269
1305
  getTables,
1270
1306
  getTableIds,
1271
1307
  getTable,
1308
+ getTableCellIds,
1272
1309
  getRowIds,
1273
1310
  getSortedRowIds,
1274
1311
  getRow,
@@ -1279,6 +1316,7 @@ const createStore = () => {
1279
1316
  getValue,
1280
1317
  hasTables,
1281
1318
  hasTable,
1319
+ hasTableCell,
1282
1320
  hasRow,
1283
1321
  hasCell,
1284
1322
  hasValues,
@@ -1317,10 +1355,12 @@ const createStore = () => {
1317
1355
  startTransaction,
1318
1356
  finishTransaction,
1319
1357
  forEachTable,
1358
+ forEachTableCell,
1320
1359
  forEachRow,
1321
1360
  forEachCell,
1322
1361
  forEachValue,
1323
1362
  addSortedRowIdsListener,
1363
+ addStartTransactionListener,
1324
1364
  addWillFinishTransactionListener,
1325
1365
  addDidFinishTransactionListener,
1326
1366
  callListener,
@@ -1333,6 +1373,7 @@ const createStore = () => {
1333
1373
  [TABLES]: [0, tablesListeners],
1334
1374
  [TABLE_IDS]: [0, tableIdsListeners],
1335
1375
  [TABLE]: [1, tableListeners, [getTableIds]],
1376
+ [TABLE + CELL_IDS]: [1, tableCellIdsListeners, [getTableIds]],
1336
1377
  [ROW_IDS]: [1, rowIdsListeners, [getTableIds]],
1337
1378
  [ROW]: [2, rowListeners, [getTableIds, getRowIds]],
1338
1379
  [CELL_IDS]: [2, cellIdsListeners, [getTableIds, getRowIds]],