tinybase 1.0.5 → 1.1.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.
@@ -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) =>
@@ -254,7 +256,7 @@ const getListenerFunctions = (getThing) => {
254
256
  const allListeners = mapNew();
255
257
  const addListener = (listener, deepSet, idOrNulls = []) => {
256
258
  thing ??= getThing();
257
- const id = listenerPool.pop() ?? '' + nextId++;
259
+ const id = arrayPop(listenerPool) ?? '' + nextId++;
258
260
  mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
259
261
  addDeepSet(deepSet, id, idOrNulls);
260
262
  return id;
@@ -275,7 +277,7 @@ const getListenerFunctions = (getThing) => {
275
277
  forDeepSet(collDel)(deepSet, id, ...idOrNulls);
276
278
  mapSet(allListeners, id);
277
279
  if (arrayLength(listenerPool) < 1e3) {
278
- listenerPool.push(id);
280
+ arrayPush(listenerPool, id);
279
281
  }
280
282
  return idOrNulls;
281
283
  },
@@ -361,7 +363,7 @@ const createCheckpoints = getCreateFunction((store) => {
361
363
  (_store, tableId, rowId, cellId, newCell, oldCell) => {
362
364
  if (listening) {
363
365
  ifNotUndefined(currentId, () => {
364
- backwardIds.push(currentId);
366
+ arrayPush(backwardIds, currentId);
365
367
  trimBackwardsIds();
366
368
  clearCheckpointIds(forwardIds);
367
369
  currentId = void 0;
@@ -380,7 +382,7 @@ const createCheckpoints = getCreateFunction((store) => {
380
382
  if (collIsEmpty(mapSet(row, cellId))) {
381
383
  if (collIsEmpty(mapSet(table, rowId))) {
382
384
  if (collIsEmpty(mapSet(delta, tableId))) {
383
- currentId = backwardIds.pop();
385
+ currentId = arrayPop(backwardIds);
384
386
  checkpointsChanged = 1;
385
387
  }
386
388
  }
@@ -404,13 +406,13 @@ const createCheckpoints = getCreateFunction((store) => {
404
406
  if (!arrayIsEmpty(backwardIds)) {
405
407
  forwardIds.unshift(addCheckpointImpl());
406
408
  updateStore(0, currentId);
407
- currentId = backwardIds.pop();
409
+ currentId = arrayPop(backwardIds);
408
410
  checkpointsChanged = 1;
409
411
  }
410
412
  };
411
413
  const goForwardImpl = () => {
412
414
  if (!arrayIsEmpty(forwardIds)) {
413
- backwardIds.push(currentId);
415
+ arrayPush(backwardIds, currentId);
414
416
  currentId = forwardIds.shift();
415
417
  updateStore(1, currentId);
416
418
  checkpointsChanged = 1;
@@ -1212,8 +1214,9 @@ const getCellType = (cell) => {
1212
1214
  ? type
1213
1215
  : void 0;
1214
1216
  };
1215
- const validate = (obj, validateChild) => {
1216
- 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?.();
1217
1220
  return false;
1218
1221
  }
1219
1222
  objForEach(obj, (child, id) => {
@@ -1233,8 +1236,9 @@ const createStore = () => {
1233
1236
  const changedRowIds = mapNew();
1234
1237
  const changedCellIds = mapNew();
1235
1238
  const changedCells = mapNew();
1239
+ const invalidCells = mapNew();
1236
1240
  const schemaMap = mapNew();
1237
- const schemaDefaultRows = mapNew();
1241
+ const schemaRowCache = mapNew();
1238
1242
  const tablesMap = mapNew();
1239
1243
  const tablesListeners = mapNewPair(setNew);
1240
1244
  const tableIdsListeners = mapNewPair(setNew);
@@ -1243,6 +1247,7 @@ const createStore = () => {
1243
1247
  const rowListeners = mapNewPair();
1244
1248
  const cellIdsListeners = mapNewPair();
1245
1249
  const cellListeners = mapNewPair();
1250
+ const invalidCellListeners = mapNewPair();
1246
1251
  const [addListener, callListeners, delListenerImpl, callListenerImpl] =
1247
1252
  getListenerFunctions(() => store);
1248
1253
  const validateSchema = (schema) =>
@@ -1263,40 +1268,57 @@ const createStore = () => {
1263
1268
  return true;
1264
1269
  }),
1265
1270
  );
1266
- const validateTables = (tables) => validate(tables, validateTable);
1271
+ const validateTables = (tables) =>
1272
+ validate(tables, validateTable, cellInvalid);
1267
1273
  const validateTable = (table, tableId) =>
1268
- (!hasSchema || collHas(schemaMap, tableId)) &&
1269
- validate(table, (row) => validateRow(tableId, row));
1270
- const validateRow = (tableId, row, skipDefaults) =>
1274
+ (!hasSchema || collHas(schemaMap, tableId) || cellInvalid(tableId)) &&
1271
1275
  validate(
1272
- 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),
1273
1283
  (cell, cellId) =>
1274
1284
  ifNotUndefined(
1275
- getValidatedCell(tableId, cellId, cell),
1285
+ getValidatedCell(tableId, rowId, cellId, cell),
1276
1286
  (validCell) => {
1277
1287
  row[cellId] = validCell;
1278
1288
  return true;
1279
1289
  },
1280
1290
  () => false,
1281
1291
  ),
1292
+ () => cellInvalid(tableId, rowId),
1282
1293
  );
1283
- const getValidatedCell = (tableId, cellId, cell) =>
1294
+ const getValidatedCell = (tableId, rowId, cellId, cell) =>
1284
1295
  hasSchema
1285
1296
  ? ifNotUndefined(
1286
1297
  mapGet(mapGet(schemaMap, tableId), cellId),
1287
1298
  (cellSchema) =>
1288
- 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),
1289
1303
  )
1290
1304
  : isUndefined(getCellType(cell))
1291
- ? void 0
1305
+ ? cellInvalid(tableId, rowId, cellId, cell)
1292
1306
  : cell;
1293
- const addDefaultsToRow = (row, tableId) => {
1294
- ifNotUndefined(mapGet(schemaDefaultRows, tableId), (defaultRow) =>
1295
- objForEach(defaultRow, (cell, cellId) => {
1296
- if (!objHas(row, cellId)) {
1297
- row[cellId] = cell;
1298
- }
1299
- }),
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
+ },
1300
1322
  );
1301
1323
  return row;
1302
1324
  };
@@ -1305,7 +1327,8 @@ const createStore = () => {
1305
1327
  schemaMap,
1306
1328
  schema,
1307
1329
  (_schema, tableId, tableSchema) => {
1308
- const defaultRow = {};
1330
+ const rowDefaulted = mapNew();
1331
+ const rowNonDefaulted = setNew();
1309
1332
  transformMap(
1310
1333
  mapEnsure(schemaMap, tableId, mapNew()),
1311
1334
  tableSchema,
@@ -1313,15 +1336,16 @@ const createStore = () => {
1313
1336
  mapSet(tableSchemaMap, cellId, cellSchema);
1314
1337
  ifNotUndefined(
1315
1338
  cellSchema[DEFAULT],
1316
- (def) => (defaultRow[cellId] = def),
1339
+ (def) => mapSet(rowDefaulted, cellId, def),
1340
+ () => setAdd(rowNonDefaulted, cellId),
1317
1341
  );
1318
1342
  },
1319
1343
  );
1320
- mapSet(schemaDefaultRows, tableId, defaultRow);
1344
+ mapSet(schemaRowCache, tableId, [rowDefaulted, rowNonDefaulted]);
1321
1345
  },
1322
1346
  (_schema, tableId) => {
1323
1347
  mapSet(schemaMap, tableId);
1324
- mapSet(schemaDefaultRows, tableId);
1348
+ mapSet(schemaRowCache, tableId);
1325
1349
  },
1326
1350
  );
1327
1351
  const setValidTables = (tables) =>
@@ -1361,10 +1385,6 @@ const createStore = () => {
1361
1385
  mapSet(rowMap, cellId, newCell);
1362
1386
  }
1363
1387
  };
1364
- const setValidRowTransaction = (tableId, rowId, row) =>
1365
- transaction(() =>
1366
- setValidRow(tableId, getOrCreateTable(tableId), rowId, row),
1367
- );
1368
1388
  const setCellIntoDefaultRow = (tableId, tableMap, rowId, cellId, validCell) =>
1369
1389
  ifNotUndefined(
1370
1390
  mapGet(tableMap, rowId),
@@ -1374,7 +1394,7 @@ const createStore = () => {
1374
1394
  tableId,
1375
1395
  tableMap,
1376
1396
  rowId,
1377
- addDefaultsToRow({[cellId]: validCell}, tableId),
1397
+ addDefaultsToRow({[cellId]: validCell}, tableId, rowId),
1378
1398
  ),
1379
1399
  );
1380
1400
  const getNewRowId = (tableMap) => {
@@ -1390,7 +1410,7 @@ const createStore = () => {
1390
1410
  const delValidRow = (tableId, tableMap, rowId) =>
1391
1411
  setValidRow(tableId, tableMap, rowId, {}, true);
1392
1412
  const delValidCell = (tableId, table, rowId, row, cellId, forceDel) => {
1393
- const defaultCell = mapGet(schemaDefaultRows, tableId)?.[cellId];
1413
+ const defaultCell = mapGet(mapGet(schemaRowCache, tableId)?.[0], cellId);
1394
1414
  if (!isUndefined(defaultCell) && !forceDel) {
1395
1415
  return setValidCell(tableId, rowId, row, cellId, defaultCell);
1396
1416
  }
@@ -1424,6 +1444,17 @@ const createStore = () => {
1424
1444
  cellId,
1425
1445
  oldCell,
1426
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
+ };
1427
1458
  const getCellChange = (tableId, rowId, cellId) => {
1428
1459
  const changedRow = mapGet(mapGet(changedCells, tableId), rowId);
1429
1460
  const newCell = getCell(tableId, rowId, cellId);
@@ -1431,80 +1462,103 @@ const createStore = () => {
1431
1462
  ? [true, mapGet(changedRow, cellId), newCell]
1432
1463
  : [false, newCell, newCell];
1433
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;
1434
1483
  const callListenersForChanges = (mutator) => {
1435
- const emptyIdListeners =
1436
- collIsEmpty(cellIdsListeners[mutator]) &&
1437
- collIsEmpty(rowIdsListeners[mutator]) &&
1438
- collIsEmpty(tableIdsListeners[mutator]);
1439
- const emptyOtherListeners =
1440
- collIsEmpty(cellListeners[mutator]) &&
1441
- collIsEmpty(rowListeners[mutator]) &&
1442
- collIsEmpty(tableListeners[mutator]) &&
1443
- collIsEmpty(tablesListeners[mutator]);
1444
- if (emptyIdListeners && emptyOtherListeners) {
1445
- return;
1446
- }
1447
- const changes = mutator
1448
- ? [
1449
- mapClone(changedTableIds),
1450
- mapClone(changedRowIds, mapClone),
1451
- mapClone(changedCellIds, (table) => mapClone(table, mapClone)),
1452
- mapClone(changedCells, (table) => mapClone(table, mapClone)),
1453
- ]
1454
- : [changedTableIds, changedRowIds, changedCellIds, changedCells];
1455
- if (!emptyIdListeners) {
1456
- collForEach(changes[2], (rowCellIds, tableId) =>
1457
- collForEach(rowCellIds, (changedIds, rowId) => {
1458
- if (!collIsEmpty(changedIds)) {
1459
- 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]);
1460
1518
  }
1461
- }),
1462
- );
1463
- collForEach(changes[1], (changedIds, tableId) => {
1464
- if (!collIsEmpty(changedIds)) {
1465
- callListeners(rowIdsListeners[mutator], [tableId]);
1466
1519
  }
1467
- });
1468
- if (!collIsEmpty(changes[0])) {
1469
- callListeners(tableIdsListeners[mutator]);
1470
- }
1471
- }
1472
- if (!emptyOtherListeners) {
1473
- let tablesChanged;
1474
- collForEach(changes[3], (rows, tableId) => {
1475
- let tableChanged;
1476
- collForEach(rows, (cells, rowId) => {
1477
- let rowChanged;
1478
- collForEach(cells, (oldCell, cellId) => {
1479
- const newCell = getCell(tableId, rowId, cellId);
1480
- if (newCell !== oldCell) {
1481
- callListeners(
1482
- cellListeners[mutator],
1483
- [tableId, rowId, cellId],
1484
- newCell,
1485
- oldCell,
1486
- getCellChange,
1487
- );
1488
- 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);
1489
1549
  }
1490
1550
  });
1491
- if (rowChanged) {
1492
- callListeners(
1493
- rowListeners[mutator],
1494
- [tableId, rowId],
1495
- getCellChange,
1496
- );
1551
+ if (tablesChanged) {
1552
+ callListeners(tablesListeners[mutator], [], getCellChange);
1497
1553
  }
1498
- });
1499
- if (tableChanged) {
1500
- callListeners(tableListeners[mutator], [tableId], getCellChange);
1501
1554
  }
1502
- });
1503
- if (tablesChanged) {
1504
- callListeners(tablesListeners[mutator], [], getCellChange);
1505
1555
  }
1506
1556
  }
1507
1557
  };
1558
+ const fluentTransaction = (actions) => {
1559
+ transaction(actions);
1560
+ return store;
1561
+ };
1508
1562
  const getTables = () =>
1509
1563
  mapToObj(tablesMap, (tableMap) => mapToObj(tableMap, mapToObj));
1510
1564
  const getTableIds = () => mapKeys(tablesMap);
@@ -1523,52 +1577,52 @@ const createStore = () => {
1523
1577
  collHas(mapGet(mapGet(tablesMap, tableId), rowId), cellId);
1524
1578
  const getJson = () => jsonString(tablesMap);
1525
1579
  const getSchemaJson = () => jsonString(schemaMap);
1526
- const setTables = (tables) => {
1527
- if (validateTables(tables)) {
1528
- transaction(() => setValidTables(tables));
1529
- }
1530
- return store;
1531
- };
1532
- const setTable = (tableId, table) => {
1533
- if (validateTable(table, tableId)) {
1534
- transaction(() => setValidTable(tableId, table));
1535
- }
1536
- return store;
1537
- };
1538
- const setRow = (tableId, rowId, row) => {
1539
- if (validateRow(tableId, row)) {
1540
- setValidRowTransaction(tableId, rowId, row);
1541
- }
1542
- return store;
1543
- };
1544
- const addRow = (tableId, row) => {
1545
- let rowId = void 0;
1546
- if (validateRow(tableId, row)) {
1547
- rowId = getNewRowId(mapGet(tablesMap, tableId));
1548
- setValidRowTransaction(tableId, rowId, row);
1549
- }
1550
- return rowId;
1551
- };
1552
- const setPartialRow = (tableId, rowId, partialRow) => {
1553
- if (validateRow(tableId, partialRow, 1)) {
1554
- 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)) {
1555
1610
  const table = getOrCreateTable(tableId);
1556
1611
  objForEach(partialRow, (cell, cellId) =>
1557
1612
  setCellIntoDefaultRow(tableId, table, rowId, cellId, cell),
1558
1613
  );
1559
- });
1560
- }
1561
- return store;
1562
- };
1563
- const setCell = (tableId, rowId, cellId, cell) => {
1564
- ifNotUndefined(
1565
- getValidatedCell(
1566
- tableId,
1567
- cellId,
1568
- isFunction(cell) ? cell(getCell(tableId, rowId, cellId)) : cell,
1569
- ),
1570
- (validCell) =>
1571
- 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) =>
1572
1626
  setCellIntoDefaultRow(
1573
1627
  tableId,
1574
1628
  getOrCreateTable(tableId),
@@ -1576,77 +1630,74 @@ const createStore = () => {
1576
1630
  cellId,
1577
1631
  validCell,
1578
1632
  ),
1579
- ),
1633
+ ),
1580
1634
  );
1581
- return store;
1582
- };
1583
1635
  const setJson = (json) => {
1584
1636
  try {
1585
1637
  json === EMPTY_OBJECT ? delTables() : setTables(jsonParse(json));
1586
1638
  } catch {}
1587
1639
  return store;
1588
1640
  };
1589
- const setSchema = (schema) => {
1590
- if ((hasSchema = validateSchema(schema))) {
1591
- setValidSchema(schema);
1592
- if (!collIsEmpty(tablesMap)) {
1593
- const tables = getTables();
1594
- delTables();
1595
- setTables(tables);
1596
- }
1597
- }
1598
- return store;
1599
- };
1600
- const delTables = () => {
1601
- transaction(() => setValidTables({}));
1602
- return store;
1603
- };
1604
- const delTable = (tableId) => {
1605
- if (collHas(tablesMap, tableId)) {
1606
- transaction(() => delValidTable(tableId));
1607
- }
1608
- return store;
1609
- };
1610
- const delRow = (tableId, rowId) => {
1611
- ifNotUndefined(mapGet(tablesMap, tableId), (tableMap) => {
1612
- if (collHas(tableMap, rowId)) {
1613
- 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
+ }
1614
1650
  }
1615
1651
  });
1616
- return store;
1617
- };
1618
- const delCell = (tableId, rowId, cellId, forceDel) => {
1619
- ifNotUndefined(mapGet(tablesMap, tableId), (tableMap) =>
1620
- ifNotUndefined(mapGet(tableMap, rowId), (rowMap) => {
1621
- if (collHas(rowMap, cellId)) {
1622
- transaction(() =>
1623
- delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel),
1624
- );
1625
- }
1626
- }),
1652
+ const delTables = () => fluentTransaction(() => setValidTables({}));
1653
+ const delTable = (tableId) =>
1654
+ fluentTransaction(() =>
1655
+ collHas(tablesMap, tableId) ? delValidTable(tableId) : 0,
1627
1656
  );
1628
- return store;
1629
- };
1630
- const delSchema = () => {
1631
- setValidSchema({});
1632
- hasSchema = false;
1633
- return store;
1634
- };
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
+ });
1635
1678
  const transaction = (actions) => {
1636
1679
  if (transactions == -1) {
1637
1680
  return;
1638
1681
  }
1639
1682
  transactions++;
1640
- const result = actions();
1683
+ const result = actions?.();
1641
1684
  transactions--;
1642
1685
  if (transactions == 0) {
1643
1686
  transactions = 1;
1687
+ callInvalidCellListeners(1);
1644
1688
  callListenersForChanges(1);
1645
1689
  transactions = -1;
1690
+ callInvalidCellListeners(0);
1646
1691
  callListenersForChanges(0);
1647
1692
  transactions = 0;
1648
1693
  arrayForEach(
1649
- [changedCells, changedTableIds, changedRowIds, changedCellIds],
1694
+ [
1695
+ changedCells,
1696
+ invalidCells,
1697
+ changedTableIds,
1698
+ changedRowIds,
1699
+ changedCellIds,
1700
+ ],
1650
1701
  collClear,
1651
1702
  );
1652
1703
  }
@@ -1686,6 +1737,12 @@ const createStore = () => {
1686
1737
  rowId,
1687
1738
  cellId,
1688
1739
  ]);
1740
+ const addInvalidCellListener = (tableId, rowId, cellId, listener, mutator) =>
1741
+ addListener(listener, invalidCellListeners[mutator ? 1 : 0], [
1742
+ tableId,
1743
+ rowId,
1744
+ cellId,
1745
+ ]);
1689
1746
  const callListener = (listenerId) => {
1690
1747
  callListenerImpl(listenerId, [getTableIds, getRowIds, getCellIds], (ids) =>
1691
1748
  isUndefined(ids[2]) ? [] : Array(2).fill(getCell(...ids)),
@@ -1743,6 +1800,7 @@ const createStore = () => {
1743
1800
  addRowListener,
1744
1801
  addCellIdsListener,
1745
1802
  addCellListener,
1803
+ addInvalidCellListener,
1746
1804
  callListener,
1747
1805
  delListener,
1748
1806
  getListenerStats,
package/lib/metrics.d.ts CHANGED
@@ -37,7 +37,7 @@ export type Metric = number;
37
37
  export type MetricCallback = (metricId: Id, metric?: Metric) => void;
38
38
 
39
39
  /**
40
- * The Aggregate type describes a custom function that takes an array or numbers
40
+ * The Aggregate type describes a custom function that takes an array of numbers
41
41
  * and returns an aggregate that is used as a Metric.
42
42
  *
43
43
  * There are a number of common predefined aggregators, such as for counting,