tinybase 7.3.5 → 8.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/@types/index.d.ts +1 -0
  2. package/@types/middleware/index.d.ts +1064 -0
  3. package/@types/middleware/with-schemas/index.d.ts +1355 -0
  4. package/@types/omni/index.d.ts +1 -0
  5. package/@types/omni/with-schemas/index.d.ts +1 -0
  6. package/@types/store/index.d.ts +0 -1
  7. package/@types/with-schemas/index.d.ts +1 -0
  8. package/agents.md +33 -11
  9. package/checkpoints/index.js +8 -9
  10. package/checkpoints/with-schemas/index.js +8 -9
  11. package/index.js +484 -153
  12. package/mergeable-store/index.js +371 -135
  13. package/mergeable-store/with-schemas/index.js +371 -135
  14. package/middleware/index.js +130 -0
  15. package/middleware/with-schemas/index.js +130 -0
  16. package/min/checkpoints/index.js +1 -1
  17. package/min/checkpoints/index.js.gz +0 -0
  18. package/min/checkpoints/with-schemas/index.js +1 -1
  19. package/min/checkpoints/with-schemas/index.js.gz +0 -0
  20. package/min/index.js +1 -1
  21. package/min/index.js.gz +0 -0
  22. package/min/mergeable-store/index.js +1 -1
  23. package/min/mergeable-store/index.js.gz +0 -0
  24. package/min/mergeable-store/with-schemas/index.js +1 -1
  25. package/min/mergeable-store/with-schemas/index.js.gz +0 -0
  26. package/min/middleware/index.js +1 -0
  27. package/min/middleware/index.js.gz +0 -0
  28. package/min/middleware/with-schemas/index.js +1 -0
  29. package/min/middleware/with-schemas/index.js.gz +0 -0
  30. package/min/omni/index.js +1 -1
  31. package/min/omni/index.js.gz +0 -0
  32. package/min/omni/with-schemas/index.js +1 -1
  33. package/min/omni/with-schemas/index.js.gz +0 -0
  34. package/min/queries/index.js +1 -1
  35. package/min/queries/index.js.gz +0 -0
  36. package/min/queries/with-schemas/index.js +1 -1
  37. package/min/queries/with-schemas/index.js.gz +0 -0
  38. package/min/store/index.js +1 -1
  39. package/min/store/index.js.gz +0 -0
  40. package/min/store/with-schemas/index.js +1 -1
  41. package/min/store/with-schemas/index.js.gz +0 -0
  42. package/min/ui-react-inspector/index.js +1 -1
  43. package/min/ui-react-inspector/index.js.gz +0 -0
  44. package/min/ui-react-inspector/with-schemas/index.js +1 -1
  45. package/min/ui-react-inspector/with-schemas/index.js.gz +0 -0
  46. package/min/with-schemas/index.js +1 -1
  47. package/min/with-schemas/index.js.gz +0 -0
  48. package/omni/index.js +492 -161
  49. package/omni/with-schemas/index.js +492 -161
  50. package/package.json +37 -1
  51. package/queries/index.js +1 -6
  52. package/queries/with-schemas/index.js +1 -6
  53. package/readme.md +14 -14
  54. package/releases.md +41 -41
  55. package/store/index.js +370 -134
  56. package/store/with-schemas/index.js +370 -134
  57. package/ui-react-inspector/index.js +349 -134
  58. package/ui-react-inspector/with-schemas/index.js +349 -134
  59. package/with-schemas/index.js +484 -153
package/index.js CHANGED
@@ -64,6 +64,7 @@ const size = (arrayOrString) => arrayOrString.length;
64
64
  const test = (regex, subject) => regex.test(subject);
65
65
  const getUndefined = () => void 0;
66
66
  const noop = () => {};
