tinybase 1.0.4 → 1.1.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.
@@ -29,6 +29,8 @@ const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
29
29
  const arrayFilter = (array, cb) => array.filter(cb);
30
30
  const arrayFromSecond = (ids) => ids.slice(1);
31
31
  const arrayClear = (array, to) => array.splice(0, to);
32
+ const arrayPush = (array, value) => array.push(value);
33
+ const arrayPop = (array) => array.pop();
32
34
 
33
35
  const jsonString = (obj) =>
34
36
  JSON.stringify(obj, (_key, value) =>
@@ -110,6 +112,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
110
112
  const storeListenerIds = mapNew();
111
113
  const getStore = () => store;
112
114
  const getThingIds = () => mapKeys(tableIds);
115
+ const forEachThing = (cb) => mapForEach(things, cb);
113
116
  const hasThing = (id) => collHas(things, id);
114
117
  const getTableId = (id) => mapGet(tableIds, id);
115
118
  const getThing = (id) => mapGet(things, id);
@@ -200,6 +203,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
200
203
  return [
201
204
  getStore,
202
205
  getThingIds,
206
+ forEachThing,
203
207
  hasThing,
204
208
  getTableId,
205
209
  getThing,
@@ -252,7 +256,7 @@ const getListenerFunctions = (getThing) => {
252
256
  const allListeners = mapNew();
253
257
  const addListener = (listener, deepSet, idOrNulls = []) => {
254
258
  thing ??= getThing();
255
- const id = listenerPool.pop() ?? '' + nextId++;
259
+ const id = arrayPop(listenerPool) ?? '' + nextId++;
256
260
  mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
257
261
  addDeepSet(deepSet, id, idOrNulls);
258
262
  return id;
@@ -273,7 +277,7 @@ const getListenerFunctions = (getThing) => {
273
277
  forDeepSet(collDel)(deepSet, id, ...idOrNulls);
274
278
  mapSet(allListeners, id);
275
279
  if (arrayLength(listenerPool) < 1e3) {
276
- listenerPool.push(id);
280
+ arrayPush(listenerPool, id);
277
281
  }
278
282
  return idOrNulls;
279
283
  },
@@ -359,7 +363,7 @@ const createCheckpoints = getCreateFunction((store) => {
359
363
  (_store, tableId, rowId, cellId, newCell, oldCell) => {
360
364
  if (listening) {
361
365
  ifNotUndefined(currentId, () => {
362
- backwardIds.push(currentId);
366
+ arrayPush(backwardIds, currentId);
363
367
  trimBackwardsIds();
364
368
  clearCheckpointIds(forwardIds);
365
369
  currentId = void 0;
@@ -378,7 +382,7 @@ const createCheckpoints = getCreateFunction((store) => {
378
382
  if (collIsEmpty(mapSet(row, cellId))) {
379
383
  if (collIsEmpty(mapSet(table, rowId))) {
380
384
  if (collIsEmpty(mapSet(delta, tableId))) {
381
- currentId = backwardIds.pop();
385
+ currentId = arrayPop(backwardIds);
382
386
  checkpointsChanged = 1;
383
387
  }
384
388
  }
@@ -402,13 +406,13 @@ const createCheckpoints = getCreateFunction((store) => {
402
406
  if (!arrayIsEmpty(backwardIds)) {
403
407
  forwardIds.unshift(addCheckpointImpl());
404
408
  updateStore(0, currentId);
405
- currentId = backwardIds.pop();
409
+ currentId = arrayPop(backwardIds);
406
410
  checkpointsChanged = 1;
407
411
  }
408
412
  };
409
413
  const goForwardImpl = () => {
410
414
  if (!arrayIsEmpty(forwardIds)) {
411
- backwardIds.push(currentId);
415
+ arrayPush(backwardIds, currentId);
412
416
  currentId = forwardIds.shift();
413
417
  updateStore(1, currentId);
414
418
  checkpointsChanged = 1;
@@ -439,6 +443,8 @@ const createCheckpoints = getCreateFunction((store) => {
439
443
  };
440
444
  const getStore = () => store;
441
445
  const getCheckpointIds = () => [[...backwardIds], currentId, [...forwardIds]];
446
+ const forEachCheckpoint = (checkpointCallback) =>
447
+ mapForEach(labels, checkpointCallback);
442
448
  const hasCheckpoint = (checkpointId) => collHas(deltas, checkpointId);
443
449
  const getCheckpoint = (checkpointId) => mapGet(labels, checkpointId);
444
450
  const goBackward = () => {
@@ -495,6 +501,7 @@ const createCheckpoints = getCreateFunction((store) => {
495
501
  setCheckpoint,
496
502
  getStore,
497
503
  getCheckpointIds,
504
+ forEachCheckpoint,
498
505
  hasCheckpoint,
499
506
  getCheckpoint,
500
507
  goBackward,
@@ -518,6 +525,7 @@ const createIndexes = getCreateFunction((store) => {
518
525
  const [
519
526
  getStore,
520
527
  getIndexIds,
528
+ forEachIndexImpl,
521
529
  hasIndex,
522
530
  getTableId,
523
531
  getIndex,
@@ -627,6 +635,26 @@ const createIndexes = getCreateFunction((store) => {
627
635
  );
628
636
  return indexes;
629
637
  };
638
+ const forEachIndex = (indexCallback) =>
639
+ forEachIndexImpl((indexId, slices) =>
640
+ indexCallback(indexId, (sliceCallback) =>
641
+ forEachSliceImpl(indexId, sliceCallback, slices),
642
+ ),
643
+ );
644
+ const forEachSlice = (indexId, sliceCallback) =>
645
+ forEachSliceImpl(indexId, sliceCallback, getIndex(indexId));
646
+ const forEachSliceImpl = (indexId, sliceCallback, slices) => {
647
+ const tableId = getTableId(indexId);
648
+ collForEach(slices, (rowIds, sliceId) =>
649
+ sliceCallback(sliceId, (rowCallback) =>
650
+ collForEach(rowIds, (rowId) =>
651
+ rowCallback(rowId, (cellCallback) =>
652
+ store.forEachCell(tableId, rowId, cellCallback),
653
+ ),
654
+ ),
655
+ ),
656
+ );
657
+ };
630
658
  const delIndexDefinition = (indexId) => {
631
659
  delDefinition(indexId);
632
660
  return indexes;
@@ -651,6 +679,8 @@ const createIndexes = getCreateFunction((store) => {
651
679
  delIndexDefinition,
652
680
  getStore,
653
681
  getIndexIds,
682
+ forEachIndex,
683
+ forEachSlice,
654
684
  hasIndex,
655
685
  hasSlice,
656
686
  getTableId,
@@ -710,6 +740,7 @@ const createMetrics = getCreateFunction((store) => {
710
740
  const [
711
741
  getStore,
712
742
  getMetricIds,
743
+ forEachMetric,
713
744
  hasMetric,
714
745
  getTableId,
715
746
  getMetric,
@@ -795,6 +826,7 @@ const createMetrics = getCreateFunction((store) => {
795
826
  delMetricDefinition,
796
827
  getStore,
797
828
  getMetricIds,
829
+ forEachMetric,
798
830
  hasMetric,
799
831
  getTableId,
800
832
  getMetric,
@@ -987,6 +1019,7 @@ const createRelationships = getCreateFunction((store) => {
987
1019
  const [
988
1020
  getStore,
989
1021
  getRelationshipIds,
1022
+ forEachRelationshipImpl,
990
1023
  hasRelationship,
991
1024
  getLocalTableId,
992
1025
  getRelationship,
@@ -1101,6 +1134,12 @@ const createRelationships = getCreateFunction((store) => {
1101
1134
  );
1102
1135
  return relationships;
1103
1136
  };
1137
+ const forEachRelationship = (relationshipCallback) =>
1138
+ forEachRelationshipImpl((relationshipId) =>
1139
+ relationshipCallback(relationshipId, (rowCallback) =>
1140
+ store.forEachRow(getLocalTableId(relationshipId), rowCallback),
1141
+ ),
1142
+ );
1104
1143
  const delRelationshipDefinition = (relationshipId) => {
1105
1144
  mapSet(remoteTableIds, relationshipId);
1106
1145
  delDefinition(relationshipId);
@@ -1141,6 +1180,7 @@ const createRelationships = getCreateFunction((store) => {
1141
1180
  delRelationshipDefinition,
1142
1181
  getStore,
1143
1182
  getRelationshipIds,
1183
+ forEachRelationship,
1144
1184
  hasRelationship,
1145
1185
  getLocalTableId,
1146
1186
  getRemoteTableId,
@@ -1174,8 +1214,9 @@ const getCellType = (cell) => {
1174
1214
  ? type
1175
1215
  : void 0;
1176
1216
  };
1177
- const validate = (obj, validateChild) => {
1178
- if (isUndefined(obj) || !isObject(obj) || objFrozen(obj)) {
1217
+ const validate = (obj, validateChild, onInvalidObj) => {
1218
+ if (isUndefined(obj) || !isObject(obj) || objIsEmpty(obj) || objFrozen(obj)) {
1219
+ onInvalidObj?.();
1179
1220
  return false;
1180
1221
  }
1181
1222
  objForEach(obj, (child, id) => {
@@ -1195,8 +1236,9 @@ const createStore = () => {
1195
1236
  const changedRowIds = mapNew();
1196
1237
  const changedCellIds = mapNew();
1197
1238
  const changedCells = mapNew();
1239
+ const invalidCells = mapNew();
1198
1240
  const schemaMap = mapNew();
1199
- const schemaDefaultRows = mapNew();
1241
+ const schemaRowCache = mapNew();
1200
1242
  const tablesMap = mapNew();
1201
1243
  const tablesListeners = mapNewPair(setNew);
1202
1244
  const tableIdsListeners = mapNewPair(setNew);
@@ -1205,6 +1247,7 @@ const createStore = () => {
1205
1247
  const rowListeners = mapNewPair();
1206
1248
  const cellIdsListeners = mapNewPair();
1207
1249
  const cellListeners = mapNewPair();
1250
+ const invalidCellListeners = mapNewPair();
1208
1251
  const [addListener, callListeners, delListenerImpl, callListenerImpl] =
1209
1252
  getListenerFunctions(() => store);
1210
1253
  const validateSchema = (schema) =>
@@ -1225,40 +1268,57 @@ const createStore = () => {
1225
1268
  return true;
1226
1269
  }),
1227
1270
  );
1228
- const validateTables = (tables) => validate(tables, validateTable);
1271
+ const validateTables = (tables) =>
1272
+ validate(tables, validateTable, cellInvalid);
1229
1273
  const validateTable = (table, tableId) =>
1230
- (!hasSchema || collHas(schemaMap, tableId)) &&
1231
- validate(table, (row) => validateRow(tableId, row));
1232
- const validateRow = (tableId, row, skipDefaults) =>
1274
+ (!hasSchema || collHas(schemaMap, tableId) || cellInvalid(tableId)) &&
1233
1275
  validate(
1234
- skipDefaults ? row : addDefaultsToRow(row, tableId),
1276
+ table,
1277
+ (row, rowId) => validateRow(tableId, rowId, row),
1278
+ () => cellInvalid(tableId),
1279
+ );
1280
+ const validateRow = (tableId, rowId, row, skipDefaults) =>
1281
+ validate(
1282
+ skipDefaults ? row : addDefaultsToRow(row, tableId, rowId),
1235
1283
  (cell, cellId) =>
1236
1284
  ifNotUndefined(
1237
- getValidatedCell(tableId, cellId, cell),
1285
+ getValidatedCell(tableId, rowId, cellId, cell),
1238
1286
  (validCell) => {
1239
1287
  row[cellId] = validCell;
1240
1288
  return true;
1241
1289
  },
1242
1290
  () => false,
1243
1291
  ),
1292
+ () => cellInvalid(tableId, rowId),
1244
1293
  );
1245
- const getValidatedCell = (tableId, cellId, cell) =>
1294
+ const getValidatedCell = (tableId, rowId, cellId, cell) =>
1246
1295
  hasSchema
1247
1296
  ? ifNotUndefined(
1248
1297
  mapGet(mapGet(schemaMap, tableId), cellId),
1249
1298
  (cellSchema) =>
1250
- getCellType(cell) != cellSchema[TYPE] ? cellSchema[DEFAULT] : cell,
1299
+ getCellType(cell) != cellSchema[TYPE]
1300
+ ? cellInvalid(tableId, rowId, cellId, cell, cellSchema[DEFAULT])
1301
+ : cell,
1302
+ () => cellInvalid(tableId, rowId, cellId, cell),
1251
1303
  )
1252
1304
  : isUndefined(getCellType(cell))
1253
- ? void 0
1305
+ ? cellInvalid(tableId, rowId, cellId, cell)
1254
1306
  : cell;
1255
- const addDefaultsToRow = (row, tableId) => {
1256
- ifNotUndefined(mapGet(schemaDefaultRows, tableId), (defaultRow) =>
1257
- objForEach(defaultRow, (cell, cellId) => {
1258
- if (!objHas(row, cellId)) {
1259
- row[cellId] = cell;
1260
- }
1261
- }),
1307
+ const addDefaultsToRow = (row, tableId, rowId) => {
1308
+ ifNotUndefined(
1309
+ mapGet(schemaRowCache, tableId),
1310
+ ([rowDefaulted, rowNonDefaulted]) => {
1311
+ collForEach(rowDefaulted, (cell, cellId) => {
1312
+ if (!objHas(row, cellId)) {
1313
+ row[cellId] = cell;
1314
+ }
1315
+ });
1316
+ collForEach(rowNonDefaulted, (cellId) => {
1317
+ if (!objHas(row, cellId)) {
1318
+ cellInvalid(tableId, rowId, cellId);
1319
+ }
1320
+ });
1321
+ },
1262
1322
  );
1263
1323
  return row;
1264
1324
  };
@@ -1267,7 +1327,8 @@ const createStore = () => {
1267
1327
  schemaMap,
1268
1328
  schema,
1269
1329
  (_schema, tableId, tableSchema) => {
1270
- const defaultRow = {};
1330
+ const rowDefaulted = mapNew();
1331
+ const rowNonDefaulted = setNew();
1271
1332
  transformMap(
1272
1333
  mapEnsure(schemaMap, tableId, mapNew()),
1273
1334
  tableSchema,
@@ -1275,15 +1336,16 @@ const createStore = () => {
1275
1336
  mapSet(tableSchemaMap, cellId, cellSchema);
1276
1337
  ifNotUndefined(
1277
1338
  cellSchema[DEFAULT],
1278
- (def) => (defaultRow[cellId] = def),
1339
+ (def) => mapSet(rowDefaulted, cellId, def),
1340
+ () => setAdd(rowNonDefaulted, cellId),
1279
1341
  );
1280
1342
  },
1281
1343
  );
1282
- mapSet(schemaDefaultRows, tableId, defaultRow);
1344
+ mapSet(schemaRowCache, tableId, [rowDefaulted, rowNonDefaulted]);
1283
1345
  },
1284
1346
  (_schema, tableId) => {
1285
1347
  mapSet(schemaMap, tableId);
1286
- mapSet(schemaDefaultRows, tableId);
1348
+ mapSet(schemaRowCache, tableId);
1287
1349
  },
1288
1350
  );
1289
1351
  const setValidTables = (tables) =>
@@ -1323,10 +1385,6 @@ const createStore = () => {
1323
1385
  mapSet(rowMap, cellId, newCell);
1324
1386
  }
1325
1387
  };
1326
- const setValidRowTransaction = (tableId, rowId, row) =>
1327
- transaction(() =>
1328
- setValidRow(tableId, getOrCreateTable(tableId), rowId, row),
1329
- );
1330
1388
  const setCellIntoDefaultRow = (tableId, tableMap, rowId, cellId, validCell) =>
1331
1389
  ifNotUndefined(
1332
1390
  mapGet(tableMap, rowId),
@@ -1336,7 +1394,7 @@ const createStore = () => {
1336
1394
  tableId,
1337
1395
  tableMap,
1338
1396
  rowId,
1339
- addDefaultsToRow({[cellId]: validCell}, tableId),
1397
+ addDefaultsToRow({[cellId]: validCell}, tableId, rowId),
1340
1398
  ),
1341
1399
  );
1342
1400
  const getNewRowId = (tableMap) => {
@@ -1352,7 +1410,7 @@ const createStore = () => {
1352
1410
  const delValidRow = (tableId, tableMap, rowId) =>
1353
1411
  setValidRow(tableId, tableMap, rowId, {}, true);
1354
1412
  const delValidCell = (tableId, table, rowId, row, cellId, forceDel) => {
1355
- const defaultCell = mapGet(schemaDefaultRows, tableId)?.[cellId];
1413
+ const defaultCell = mapGet(mapGet(schemaRowCache, tableId)?.[0], cellId);
1356
1414
  if (!isUndefined(defaultCell) && !forceDel) {
1357
1415
  return setValidCell(tableId, rowId, row, cellId, defaultCell);
1358
1416
  }
@@ -1386,6 +1444,17 @@ const createStore = () => {
1386
1444
  cellId,
1387
1445
  oldCell,
1388
1446
  );
1447
+ const cellInvalid = (tableId, rowId, cellId, invalidCell, defaultedCell) => {
1448
+ arrayPush(
1449
+ mapEnsure(
1450
+ mapEnsure(mapEnsure(invalidCells, tableId, mapNew()), rowId, mapNew()),
1451
+ cellId,
1452
+ [],
1453
+ ),
1454
+ invalidCell,
1455
+ );
1456
+ return defaultedCell;
1457
+ };
1389
1458
  const getCellChange = (tableId, rowId, cellId) => {
1390
1459
  const changedRow = mapGet(mapGet(changedCells, tableId), rowId);
1391
1460
  const newCell = getCell(tableId, rowId, cellId);
@@ -1393,80 +1462,103 @@ const createStore = () => {
1393
1462
  ? [true, mapGet(changedRow, cellId), newCell]
1394
1463
  : [false, newCell, newCell];
1395
1464
  };
1465
+ const callInvalidCellListeners = (mutator) =>
1466
+ !collIsEmpty(invalidCells) && !collIsEmpty(invalidCellListeners[mutator])
1467
+ ? collForEach(
1468
+ mutator
1469
+ ? mapClone(invalidCells, (table) => mapClone(table, mapClone))
1470
+ : invalidCells,
1471
+ (rows, tableId) =>
1472
+ collForEach(rows, (cells, rowId) =>
1473
+ collForEach(cells, (invalidCell, cellId) =>
1474
+ callListeners(
1475
+ invalidCellListeners[mutator],
1476
+ [tableId, rowId, cellId],
1477
+ invalidCell,
1478
+ ),
1479
+ ),
1480
+ ),
1481
+ )
1482
+ : 0;
1396
1483
  const callListenersForChanges = (mutator) => {
1397
- const emptyIdListeners =
1398
- collIsEmpty(cellIdsListeners[mutator]) &&
1399
- collIsEmpty(rowIdsListeners[mutator]) &&
1400
- collIsEmpty(tableIdsListeners[mutator]);
1401
- const emptyOtherListeners =
1402
- collIsEmpty(cellListeners[mutator]) &&
1403
- collIsEmpty(rowListeners[mutator]) &&
1404
- collIsEmpty(tableListeners[mutator]) &&
1405
- collIsEmpty(tablesListeners[mutator]);
1406
- if (emptyIdListeners && emptyOtherListeners) {
1407
- return;
1408
- }
1409
- const changes = mutator
1410
- ? [
1411
- mapClone(changedTableIds),
1412
- mapClone(changedRowIds, mapClone),
1413
- mapClone(changedCellIds, (table) => mapClone(table, mapClone)),
1414
- mapClone(changedCells, (table) => mapClone(table, mapClone)),
1415
- ]
1416
- : [changedTableIds, changedRowIds, changedCellIds, changedCells];
1417
- if (!emptyIdListeners) {
1418
- collForEach(changes[2], (rowCellIds, tableId) =>
1419
- collForEach(rowCellIds, (changedIds, rowId) => {
1420
- if (!collIsEmpty(changedIds)) {
1421
- callListeners(cellIdsListeners[mutator], [tableId, rowId]);
1484
+ if (!collIsEmpty(changedCells)) {
1485
+ const emptyIdListeners =
1486
+ collIsEmpty(cellIdsListeners[mutator]) &&
1487
+ collIsEmpty(rowIdsListeners[mutator]) &&
1488
+ collIsEmpty(tableIdsListeners[mutator]);
1489
+ const emptyOtherListeners =
1490
+ collIsEmpty(cellListeners[mutator]) &&
1491
+ collIsEmpty(rowListeners[mutator]) &&
1492
+ collIsEmpty(tableListeners[mutator]) &&
1493
+ collIsEmpty(tablesListeners[mutator]);
1494
+ if (!(emptyIdListeners && emptyOtherListeners)) {
1495
+ const changes = mutator
1496
+ ? [
1497
+ mapClone(changedTableIds),
1498
+ mapClone(changedRowIds, mapClone),
1499
+ mapClone(changedCellIds, (table) => mapClone(table, mapClone)),
1500
+ mapClone(changedCells, (table) => mapClone(table, mapClone)),
1501
+ ]
1502
+ : [changedTableIds, changedRowIds, changedCellIds, changedCells];
1503
+ if (!emptyIdListeners) {
1504
+ collForEach(changes[2], (rowCellIds, tableId) =>
1505
+ collForEach(rowCellIds, (changedIds, rowId) => {
1506
+ if (!collIsEmpty(changedIds)) {
1507
+ callListeners(cellIdsListeners[mutator], [tableId, rowId]);
1508
+ }
1509
+ }),
1510
+ );
1511
+ collForEach(changes[1], (changedIds, tableId) => {
1512
+ if (!collIsEmpty(changedIds)) {
1513
+ callListeners(rowIdsListeners[mutator], [tableId]);
1514
+ }
1515
+ });
1516
+ if (!collIsEmpty(changes[0])) {
1517
+ callListeners(tableIdsListeners[mutator]);
1422
1518
  }
1423
- }),
1424
- );
1425
- collForEach(changes[1], (changedIds, tableId) => {
1426
- if (!collIsEmpty(changedIds)) {
1427
- callListeners(rowIdsListeners[mutator], [tableId]);
1428
1519
  }
1429
- });
1430
- if (!collIsEmpty(changes[0])) {
1431
- callListeners(tableIdsListeners[mutator]);
1432
- }
1433
- }
1434
- if (!emptyOtherListeners) {
1435
- let tablesChanged;
1436
- collForEach(changes[3], (rows, tableId) => {
1437
- let tableChanged;
1438
- collForEach(rows, (cells, rowId) => {
1439
- let rowChanged;
1440
- collForEach(cells, (oldCell, cellId) => {
1441
- const newCell = getCell(tableId, rowId, cellId);
1442
- if (newCell !== oldCell) {
1443
- callListeners(
1444
- cellListeners[mutator],
1445
- [tableId, rowId, cellId],
1446
- newCell,
1447
- oldCell,
1448
- getCellChange,
1449
- );
1450
- tablesChanged = tableChanged = rowChanged = 1;
1520
+ if (!emptyOtherListeners) {
1521
+ let tablesChanged;
1522
+ collForEach(changes[3], (rows, tableId) => {
1523
+ let tableChanged;
1524
+ collForEach(rows, (cells, rowId) => {
1525
+ let rowChanged;
1526
+ collForEach(cells, (oldCell, cellId) => {
1527
+ const newCell = getCell(tableId, rowId, cellId);
1528
+ if (newCell !== oldCell) {
1529
+ callListeners(
1530
+ cellListeners[mutator],
1531
+ [tableId, rowId, cellId],
1532
+ newCell,
1533
+ oldCell,
1534
+ getCellChange,
1535
+ );
1536
+ tablesChanged = tableChanged = rowChanged = 1;
1537
+ }
1538
+ });
1539
+ if (rowChanged) {
1540
+ callListeners(
1541
+ rowListeners[mutator],
1542
+ [tableId, rowId],
1543
+ getCellChange,
1544
+ );
1545
+ }
1546
+ });
1547
+ if (tableChanged) {
1548
+ callListeners(tableListeners[mutator], [tableId], getCellChange);
1451
1549
  }
1452
1550
  });
1453
- if (rowChanged) {
1454
- callListeners(
1455
- rowListeners[mutator],
1456
- [tableId, rowId],
1457
- getCellChange,
1458
- );
1551
+ if (tablesChanged) {
1552
+ callListeners(tablesListeners[mutator], [], getCellChange);
1459
1553
  }
1460
- });
1461
- if (tableChanged) {
1462
- callListeners(tableListeners[mutator], [tableId], getCellChange);
1463
1554
  }
1464
- });
1465
- if (tablesChanged) {
1466
- callListeners(tablesListeners[mutator], [], getCellChange);
1467
1555
  }
1468
1556
  }
1469
1557
  };
1558
+ const fluentTransaction = (actions) => {
1559
+ transaction(actions);
1560
+ return store;
1561
+ };
1470
1562
  const getTables = () =>
1471
1563
  mapToObj(tablesMap, (tableMap) => mapToObj(tableMap, mapToObj));
1472
1564
  const getTableIds = () => mapKeys(tablesMap);
@@ -1485,52 +1577,52 @@ const createStore = () => {
1485
1577
  collHas(mapGet(mapGet(tablesMap, tableId), rowId), cellId);
1486
1578
  const getJson = () => jsonString(tablesMap);
1487
1579
  const getSchemaJson = () => jsonString(schemaMap);
1488
- const setTables = (tables) => {
1489
- if (validateTables(tables)) {
1490
- transaction(() => setValidTables(tables));
1491
- }
1492
- return store;
1493
- };
1494
- const setTable = (tableId, table) => {
1495
- if (validateTable(table, tableId)) {
1496
- transaction(() => setValidTable(tableId, table));
1497
- }
1498
- return store;
1499
- };
1500
- const setRow = (tableId, rowId, row) => {
1501
- if (validateRow(tableId, row)) {
1502
- setValidRowTransaction(tableId, rowId, row);
1503
- }
1504
- return store;
1505
- };
1506
- const addRow = (tableId, row) => {
1507
- let rowId = void 0;
1508
- if (validateRow(tableId, row)) {
1509
- rowId = getNewRowId(mapGet(tablesMap, tableId));
1510
- setValidRowTransaction(tableId, rowId, row);
1511
- }
1512
- return rowId;
1513
- };
1514
- const setPartialRow = (tableId, rowId, partialRow) => {
1515
- if (validateRow(tableId, partialRow, 1)) {
1516
- transaction(() => {
1580
+ const setTables = (tables) =>
1581
+ fluentTransaction(() =>
1582
+ validateTables(tables) ? setValidTables(tables) : 0,
1583
+ );
1584
+ const setTable = (tableId, table) =>
1585
+ fluentTransaction(() =>
1586
+ validateTable(table, tableId) ? setValidTable(tableId, table) : 0,
1587
+ );
1588
+ const setRow = (tableId, rowId, row) =>
1589
+ fluentTransaction(() =>
1590
+ validateRow(tableId, rowId, row)
1591
+ ? setValidRow(tableId, getOrCreateTable(tableId), rowId, row)
1592
+ : 0,
1593
+ );
1594
+ const addRow = (tableId, row) =>
1595
+ transaction(() => {
1596
+ let rowId = void 0;
1597
+ if (validateRow(tableId, rowId, row)) {
1598
+ setValidRow(
1599
+ tableId,
1600
+ getOrCreateTable(tableId),
1601
+ (rowId = getNewRowId(mapGet(tablesMap, tableId))),
1602
+ row,
1603
+ );
1604
+ }
1605
+ return rowId;
1606
+ });
1607
+ const setPartialRow = (tableId, rowId, partialRow) =>
1608
+ fluentTransaction(() => {
1609
+ if (validateRow(tableId, rowId, partialRow, 1)) {
1517
1610
  const table = getOrCreateTable(tableId);
1518
1611
  objForEach(partialRow, (cell, cellId) =>
1519
1612
  setCellIntoDefaultRow(tableId, table, rowId, cellId, cell),
1520
1613
  );
1521
- });
1522
- }
1523
- return store;
1524
- };
1525
- const setCell = (tableId, rowId, cellId, cell) => {
1526
- ifNotUndefined(
1527
- getValidatedCell(
1528
- tableId,
1529
- cellId,
1530
- isFunction(cell) ? cell(getCell(tableId, rowId, cellId)) : cell,
1531
- ),
1532
- (validCell) =>
1533
- transaction(() =>
1614
+ }
1615
+ });
1616
+ const setCell = (tableId, rowId, cellId, cell) =>
1617
+ fluentTransaction(() =>
1618
+ ifNotUndefined(
1619
+ getValidatedCell(
1620
+ tableId,
1621
+ rowId,
1622
+ cellId,
1623
+ isFunction(cell) ? cell(getCell(tableId, rowId, cellId)) : cell,
1624
+ ),
1625
+ (validCell) =>
1534
1626
  setCellIntoDefaultRow(
1535
1627
  tableId,
1536
1628
  getOrCreateTable(tableId),
@@ -1538,77 +1630,74 @@ const createStore = () => {
1538
1630
  cellId,
1539
1631
  validCell,
1540
1632
  ),
1541
- ),
1633
+ ),
1542
1634
  );
1543
- return store;
1544
- };
1545
1635
  const setJson = (json) => {
1546
1636
  try {
1547
1637
  json === EMPTY_OBJECT ? delTables() : setTables(jsonParse(json));
1548
1638
  } catch {}
1549
1639
  return store;
1550
1640
  };
1551
- const setSchema = (schema) => {
1552
- if ((hasSchema = validateSchema(schema))) {
1553
- setValidSchema(schema);
1554
- if (!collIsEmpty(tablesMap)) {
1555
- const tables = getTables();
1556
- delTables();
1557
- setTables(tables);
1558
- }
1559
- }
1560
- return store;
1561
- };
1562
- const delTables = () => {
1563
- transaction(() => setValidTables({}));
1564
- return store;
1565
- };
1566
- const delTable = (tableId) => {
1567
- if (collHas(tablesMap, tableId)) {
1568
- transaction(() => delValidTable(tableId));
1569
- }
1570
- return store;
1571
- };
1572
- const delRow = (tableId, rowId) => {
1573
- ifNotUndefined(mapGet(tablesMap, tableId), (tableMap) => {
1574
- if (collHas(tableMap, rowId)) {
1575
- transaction(() => delValidRow(tableId, tableMap, rowId));
1641
+ const setSchema = (schema) =>
1642
+ fluentTransaction(() => {
1643
+ if ((hasSchema = validateSchema(schema))) {
1644
+ setValidSchema(schema);
1645
+ if (!collIsEmpty(tablesMap)) {
1646
+ const tables = getTables();
1647
+ delTables();
1648
+ setTables(tables);
1649
+ }
1576
1650
  }
1577
1651
  });
1578
- return store;
1579
- };
1580
- const delCell = (tableId, rowId, cellId, forceDel) => {
1581
- ifNotUndefined(mapGet(tablesMap, tableId), (tableMap) =>
1582
- ifNotUndefined(mapGet(tableMap, rowId), (rowMap) => {
1583
- if (collHas(rowMap, cellId)) {
1584
- transaction(() =>
1585
- delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel),
1586
- );
1587
- }
1588
- }),
1652
+ const delTables = () => fluentTransaction(() => setValidTables({}));
1653
+ const delTable = (tableId) =>
1654
+ fluentTransaction(() =>
1655
+ collHas(tablesMap, tableId) ? delValidTable(tableId) : 0,
1589
1656
  );
1590
- return store;
1591
- };
1592
- const delSchema = () => {
1593
- setValidSchema({});
1594
- hasSchema = false;
1595
- return store;
1596
- };
1657
+ const delRow = (tableId, rowId) =>
1658
+ fluentTransaction(() =>
1659
+ ifNotUndefined(mapGet(tablesMap, tableId), (tableMap) =>
1660
+ collHas(tableMap, rowId) ? delValidRow(tableId, tableMap, rowId) : 0,
1661
+ ),
1662
+ );
1663
+ const delCell = (tableId, rowId, cellId, forceDel) =>
1664
+ fluentTransaction(() =>
1665
+ ifNotUndefined(mapGet(tablesMap, tableId), (tableMap) =>
1666
+ ifNotUndefined(mapGet(tableMap, rowId), (rowMap) =>
1667
+ collHas(rowMap, cellId)
1668
+ ? delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel)
1669
+ : 0,
1670
+ ),
1671
+ ),
1672
+ );
1673
+ const delSchema = () =>
1674
+ fluentTransaction(() => {
1675
+ setValidSchema({});
1676
+ hasSchema = false;
1677
+ });
1597
1678
  const transaction = (actions) => {
1598
1679
  if (transactions == -1) {
1599
1680
  return;
1600
1681
  }
1601
1682
  transactions++;
1602
- const result = actions();
1683
+ const result = actions?.();
1603
1684
  transactions--;
1604
1685
  if (transactions == 0) {
1605
1686
  transactions = 1;
1687
+ callInvalidCellListeners(1);
1606
1688
  callListenersForChanges(1);
1607
1689
  transactions = -1;
1690
+ callInvalidCellListeners(0);
1608
1691
  callListenersForChanges(0);
1609
1692
  transactions = 0;
1610
1693
  arrayForEach(
1611
- [changedCells, changedTableIds, changedRowIds, changedCellIds],
1694
+ [
1695
+ changedCells,
1696
+ invalidCells,
1697
+ changedTableIds,
1698
+ changedRowIds,
1699
+ changedCellIds,
1700
+ ],
1612
1701
  collClear,
1613
1702
  );
1614
1703
  }
@@ -1648,6 +1737,12 @@ const createStore = () => {
1648
1737
  rowId,
1649
1738
  cellId,
1650
1739
  ]);
1740
+ const addInvalidCellListener = (tableId, rowId, cellId, listener, mutator) =>
1741
+ addListener(listener, invalidCellListeners[mutator ? 1 : 0], [
1742
+ tableId,
1743
+ rowId,
1744
+ cellId,
1745
+ ]);
1651
1746
  const callListener = (listenerId) => {
1652
1747
  callListenerImpl(listenerId, [getTableIds, getRowIds, getCellIds], (ids) =>
1653
1748
  isUndefined(ids[2]) ? [] : Array(2).fill(getCell(...ids)),
@@ -1705,6 +1800,7 @@ const createStore = () => {
1705
1800
  addRowListener,
1706
1801
  addCellIdsListener,
1707
1802
  addCellListener,
1803
+ addInvalidCellListener,
1708
1804
  callListener,
1709
1805
  delListener,
1710
1806
  getListenerStats,