67
+ const structuredClone = GLOBAL.structuredClone;
67
68
  const tryCatch = async (action, then1, then2) => {
68
69
  try {
69
70
  return await action();
@@ -99,25 +100,6 @@ const arrayPop = (array) => array.pop();
99
100
  const arrayUnshift = (array, ...values) => array.unshift(...values);
100
101
  const arrayShift = (array) => array.shift();
101
102
 
102
- const getCellOrValueType = (cellOrValue) => {
103
- if (isNull(cellOrValue)) {
104
- return NULL;
105
- }
106
- const type = getTypeOf(cellOrValue);
107
- return isTypeStringOrBoolean(type) ||
108
- (type == NUMBER && isFiniteNumber(cellOrValue))
109
- ? type
110
- : void 0;
111
- };
112
- const isCellOrValueOrUndefined = (cellOrValue) =>
113
- isUndefined(cellOrValue) || !isUndefined(getCellOrValueType(cellOrValue));
114
- const setOrDelCell = (store, tableId, rowId, cellId, cell) =>
115
- isUndefined(cell)
116
- ? store.delCell(tableId, rowId, cellId, true)
117
- : store.setCell(tableId, rowId, cellId, cell);
118
- const setOrDelValue = (store, valueId, value) =>
119
- isUndefined(value) ? store.delValue(valueId) : store.setValue(valueId, value);
120
-
121
103
  const collSizeN = (collSizer) => (coll) =>
122
104
  arrayReduce(collValues(coll), (total, coll2) => total + collSizer(coll2), 0);
123
105
  const collSize = (coll) => coll?.size ?? 0;
@@ -577,12 +559,18 @@ const createCheckpoints = getCreateFunction(
577
559
  collForEach(cellsDelta2, (table, tableId) =>
578
560
  collForEach(table, (row, rowId) =>
579
561
  collForEach(row, (oldNew, cellId) =>
580
- setOrDelCell(store, tableId, rowId, cellId, oldNew[oldOrNew]),
562
+ store.setOrDelCell(
563
+ tableId,
564
+ rowId,
565
+ cellId,
566
+ oldNew[oldOrNew],
567
+ true,
568
+ ),
581
569
  ),
582
570
  ),
583
571
  );
584
572
  collForEach(valuesDelta2, (oldNew, valueId) =>
585
- setOrDelValue(store, valueId, oldNew[oldOrNew]),
573
+ store.setOrDelValue(valueId, oldNew[oldOrNew], true),
586
574
  );
587
575
  });
588
576
  listening = 1;
@@ -1168,6 +1156,19 @@ const createIndexes = getCreateFunction((store) => {
1168
1156
  return objFreeze(indexes);
1169
1157
  });
1170
1158
 
1159
+ const getCellOrValueType = (cellOrValue) => {
1160
+ if (isNull(cellOrValue)) {
1161
+ return NULL;
1162
+ }
1163
+ const type = getTypeOf(cellOrValue);
1164
+ return isTypeStringOrBoolean(type) ||
1165
+ (type == NUMBER && isFiniteNumber(cellOrValue))
1166
+ ? type
1167
+ : void 0;
1168
+ };
1169
+ const isCellOrValueOrUndefined = (cellOrValue) =>
1170
+ isUndefined(cellOrValue) || !isUndefined(getCellOrValueType(cellOrValue));
1171
+
1171
1172
  const stampClone = ([value, hlc]) => stampNew(value, hlc);
1172
1173
  const stampCloneWithHash = ([value, hlc, hash]) => [value, hlc, hash];
1173
1174
  const stampNew = (value, hlc) => (hlc ? [value, hlc] : [value]);
@@ -1212,12 +1213,15 @@ const idsChanged = (changedIds, id2, addedOrRemoved) =>
1212
1213
  id2,
1213
1214
  mapGet(changedIds, id2) == -addedOrRemoved ? void 0 : addedOrRemoved,
1214
1215
  );
1216
+ const contentOrChangesIsEqual = ([tables1, values1], [tables2, values2]) =>
1217
+ objIsEqual(tables1, tables2) && objIsEqual(values1, values2);
1215
1218
  const createStore = () => {
1216
1219
  let hasTablesSchema;
1217
1220
  let hasValuesSchema;
1218
1221
  let hadTables = false;
1219
1222
  let hadValues = false;
1220
1223
  let transactions = 0;
1224
+ let middleware = [];
1221
1225
  let internalListeners = [];
1222
1226
  let mutating = 0;
1223
1227
  const changedTableIds = mapNew();
@@ -1265,6 +1269,19 @@ const createStore = () => {
1265
1269
  const finishTransactionListeners = pairNewMap();
1266
1270
  const [addListener, callListeners, delListenerImpl, callListenerImpl] =
1267
1271
  getListenerFunctions(() => store);
1272
+ const whileMutating = (action) => {
1273
+ const wasMutating = mutating;
1274
+ mutating = 1;
1275
+ const result = action();
1276
+ mutating = wasMutating;
1277
+ return result;
1278
+ };
1279
+ const ifTransformed = (snapshot, getResult, then, isEqual = Object.is) =>
1280
+ ifNotUndefined(getResult(), (result) =>
1281
+ snapshot === result || isEqual(snapshot, result)
1282
+ ? then(result)
1283
+ : whileMutating(() => then(result)),
1284
+ );
1268
1285
  const validateTablesSchema = (tableSchema) =>
1269
1286
  objValidate(tableSchema, (tableSchema2) =>
1270
1287
  objValidate(tableSchema2, validateCellOrValueSchema),
@@ -1452,82 +1469,194 @@ const createStore = () => {
1452
1469
  );
1453
1470
  const setOrDelTables = (tables) =>
1454
1471
  objIsEmpty(tables) ? delTables() : setTables(tables);
1455
- const setValidContent = ([tables, values]) => {
1456
- (objIsEmpty(tables) ? delTables : setTables)(tables);
1457
- (objIsEmpty(values) ? delValues : setValues)(values);
1458
- };
1459
- const setValidTables = (tables) =>
1460
- mapMatch(
1461
- tablesMap,
1472
+ const setOrDelCell = (tableId, rowId, cellId, cell, skipMiddleware) =>
1473
+ isUndefined(cell)
1474
+ ? delCell(tableId, rowId, cellId, true, skipMiddleware)
1475
+ : setCell(tableId, rowId, cellId, cell, skipMiddleware);
1476
+ const setOrDelValues = (values) =>
1477
+ objIsEmpty(values) ? delValues() : setValues(values);
1478
+ const setOrDelValue = (valueId, value, skipMiddleware) =>
1479
+ isUndefined(value)
1480
+ ? delValue(valueId, skipMiddleware)
1481
+ : setValue(valueId, value, skipMiddleware);
1482
+ const setValidContent = (content) =>
1483
+ ifTransformed(
1484
+ content,
1485
+ () =>
1486
+ ifNotUndefined(
1487
+ middleware[0],
1488
+ (willSetContent) =>
1489
+ whileMutating(() => willSetContent(structuredClone(content))),
1490
+ () => content,
1491
+ ),
1492
+ ([tables, values]) => {
1493
+ (objIsEmpty(tables) ? delTables : setTables)(tables);
1494
+ (objIsEmpty(values) ? delValues : setValues)(values);
1495
+ },
1496
+ contentOrChangesIsEqual,
1497
+ );
1498
+ const setValidTables = (tables, forceDel) =>
1499
+ ifTransformed(
1462
1500
  tables,
1463
- (_tables, tableId, table) => setValidTable(tableId, table),
1464
- (_tables, tableId) => delValidTable(tableId),
1501
+ () =>
1502
+ forceDel
1503
+ ? tables
1504
+ : ifNotUndefined(
1505
+ middleware[1],
1506
+ (willSetTables) =>
1507
+ whileMutating(() => willSetTables(structuredClone(tables))),
1508
+ () => tables,
1509
+ ),
1510
+ (validTables) =>
1511
+ mapMatch(
1512
+ tablesMap,
1513
+ validTables,
1514
+ (_tables, tableId, table) => setValidTable(tableId, table),
1515
+ (_tables, tableId) => delValidTable(tableId),
1516
+ ),
1517
+ objIsEqual,
1465
1518
  );
1466
- const setValidTable = (tableId, table) =>
1467
- mapMatch(
1468
- mapEnsure(tablesMap, tableId, () => {
1469
- tableIdsChanged(tableId, 1);
1470
- mapSet(tablePoolFunctions, tableId, getPoolFunctions());
1471
- mapSet(tableCellIds, tableId, mapNew());
1472
- return mapNew();
1473
- }),
1519
+ const setValidTable = (tableId, table, forceDel) =>
1520
+ ifTransformed(
1474
1521
  table,
1475
- (tableMap, rowId, row) => setValidRow(tableId, tableMap, rowId, row),
1476
- (tableMap, rowId) => delValidRow(tableId, tableMap, rowId),
1522
+ () =>
1523
+ forceDel
1524
+ ? table
1525
+ : ifNotUndefined(
1526
+ middleware[2],
1527
+ (willSetTable) =>
1528
+ whileMutating(() =>
1529
+ willSetTable(tableId, structuredClone(table)),
1530
+ ),
1531
+ () => table,
1532
+ ),
1533
+ (validTable) =>
1534
+ mapMatch(
1535
+ mapEnsure(tablesMap, tableId, () => {
1536
+ tableIdsChanged(tableId, 1);
1537
+ mapSet(tablePoolFunctions, tableId, getPoolFunctions());
1538
+ mapSet(tableCellIds, tableId, mapNew());
1539
+ return mapNew();
1540
+ }),
1541
+ validTable,
1542
+ (tableMap, rowId, row) => setValidRow(tableId, tableMap, rowId, row),
1543
+ (tableMap, rowId) => delValidRow(tableId, tableMap, rowId),
1544
+ ),
1545
+ objIsEqual,
1477
1546
  );
1478
1547
  const setValidRow = (tableId, tableMap, rowId, row, forceDel) =>
1479
- mapMatch(
1480
- mapEnsure(tableMap, rowId, () => {
1481
- rowIdsChanged(tableId, rowId, 1);
1482
- return mapNew();
1483
- }),
1548
+ ifTransformed(
1484
1549
  row,
1485
- (rowMap, cellId, cell) =>
1486
- setValidCell(tableId, rowId, rowMap, cellId, cell),
1487
- (rowMap, cellId) =>
1488
- delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel),
1489
- );
1490
- const setValidCell = (tableId, rowId, rowMap, cellId, cell) => {
1491
- if (!collHas(rowMap, cellId)) {
1492
- cellIdsChanged(tableId, rowId, cellId, 1);
1493
- }
1494
- const oldCell = mapGet(rowMap, cellId);
1495
- if (cell !== oldCell) {
1496
- cellChanged(tableId, rowId, cellId, oldCell, cell);
1497
- mapSet(rowMap, cellId, cell);
1498
- }
1499
- };
1500
- const setCellIntoDefaultRow = (tableId, tableMap, rowId, cellId, validCell) =>
1550
+ () =>
1551
+ forceDel
1552
+ ? row
1553
+ : ifNotUndefined(
1554
+ middleware[3],
1555
+ (willSetRow) =>
1556
+ whileMutating(() =>
1557
+ willSetRow(tableId, rowId, structuredClone(row)),
1558
+ ),
1559
+ () => row,
1560
+ ),
1561
+ (validRow) =>
1562
+ mapMatch(
1563
+ mapEnsure(tableMap, rowId, () => {
1564
+ rowIdsChanged(tableId, rowId, 1);
1565
+ return mapNew();
1566
+ }),
1567
+ validRow,
1568
+ (rowMap, cellId, cell) =>
1569
+ setValidCell(tableId, rowId, rowMap, cellId, cell),
1570
+ (rowMap, cellId) =>
1571
+ delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel),
1572
+ ),
1573
+ objIsEqual,
1574
+ );
1575
+ const setValidCell = (tableId, rowId, rowMap, cellId, cell, skipMiddleware) =>
1576
+ ifTransformed(
1577
+ cell,
1578
+ () =>
1579
+ ifNotUndefined(
1580
+ skipMiddleware ? void 0 : middleware[4],
1581
+ (willSetCell) =>
1582
+ whileMutating(() => willSetCell(tableId, rowId, cellId, cell)),
1583
+ () => cell,
1584
+ ),
1585
+ (cell2) => {
1586
+ if (!collHas(rowMap, cellId)) {
1587
+ cellIdsChanged(tableId, rowId, cellId, 1);
1588
+ }
1589
+ const oldCell = mapGet(rowMap, cellId);
1590
+ if (cell2 !== oldCell) {
1591
+ cellChanged(tableId, rowId, cellId, oldCell, cell2);
1592
+ mapSet(rowMap, cellId, cell2);
1593
+ }
1594
+ },
1595
+ );
1596
+ const setCellIntoNewRow = (
1597
+ tableId,
1598
+ tableMap,
1599
+ rowId,
1600
+ cellId,
1601
+ validCell,
1602
+ skipMiddleware,
1603
+ ) =>
1501
1604
  ifNotUndefined(
1502
1605
  mapGet(tableMap, rowId),
1503
- (rowMap) => setValidCell(tableId, rowId, rowMap, cellId, validCell),
1504
- () =>
1505
- setValidRow(
1506
- tableId,
1507
- tableMap,
1508
- rowId,
1606
+ (rowMap) =>
1607
+ setValidCell(tableId, rowId, rowMap, cellId, validCell, skipMiddleware),
1608
+ () => {
1609
+ const rowMap = mapNew();
1610
+ mapSet(tableMap, rowId, rowMap);
1611
+ rowIdsChanged(tableId, rowId, 1);
1612
+ objMap(
1509
1613
  addDefaultsToRow({[cellId]: validCell}, tableId, rowId),
1510
- ),
1614
+ (cell, cellId2) =>
1615
+ setValidCell(tableId, rowId, rowMap, cellId2, cell, skipMiddleware),
1616
+ );
1617
+ },
1511
1618
  );
1512
- const setOrDelValues = (values) =>
1513
- objIsEmpty(values) ? delValues() : setValues(values);
1514
- const setValidValues = (values) =>
1515
- mapMatch(
1516
- valuesMap,
1619
+ const setValidValues = (values, forceDel) =>
1620
+ ifTransformed(
1517
1621
  values,
1518
- (_valuesMap, valueId, value) => setValidValue(valueId, value),
1519
- (_valuesMap, valueId) => delValidValue(valueId),
1622
+ () =>
1623
+ forceDel
1624
+ ? values
1625
+ : ifNotUndefined(
1626
+ middleware[5],
1627
+ (willSetValues) =>
1628
+ whileMutating(() => willSetValues(structuredClone(values))),
1629
+ () => values,
1630
+ ),
1631
+ (validValues) =>
1632
+ mapMatch(
1633
+ valuesMap,
1634
+ validValues,
1635
+ (_valuesMap, valueId, value) => setValidValue(valueId, value),
1636
+ (_valuesMap, valueId) => delValidValue(valueId),
1637
+ ),
1638
+ objIsEqual,
1639
+ );
1640
+ const setValidValue = (valueId, value, skipMiddleware) =>
1641
+ ifTransformed(
1642
+ value,
1643
+ () =>
1644
+ ifNotUndefined(
1645
+ skipMiddleware ? void 0 : middleware[6],
1646
+ (willSetValue) => whileMutating(() => willSetValue(valueId, value)),
1647
+ () => value,
1648
+ ),
1649
+ (value2) => {
1650
+ if (!collHas(valuesMap, valueId)) {
1651
+ valueIdsChanged(valueId, 1);
1652
+ }
1653
+ const oldValue = mapGet(valuesMap, valueId);
1654
+ if (value2 !== oldValue) {
1655
+ valueChanged(valueId, oldValue, value2);
1656
+ mapSet(valuesMap, valueId, value2);
1657
+ }
1658
+ },
1520
1659
  );
1521
- const setValidValue = (valueId, value) => {
1522
- if (!collHas(valuesMap, valueId)) {
1523
- valueIdsChanged(valueId, 1);
1524
- }
1525
- const oldValue = mapGet(valuesMap, valueId);
1526
- if (value !== oldValue) {
1527
- valueChanged(valueId, oldValue, value);
1528
- mapSet(valuesMap, valueId, value);
1529
- }
1530
- };
1531
1660
  const getNewRowId = (tableId, reuse) => {
1532
1661
  const [getId] = mapGet(tablePoolFunctions, tableId);
1533
1662
  let rowId;
@@ -1537,14 +1666,34 @@ const createStore = () => {
1537
1666
  return rowId;
1538
1667
  };
1539
1668
  const getOrCreateTable = (tableId) =>
1540
- mapGet(tablesMap, tableId) ?? setValidTable(tableId, {});
1541
- const delValidTable = (tableId) => setValidTable(tableId, {});
1669
+ mapEnsure(tablesMap, tableId, () => {
1670
+ tableIdsChanged(tableId, 1);
1671
+ mapSet(tablePoolFunctions, tableId, getPoolFunctions());
1672
+ mapSet(tableCellIds, tableId, mapNew());
1673
+ return mapNew();
1674
+ });
1675
+ const delValidTable = (tableId) => {
1676
+ if (whileMutating(() => middleware[8]?.(tableId)) ?? true) {
1677
+ return setValidTable(tableId, {}, true);
1678
+ }
1679
+ return mapGet(tablesMap, tableId);
1680
+ };
1542
1681
  const delValidRow = (tableId, tableMap, rowId) => {
1543
- const [, releaseId] = mapGet(tablePoolFunctions, tableId);
1544
- releaseId(rowId);
1545
- setValidRow(tableId, tableMap, rowId, {}, true);
1682
+ if (whileMutating(() => middleware[9]?.(tableId, rowId)) ?? true) {
1683
+ const [, releaseId] = mapGet(tablePoolFunctions, tableId);
1684
+ releaseId(rowId);
1685
+ setValidRow(tableId, tableMap, rowId, {}, true);
1686
+ }
1546
1687
  };
1547
- const delValidCell = (tableId, table, rowId, row, cellId, forceDel) => {
1688
+ const delValidCell = (
1689
+ tableId,
1690
+ table,
1691
+ rowId,
1692
+ row,
1693
+ cellId,
1694
+ forceDel,
1695
+ skipMiddleware,
1696
+ ) => {
1548
1697
  const defaultCell = mapGet(
1549
1698
  mapGet(tablesSchemaRowCache, tableId)?.[0],
1550
1699
  cellId,
@@ -1552,34 +1701,44 @@ const createStore = () => {
1552
1701
  if (!isUndefined(defaultCell) && !forceDel) {
1553
1702
  return setValidCell(tableId, rowId, row, cellId, defaultCell);
1554
1703
  }
1555
- const delCell2 = (cellId2) => {
1556
- cellChanged(tableId, rowId, cellId2, mapGet(row, cellId2));
1557
- cellIdsChanged(tableId, rowId, cellId2, -1);
1558
- mapSet(row, cellId2);
1559
- };
1560
- if (isUndefined(defaultCell)) {
1561
- delCell2(cellId);
1562
- } else {
1563
- mapForEach(row, delCell2);
1564
- }
1565
- if (collIsEmpty(row)) {
1566
- rowIdsChanged(tableId, rowId, -1);
1567
- if (collIsEmpty(mapSet(table, rowId))) {
1568
- tableIdsChanged(tableId, -1);
1569
- mapSet(tablesMap, tableId);
1570
- mapSet(tablePoolFunctions, tableId);
1571
- mapSet(tableCellIds, tableId);
1704
+ if (
1705
+ skipMiddleware ||
1706
+ (whileMutating(() => middleware[10]?.(tableId, rowId, cellId)) ?? true)
1707
+ ) {
1708
+ const delCell2 = (cellId2) => {
1709
+ cellChanged(tableId, rowId, cellId2, mapGet(row, cellId2));
1710
+ cellIdsChanged(tableId, rowId, cellId2, -1);
1711
+ mapSet(row, cellId2);
1712
+ };
1713
+ if (isUndefined(defaultCell)) {
1714
+ delCell2(cellId);
1715
+ } else {
1716
+ mapForEach(row, delCell2);
1717
+ }
1718
+ if (collIsEmpty(row)) {
1719
+ rowIdsChanged(tableId, rowId, -1);
1720
+ if (collIsEmpty(mapSet(table, rowId))) {
1721
+ tableIdsChanged(tableId, -1);
1722
+ mapSet(tablesMap, tableId);
1723
+ mapSet(tablePoolFunctions, tableId);
1724
+ mapSet(tableCellIds, tableId);
1725
+ }
1572
1726
  }
1573
1727
  }
1574
1728
  };
1575
- const delValidValue = (valueId) => {
1729
+ const delValidValue = (valueId, skipMiddleware) => {
1576
1730
  const defaultValue = mapGet(valuesDefaulted, valueId);
1577
1731
  if (!isUndefined(defaultValue)) {
1578
1732
  return setValidValue(valueId, defaultValue);
1579
1733
  }
1580
- valueChanged(valueId, mapGet(valuesMap, valueId));
1581
- valueIdsChanged(valueId, -1);
1582
- mapSet(valuesMap, valueId);
1734
+ if (
1735
+ skipMiddleware ||
1736
+ (whileMutating(() => middleware[12]?.(valueId)) ?? true)
1737
+ ) {
1738
+ valueChanged(valueId, mapGet(valuesMap, valueId));
1739
+ valueIdsChanged(valueId, -1);
1740
+ mapSet(valuesMap, valueId);
1741
+ }
1583
1742
  };
1584
1743
  const tableIdsChanged = (tableId, addedOrRemoved) =>
1585
1744
  idsChanged(changedTableIds, tableId, addedOrRemoved);
@@ -2038,14 +2197,14 @@ const createStore = () => {
2038
2197
  if (validateRow(tableId2, rowId2, partialRow, 1)) {
2039
2198
  const table = getOrCreateTable(tableId2);
2040
2199
  objMap(partialRow, (cell, cellId) =>
2041
- setCellIntoDefaultRow(tableId2, table, rowId2, cellId, cell),
2200
+ setCellIntoNewRow(tableId2, table, rowId2, cellId, cell),
2042
2201
  );
2043
2202
  }
2044
2203
  },
2045
2204
  tableId,
2046
2205
  rowId,
2047
2206
  );
2048
- const setCell = (tableId, rowId, cellId, cell) =>
2207
+ const setCell = (tableId, rowId, cellId, cell, skipMiddleware) =>
2049
2208
  fluentTransaction(
2050
2209
  (tableId2, rowId2, cellId2) =>
2051
2210
  ifNotUndefined(
@@ -2056,12 +2215,13 @@ const createStore = () => {
2056
2215
  isFunction(cell) ? cell(getCell(tableId2, rowId2, cellId2)) : cell,
2057
2216
  ),
2058
2217
  (validCell) =>
2059
- setCellIntoDefaultRow(
2218
+ setCellIntoNewRow(
2060
2219
  tableId2,
2061
2220
  getOrCreateTable(tableId2),
2062
2221
  rowId2,
2063
2222
  cellId2,
2064
2223
  validCell,
2224
+ skipMiddleware,
2065
2225
  ),
2066
2226
  ),
2067
2227
  tableId,
@@ -2080,7 +2240,7 @@ const createStore = () => {
2080
2240
  )
2081
2241
  : 0,
2082
2242
  );
2083
- const setValue = (valueId, value) =>
2243
+ const setValue = (valueId, value, skipMiddleware) =>
2084
2244
  fluentTransaction(
2085
2245
  (valueId2) =>
2086
2246
  ifNotUndefined(
@@ -2088,27 +2248,40 @@ const createStore = () => {
2088
2248
  valueId2,
2089
2249
  isFunction(value) ? value(getValue(valueId2)) : value,
2090
2250
  ),
2091
- (validValue) => setValidValue(valueId2, validValue),
2251
+ (validValue) => setValidValue(valueId2, validValue, skipMiddleware),
2092
2252
  ),
2093
2253
  valueId,
2094
2254
  );
2095
2255
  const applyChanges = (changes) =>
2096
- fluentTransaction(() => {
2097
- objMap(changes[0], (table, tableId) =>
2098
- isUndefined(table)
2099
- ? delTable(tableId)
2100
- : objMap(table, (row, rowId) =>
2101
- isUndefined(row)
2102
- ? delRow(tableId, rowId)
2103
- : objMap(row, (cell, cellId) =>
2104
- setOrDelCell(store, tableId, rowId, cellId, cell),
2105
- ),
2106
- ),
2107
- );
2108
- objMap(changes[1], (value, valueId) =>
2109
- setOrDelValue(store, valueId, value),
2110
- );
2111
- });
2256
+ fluentTransaction(() =>
2257
+ ifTransformed(
2258
+ changes,
2259
+ () =>
2260
+ ifNotUndefined(
2261
+ middleware[13],
2262
+ (willApplyChanges) =>
2263
+ whileMutating(() => willApplyChanges(structuredClone(changes))),
2264
+ () => changes,
2265
+ ),
2266
+ (changes2) => {
2267
+ objMap(changes2[0], (table, tableId) =>
2268
+ isUndefined(table)
2269
+ ? delTable(tableId)
2270
+ : objMap(table, (row, rowId) =>
2271
+ isUndefined(row)
2272
+ ? delRow(tableId, rowId)
2273
+ : objMap(row, (cell, cellId) =>
2274
+ setOrDelCell(tableId, rowId, cellId, cell),
2275
+ ),
2276
+ ),
2277
+ );
2278
+ objMap(changes2[1], (value, valueId) =>
2279
+ setOrDelValue(valueId, value),
2280
+ );
2281
+ },
2282
+ contentOrChangesIsEqual,
2283
+ ),
2284
+ );
2112
2285
  const setTablesJson = (tablesJson) => {
2113
2286
  tryCatch(() => setOrDelTables(jsonParse(tablesJson)));
2114
2287
  return store;
@@ -2155,7 +2328,12 @@ const createStore = () => {
2155
2328
  setTablesSchema(tablesSchema);
2156
2329
  setValuesSchema(valuesSchema);
2157
2330
  });
2158
- const delTables = () => fluentTransaction(() => setValidTables({}));
2331
+ const delTables = () =>
2332
+ fluentTransaction(() =>
2333
+ (whileMutating(() => middleware[7]?.()) ?? true)
2334
+ ? setValidTables({}, true)
2335
+ : 0,
2336
+ );
2159
2337
  const delTable = (tableId) =>
2160
2338
  fluentTransaction(
2161
2339
  (tableId2) =>
@@ -2173,7 +2351,7 @@ const createStore = () => {
2173
2351
  tableId,
2174
2352
  rowId,
2175
2353
  );
2176
- const delCell = (tableId, rowId, cellId, forceDel) =>
2354
+ const delCell = (tableId, rowId, cellId, forceDel, skipMiddleware) =>
2177
2355
  fluentTransaction(
2178
2356
  (tableId2, rowId2, cellId2) =>
2179
2357
  ifNotUndefined(mapGet(tablesMap, tableId2), (tableMap) =>
@@ -2186,6 +2364,7 @@ const createStore = () => {
2186
2364
  rowMap,
2187
2365
  cellId2,
2188
2366
  forceDel,
2367
+ skipMiddleware,
2189
2368
  )
2190
2369
  : 0,
2191
2370
  ),
@@ -2194,11 +2373,18 @@ const createStore = () => {
2194
2373
  rowId,
2195
2374
  cellId,
2196
2375
  );
2197
- const delValues = () => fluentTransaction(() => setValidValues({}));
2198
- const delValue = (valueId) =>
2376
+ const delValues = () =>
2377
+ fluentTransaction(() =>
2378
+ (whileMutating(() => middleware[11]?.()) ?? true)
2379
+ ? setValidValues({}, true)
2380
+ : 0,
2381
+ );
2382
+ const delValue = (valueId, skipMiddleware) =>
2199
2383
  fluentTransaction(
2200
2384
  (valueId2) =>
2201
- collHas(valuesMap, valueId2) ? delValidValue(valueId2) : 0,
2385
+ collHas(valuesMap, valueId2)
2386
+ ? delValidValue(valueId2, skipMiddleware)
2387
+ : 0,
2202
2388
  valueId,
2203
2389
  );
2204
2390
  const delTablesSchema = () =>
@@ -2280,27 +2466,27 @@ const createStore = () => {
2280
2466
  transactions--;
2281
2467
  if (transactions == 0) {
2282
2468
  transactions = 1;
2283
- mutating = 1;
2284
- callInvalidCellListeners(1);
2285
- if (!collIsEmpty(changedCells)) {
2286
- callTabularListenersForChanges(1);
2287
- }
2288
- callInvalidValueListeners(1);
2289
- if (!collIsEmpty(changedValues)) {
2290
- callValuesListenersForChanges(1);
2291
- }
2292
- mutating = 0;
2469
+ whileMutating(() => {
2470
+ callInvalidCellListeners(1);
2471
+ if (!collIsEmpty(changedCells)) {
2472
+ callTabularListenersForChanges(1);
2473
+ }
2474
+ callInvalidValueListeners(1);
2475
+ if (!collIsEmpty(changedValues)) {
2476
+ callValuesListenersForChanges(1);
2477
+ }
2478
+ });
2293
2479
  if (doRollback?.(store)) {
2294
2480
  collForEach(changedCells, (table, tableId) =>
2295
2481
  collForEach(table, (row, rowId) =>
2296
2482
  collForEach(row, ([oldCell], cellId) =>
2297
- setOrDelCell(store, tableId, rowId, cellId, oldCell),
2483
+ setOrDelCell(tableId, rowId, cellId, oldCell, true),
2298
2484
  ),
2299
2485
  ),
2300
2486
  );
2301
2487
  collClear(changedCells);
2302
2488
  collForEach(changedValues, ([oldValue], valueId) =>
2303
- setOrDelValue(store, valueId, oldValue),
2489
+ setOrDelValue(valueId, oldValue, true),
2304
2490
  );
2305
2491
  collClear(changedValues);
2306
2492
  }
@@ -2427,6 +2613,38 @@ const createStore = () => {
2427
2613
  collSize2(startTransactionListeners) +
2428
2614
  pairCollSize2(finishTransactionListeners),
2429
2615
  });
2616
+ const setMiddleware = (
2617
+ willSetContent,
2618
+ willSetTables,
2619
+ willSetTable,
2620
+ willSetRow,
2621
+ willSetCell,
2622
+ willSetValues,
2623
+ willSetValue,
2624
+ willDelTables,
2625
+ willDelTable,
2626
+ willDelRow,
2627
+ willDelCell,
2628
+ willDelValues,
2629
+ willDelValue,
2630
+ willApplyChanges,
2631
+ ) =>
2632
+ (middleware = [
2633
+ willSetContent,
2634
+ willSetTables,
2635
+ willSetTable,
2636
+ willSetRow,
2637
+ willSetCell,
2638
+ willSetValues,
2639
+ willSetValue,
2640
+ willDelTables,
2641
+ willDelTable,
2642
+ willDelRow,
2643
+ willDelCell,
2644
+ willDelValues,
2645
+ willDelValue,
2646
+ willApplyChanges,
2647
+ ]);
2430
2648
  const setInternalListeners = (
2431
2649
  preStartTransaction,
2432
2650
  preFinishTransaction,
@@ -2520,6 +2738,9 @@ const createStore = () => {
2520
2738
  addListener,
2521
2739
  callListeners,
2522
2740
  setInternalListeners,
2741
+ setMiddleware,
2742
+ setOrDelCell,
2743
+ setOrDelValue,
2523
2744
  };
2524
2745
  objMap(
2525
2746
  {
@@ -3076,7 +3297,8 @@ const createMergeableStore = (uniqueId, getNow) => {
3076
3297
  strStartsWith(name, DEL) ||
3077
3298
  strStartsWith(name, 'apply') ||
3078
3299
  strEndsWith(name, TRANSACTION) ||
3079
- name == 'call' + LISTENER
3300
+ name == 'call' + LISTENER ||
3301
+ name == 'use'
3080
3302
  ? (...args) => {
3081
3303
  method(...args);
3082
3304
  return mergeableStore;
@@ -3269,6 +3491,115 @@ const createMetrics = getCreateFunction((store) => {
3269
3491
  return objFreeze(metrics);
3270
3492
  });
3271
3493
 
3494
+ const reduceCallbacks = (callbacks, thing, ...ids) =>
3495
+ arrayReduce(
3496
+ callbacks,
3497
+ (current, callback) =>
3498
+ isUndefined(current) ? current : callback(...ids, current),
3499
+ thing,
3500
+ );
3501
+ const everyCallback = (callbacks, ...ids) =>
3502
+ arrayEvery(callbacks, (callback) => callback(...ids));
3503
+ const createMiddleware = getCreateFunction((store) => {
3504
+ const fluent = (actions) => {
3505
+ actions();
3506
+ return middleware;
3507
+ };
3508
+ const addCallback = (callbacks) => (callback) =>
3509
+ fluent(() => arrayPush(callbacks, callback));
3510
+ const willSetContentCallbacks = [];
3511
+ const willSetTablesCallbacks = [];
3512
+ const willSetTableCallbacks = [];
3513
+ const willSetRowCallbacks = [];
3514
+ const willSetCellCallbacks = [];
3515
+ const willSetValuesCallbacks = [];
3516
+ const willSetValueCallbacks = [];
3517
+ const willDelTablesCallbacks = [];
3518
+ const willDelTableCallbacks = [];
3519
+ const willDelRowCallbacks = [];
3520
+ const willDelCellCallbacks = [];
3521
+ const willDelValuesCallbacks = [];
3522
+ const willDelValueCallbacks = [];
3523
+ const willApplyChangesCallbacks = [];
3524
+ const willSetContent = (content) =>
3525
+ reduceCallbacks(willSetContentCallbacks, content);
3526
+ const willSetTables = (tables) =>
3527
+ reduceCallbacks(willSetTablesCallbacks, tables);
3528
+ const willSetTable = (tableId, table) =>
3529
+ reduceCallbacks(willSetTableCallbacks, table, tableId);
3530
+ const willSetRow = (tableId, rowId, row) =>
3531
+ reduceCallbacks(willSetRowCallbacks, row, tableId, rowId);
3532
+ const willSetCell = (tableId, rowId, cellId, cell) =>
3533
+ reduceCallbacks(willSetCellCallbacks, cell, tableId, rowId, cellId);
3534
+ const willSetValues = (values) =>
3535
+ reduceCallbacks(willSetValuesCallbacks, values);
3536
+ const willSetValue = (valueId, value) =>
3537
+ reduceCallbacks(willSetValueCallbacks, value, valueId);
3538
+ const willDelTables = () => everyCallback(willDelTablesCallbacks);
3539
+ const willDelTable = (tableId) =>
3540
+ everyCallback(willDelTableCallbacks, tableId);
3541
+ const willDelRow = (tableId, rowId) =>
3542
+ everyCallback(willDelRowCallbacks, tableId, rowId);
3543
+ const willDelCell = (tableId, rowId, cellId) =>
3544
+ everyCallback(willDelCellCallbacks, tableId, rowId, cellId);
3545
+ const willDelValues = () => everyCallback(willDelValuesCallbacks);
3546
+ const willDelValue = (valueId) =>
3547
+ everyCallback(willDelValueCallbacks, valueId);
3548
+ const willApplyChanges = (changes) =>
3549
+ reduceCallbacks(willApplyChangesCallbacks, changes);
3550
+ const getStore = () => store;
3551
+ const addWillSetContentCallback = addCallback(willSetContentCallbacks);
3552
+ const addWillSetTablesCallback = addCallback(willSetTablesCallbacks);
3553
+ const addWillSetTableCallback = addCallback(willSetTableCallbacks);
3554
+ const addWillSetRowCallback = addCallback(willSetRowCallbacks);
3555
+ const addWillSetCellCallback = addCallback(willSetCellCallbacks);
3556
+ const addWillSetValuesCallback = addCallback(willSetValuesCallbacks);
3557
+ const addWillSetValueCallback = addCallback(willSetValueCallbacks);
3558
+ const addWillDelTablesCallback = addCallback(willDelTablesCallbacks);
3559
+ const addWillDelTableCallback = addCallback(willDelTableCallbacks);
3560
+ const addWillDelRowCallback = addCallback(willDelRowCallbacks);
3561
+ const addWillDelCellCallback = addCallback(willDelCellCallbacks);
3562
+ const addWillDelValuesCallback = addCallback(willDelValuesCallbacks);
3563
+ const addWillDelValueCallback = addCallback(willDelValueCallbacks);
3564
+ const addWillApplyChangesCallback = addCallback(willApplyChangesCallbacks);
3565
+ const destroy = () => {};
3566
+ const middleware = objFreeze({
3567
+ getStore,
3568
+ addWillSetContentCallback,
3569
+ addWillSetTablesCallback,
3570
+ addWillSetTableCallback,
3571
+ addWillSetRowCallback,
3572
+ addWillSetCellCallback,
3573
+ addWillSetValuesCallback,
3574
+ addWillSetValueCallback,
3575
+ addWillDelTablesCallback,
3576
+ addWillDelTableCallback,
3577
+ addWillDelRowCallback,
3578
+ addWillDelCellCallback,
3579
+ addWillDelValuesCallback,
3580
+ addWillDelValueCallback,
3581
+ addWillApplyChangesCallback,
3582
+ destroy,
3583
+ });
3584
+ store.setMiddleware(
3585
+ willSetContent,
3586
+ willSetTables,
3587
+ willSetTable,
3588
+ willSetRow,
3589
+ willSetCell,
3590
+ willSetValues,
3591
+ willSetValue,
3592
+ willDelTables,
3593
+ willDelTable,
3594
+ willDelRow,
3595
+ willDelCell,
3596
+ willDelValues,
3597
+ willDelValue,
3598
+ willApplyChanges,
3599
+ );
3600
+ return middleware;
3601
+ });
3602
+
3272
3603
  const createQueries = getCreateFunction((store) => {
3273
3604
  const createStore = store.createStore;
3274
3605
  const preStore = createStore();
@@ -3597,8 +3928,7 @@ const createQueries = getCreateFunction((store) => {
3597
3928
  selectJoinWhereStore.transaction(() =>
3598
3929
  arrayEvery(wheres, (where2) => where2(getTableCell))
3599
3930
  ? mapForEach(selects, (asCellId, tableCellGetter) =>
3600
- setOrDelCell(
3601
- selectJoinWhereStore,
3931
+ selectJoinWhereStore.setOrDelCell(
3602
3932
  queryId,
3603
3933
  rootRowId,
3604
3934
  asCellId,
@@ -4003,6 +4333,7 @@ export {
4003
4333
  createIndexes,
4004
4334
  createMergeableStore,
4005
4335
  createMetrics,
4336
+ createMiddleware,
4006
4337
  createQueries,
4007
4338
  createRelationships,
4008
4339
  createStore,