tinybase 3.0.0-beta.0 → 3.0.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 (110) hide show
  1. package/bin/cli.js +1 -1
  2. package/lib/checkpoints.d.ts +18 -3
  3. package/lib/checkpoints.js +1 -1
  4. package/lib/checkpoints.js.gz +0 -0
  5. package/lib/debug/checkpoints.d.ts +18 -3
  6. package/lib/debug/checkpoints.js +97 -49
  7. package/lib/debug/indexes.js +31 -16
  8. package/lib/debug/metrics.js +31 -16
  9. package/lib/debug/persisters.d.ts +33 -23
  10. package/lib/debug/persisters.js +10 -5
  11. package/lib/debug/queries.js +2 -2
  12. package/lib/debug/relationships.js +31 -16
  13. package/lib/debug/store.d.ts +2053 -381
  14. package/lib/debug/store.js +444 -106
  15. package/lib/debug/tinybase.js +512 -138
  16. package/lib/debug/tools.d.ts +109 -38
  17. package/lib/debug/tools.js +759 -453
  18. package/lib/debug/ui-react.d.ts +1218 -138
  19. package/lib/debug/ui-react.js +163 -12
  20. package/lib/es6/checkpoints.d.ts +18 -3
  21. package/lib/es6/checkpoints.js +1 -1
  22. package/lib/es6/checkpoints.js.gz +0 -0
  23. package/lib/es6/indexes.js +1 -1
  24. package/lib/es6/indexes.js.gz +0 -0
  25. package/lib/es6/metrics.js +1 -1
  26. package/lib/es6/metrics.js.gz +0 -0
  27. package/lib/es6/persisters.d.ts +33 -23
  28. package/lib/es6/persisters.js +1 -1
  29. package/lib/es6/persisters.js.gz +0 -0
  30. package/lib/es6/relationships.js +1 -1
  31. package/lib/es6/relationships.js.gz +0 -0
  32. package/lib/es6/store.d.ts +2053 -381
  33. package/lib/es6/store.js +1 -1
  34. package/lib/es6/store.js.gz +0 -0
  35. package/lib/es6/tinybase.js +1 -1
  36. package/lib/es6/tinybase.js.gz +0 -0
  37. package/lib/es6/tools.d.ts +109 -38
  38. package/lib/es6/tools.js +1 -1
  39. package/lib/es6/tools.js.gz +0 -0
  40. package/lib/es6/ui-react.d.ts +1218 -138
  41. package/lib/es6/ui-react.js +1 -1
  42. package/lib/es6/ui-react.js.gz +0 -0
  43. package/lib/indexes.js +1 -1
  44. package/lib/indexes.js.gz +0 -0
  45. package/lib/metrics.js +1 -1
  46. package/lib/metrics.js.gz +0 -0
  47. package/lib/persisters.d.ts +33 -23
  48. package/lib/persisters.js +1 -1
  49. package/lib/persisters.js.gz +0 -0
  50. package/lib/relationships.js +1 -1
  51. package/lib/relationships.js.gz +0 -0
  52. package/lib/store.d.ts +2053 -381
  53. package/lib/store.js +1 -1
  54. package/lib/store.js.gz +0 -0
  55. package/lib/tinybase.js +1 -1
  56. package/lib/tinybase.js.gz +0 -0
  57. package/lib/tools.d.ts +109 -38
  58. package/lib/tools.js +1 -1
  59. package/lib/tools.js.gz +0 -0
  60. package/lib/ui-react.d.ts +1218 -138
  61. package/lib/ui-react.js +1 -1
  62. package/lib/ui-react.js.gz +0 -0
  63. package/lib/umd/checkpoints.d.ts +18 -3
  64. package/lib/umd/checkpoints.js +1 -1
  65. package/lib/umd/checkpoints.js.gz +0 -0
  66. package/lib/umd/indexes.js +1 -1
  67. package/lib/umd/indexes.js.gz +0 -0
  68. package/lib/umd/metrics.js +1 -1
  69. package/lib/umd/metrics.js.gz +0 -0
  70. package/lib/umd/persisters.d.ts +33 -23
  71. package/lib/umd/persisters.js +1 -1
  72. package/lib/umd/persisters.js.gz +0 -0
  73. package/lib/umd/relationships.js +1 -1
  74. package/lib/umd/relationships.js.gz +0 -0
  75. package/lib/umd/store.d.ts +2053 -381
  76. package/lib/umd/store.js +1 -1
  77. package/lib/umd/store.js.gz +0 -0
  78. package/lib/umd/tinybase.js +1 -1
  79. package/lib/umd/tinybase.js.gz +0 -0
  80. package/lib/umd/tools.d.ts +109 -38
  81. package/lib/umd/tools.js +1 -1
  82. package/lib/umd/tools.js.gz +0 -0
  83. package/lib/umd/ui-react.d.ts +1218 -138
  84. package/lib/umd/ui-react.js +1 -1
  85. package/lib/umd/ui-react.js.gz +0 -0
  86. package/lib/umd-es6/checkpoints.d.ts +18 -3
  87. package/lib/umd-es6/checkpoints.js +1 -1
  88. package/lib/umd-es6/checkpoints.js.gz +0 -0
  89. package/lib/umd-es6/indexes.js +1 -1
  90. package/lib/umd-es6/indexes.js.gz +0 -0
  91. package/lib/umd-es6/metrics.js +1 -1
  92. package/lib/umd-es6/metrics.js.gz +0 -0
  93. package/lib/umd-es6/persisters.d.ts +33 -23
  94. package/lib/umd-es6/persisters.js +1 -1
  95. package/lib/umd-es6/persisters.js.gz +0 -0
  96. package/lib/umd-es6/relationships.js +1 -1
  97. package/lib/umd-es6/relationships.js.gz +0 -0
  98. package/lib/umd-es6/store.d.ts +2053 -381
  99. package/lib/umd-es6/store.js +1 -1
  100. package/lib/umd-es6/store.js.gz +0 -0
  101. package/lib/umd-es6/tinybase.js +1 -1
  102. package/lib/umd-es6/tinybase.js.gz +0 -0
  103. package/lib/umd-es6/tools.d.ts +109 -38
  104. package/lib/umd-es6/tools.js +1 -1
  105. package/lib/umd-es6/tools.js.gz +0 -0
  106. package/lib/umd-es6/ui-react.d.ts +1218 -138
  107. package/lib/umd-es6/ui-react.js +1 -1
  108. package/lib/umd-es6/ui-react.js.gz +0 -0
  109. package/package.json +20 -20
  110. package/readme.md +27 -16
@@ -1,5 +1,4 @@
1
1
  const getTypeOf = (thing) => typeof thing;
2
- const EMPTY_OBJECT = '{}';
3
2
  const EMPTY_STRING = '';
4
3
  const STRING = getTypeOf(EMPTY_STRING);
5
4
  const BOOLEAN = getTypeOf(true);
@@ -16,6 +15,9 @@ const ROW_IDS = 'RowIds';
16
15
  const ROW = 'Row';
17
16
  const CELL_IDS = 'CellIds';
18
17
  const CELL = 'Cell';
18
+ const VALUES = 'Values';
19
+ const VALUE_IDS = 'ValueIds';
20
+ const VALUE = 'Value';
19
21
  const id = (key) => EMPTY_STRING + key;
20
22
 
21
23
  const arrayHas = (array, value) => array.includes(value);
@@ -125,19 +127,6 @@ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
125
127
  },
126
128
  );
127
129
 
128
- const object = Object;
129
- const objIds = object.keys;
130
- const objFrozen = object.isFrozen;
131
- const objFreeze = object.freeze;
132
- const isObject = (obj) =>
133
- isInstanceOf(obj, object) && obj.constructor == object;
134
- const objGet = (obj, id) => ifNotUndefined(obj, (obj2) => obj2[id]);
135
- const objHas = (obj, id) => !isUndefined(objGet(obj, id));
136
- const objDel = (obj, id) => delete obj[id];
137
- const objMap = (obj, cb) =>
138
- arrayMap(object.entries(obj), ([id, value]) => cb(value, id));
139
- const objIsEmpty = (obj) => arrayIsEmpty(objIds(obj));
140
-
141
130
  const setNew = (entryOrEntries) =>
142
131
  new Set(
143
132
  isArray(entryOrEntries) || isUndefined(entryOrEntries)
@@ -175,10 +164,22 @@ const getListenerFunctions = (getThing) => {
175
164
  let thing;
176
165
  const [getId, releaseId] = getPoolFunctions();
177
166
  const allListeners = mapNew();
178
- const addListener = (listener, idSetNode, path) => {
167
+ const addListener = (
168
+ listener,
169
+ idSetNode,
170
+ path,
171
+ pathGetters = [],
172
+ extraArgsGetter = () => [],
173
+ ) => {
179
174
  thing ??= getThing();
180
175
  const id = getId();
181
- mapSet(allListeners, id, [listener, idSetNode, path]);
176
+ mapSet(allListeners, id, [
177
+ listener,
178
+ idSetNode,
179
+ path,
180
+ pathGetters,
181
+ extraArgsGetter,
182
+ ]);
182
183
  setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
183
184
  return id;
184
185
  };
@@ -198,28 +199,44 @@ const getListenerFunctions = (getThing) => {
198
199
  releaseId(id);
199
200
  return idOrNulls;
200
201
  });
201
- const callListener = (id, idNullGetters, extraArgsGetter) =>
202
- ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls = []]) => {
203
- const callWithIds = (...ids) => {
204
- const index = arrayLength(ids);
205
- index == arrayLength(idOrNulls)
206
- ? listener(thing, ...ids, ...extraArgsGetter(ids))
207
- : isUndefined(idOrNulls[index])
208
- ? arrayForEach(idNullGetters[index](...ids), (id2) =>
209
- callWithIds(...ids, id2),
210
- )
211
- : callWithIds(...ids, idOrNulls[index]);
212
- };
213
- callWithIds();
214
- });
202
+ const callListener = (id) =>
203
+ ifNotUndefined(
204
+ mapGet(allListeners, id),
205
+ ([listener, , path = [], pathGetters, extraArgsGetter]) => {
206
+ const callWithIds = (...ids) => {
207
+ const index = arrayLength(ids);
208
+ index == arrayLength(path)
209
+ ? listener(thing, ...ids, ...extraArgsGetter(ids))
210
+ : isUndefined(path[index])
211
+ ? arrayForEach(pathGetters[index]?.(...ids) ?? [], (id2) =>
212
+ callWithIds(...ids, id2),
213
+ )
214
+ : callWithIds(...ids, path[index]);
215
+ };
216
+ callWithIds();
217
+ },
218
+ );
215
219
  return [addListener, callListeners, delListener, callListener];
216
220
  };
217
221
 
222
+ const object = Object;
223
+ const objIds = object.keys;
224
+ const objFrozen = object.isFrozen;
225
+ const objFreeze = object.freeze;
226
+ const isObject = (obj) =>
227
+ isInstanceOf(obj, object) && obj.constructor == object;
228
+ const objGet = (obj, id) => ifNotUndefined(obj, (obj2) => obj2[id]);
229
+ const objHas = (obj, id) => !isUndefined(objGet(obj, id));
230
+ const objDel = (obj, id) => delete obj[id];
231
+ const objMap = (obj, cb) =>
232
+ arrayMap(object.entries(obj), ([id, value]) => cb(value, id));
233
+ const objIsEmpty = (obj) => isObject(obj) && arrayIsEmpty(objIds(obj));
234
+
218
235
  const pairNew = (value) => [value, value];
219
236
  const pairCollSize2 = (pair, func = collSize2) => func(pair[0]) + func(pair[1]);
220
237
  const pairNewMap = () => [mapNew(), mapNew()];
221
238
 
222
- const getCellType = (cell) => {
239
+ const getCellOrValueType = (cell) => {
223
240
  const type = getTypeOf(cell);
224
241
  return isTypeStringOrBoolean(type) || (type == NUMBER && isFiniteNumber(cell))
225
242
  ? type
@@ -229,6 +246,8 @@ const setOrDelCell = (store, tableId, rowId, cellId, cell) =>
229
246
  isUndefined(cell)
230
247
  ? store.delCell(tableId, rowId, cellId, true)
231
248
  : store.setCell(tableId, rowId, cellId, cell);
249
+ const setOrDelValue = (store, valueId, value) =>
250
+ isUndefined(value) ? store.delValue(valueId) : store.setValue(valueId, value);
232
251
 
233
252
  const defaultSorter = (sortKey1, sortKey2) => (sortKey1 < sortKey2 ? -1 : 1);
234
253
 
@@ -258,18 +277,27 @@ const validate = (obj, validateChild, onInvalidObj) => {
258
277
  const idsChanged = (changedIds, id2, added) =>
259
278
  mapSet(changedIds, id2, mapGet(changedIds, id2) == -added ? void 0 : added);
260
279
  const createStore = () => {
261
- let hasSchema;
280
+ let hasTablesSchema;
281
+ let hasValuesSchema;
262
282
  let cellsTouched;
283
+ let valuesTouched;
263
284
  let transactions = 0;
264
285
  const changedTableIds = mapNew();
265
286
  const changedRowIds = mapNew();
266
287
  const changedCellIds = mapNew();
267
288
  const changedCells = mapNew();
289
+ const changedValueIds = mapNew();
290
+ const changedValues = mapNew();
268
291
  const invalidCells = mapNew();
269
- const schemaMap = mapNew();
270
- const schemaRowCache = mapNew();
292
+ const invalidValues = mapNew();
293
+ const tablesSchemaMap = mapNew();
294
+ const tablesSchemaRowCache = mapNew();
295
+ const valuesSchemaMap = mapNew();
296
+ const valuesDefaulted = mapNew();
297
+ const valuesNonDefaulted = setNew();
271
298
  const tablePoolFunctions = mapNew();
272
299
  const tablesMap = mapNew();
300
+ const valuesMap = mapNew();
273
301
  const tablesListeners = pairNewMap();
274
302
  const tableIdsListeners = pairNewMap();
275
303
  const tableListeners = pairNewMap();
@@ -279,31 +307,38 @@ const createStore = () => {
279
307
  const cellIdsListeners = pairNewMap();
280
308
  const cellListeners = pairNewMap();
281
309
  const invalidCellListeners = pairNewMap();
310
+ const invalidValueListeners = pairNewMap();
311
+ const valuesListeners = pairNewMap();
312
+ const valueIdsListeners = pairNewMap();
313
+ const valueListeners = pairNewMap();
282
314
  const finishTransactionListeners = pairNewMap();
283
315
  const [addListener, callListeners, delListenerImpl, callListenerImpl] =
284
316
  getListenerFunctions(() => store);
285
- const validateSchema = (schema) =>
286
- validate(schema, (tableSchema) =>
287
- validate(tableSchema, (cellSchema) => {
288
- if (
289
- !validate(cellSchema, (_child, id2) => arrayHas([TYPE, DEFAULT], id2))
290
- ) {
291
- return false;
292
- }
293
- const type = cellSchema[TYPE];
294
- if (!isTypeStringOrBoolean(type) && type != NUMBER) {
295
- return false;
296
- }
297
- if (getCellType(cellSchema[DEFAULT]) != type) {
298
- objDel(cellSchema, DEFAULT);
299
- }
300
- return true;
301
- }),
317
+ const validateTablesSchema = (tableSchema) =>
318
+ validate(tableSchema, (tableSchema2) =>
319
+ validate(tableSchema2, validateCellOrValueSchema),
302
320
  );
321
+ const validateValuesSchema = (valuesSchema) =>
322
+ validate(valuesSchema, validateCellOrValueSchema);
323
+ const validateCellOrValueSchema = (schema) => {
324
+ if (!validate(schema, (_child, id2) => arrayHas([TYPE, DEFAULT], id2))) {
325
+ return false;
326
+ }
327
+ const type = schema[TYPE];
328
+ if (!isTypeStringOrBoolean(type) && type != NUMBER) {
329
+ return false;
330
+ }
331
+ if (getCellOrValueType(schema[DEFAULT]) != type) {
332
+ objDel(schema, DEFAULT);
333
+ }
334
+ return true;
335
+ };
303
336
  const validateTables = (tables) =>
304
337
  validate(tables, validateTable, cellInvalid);
305
338
  const validateTable = (table, tableId) =>
306
- (!hasSchema || collHas(schemaMap, tableId) || cellInvalid(tableId)) &&
339
+ (!hasTablesSchema ||
340
+ collHas(tablesSchemaMap, tableId) ||
341
+ cellInvalid(tableId)) &&
307
342
  validate(
308
343
  table,
309
344
  (row, rowId) => validateRow(tableId, rowId, row),
@@ -324,21 +359,48 @@ const createStore = () => {
324
359
  () => cellInvalid(tableId, rowId),
325
360
  );
326
361
  const getValidatedCell = (tableId, rowId, cellId, cell) =>
327
- hasSchema
362
+ hasTablesSchema
328
363
  ? ifNotUndefined(
329
- mapGet(mapGet(schemaMap, tableId), cellId),
364
+ mapGet(mapGet(tablesSchemaMap, tableId), cellId),
330
365
  (cellSchema) =>
331
- getCellType(cell) != cellSchema[TYPE]
366
+ getCellOrValueType(cell) != cellSchema[TYPE]
332
367
  ? cellInvalid(tableId, rowId, cellId, cell, cellSchema[DEFAULT])
333
368
  : cell,
334
369
  () => cellInvalid(tableId, rowId, cellId, cell),
335
370
  )
336
- : isUndefined(getCellType(cell))
371
+ : isUndefined(getCellOrValueType(cell))
337
372
  ? cellInvalid(tableId, rowId, cellId, cell)
338
373
  : cell;
374
+ const validateValues = (values, skipDefaults) =>
375
+ validate(
376
+ skipDefaults ? values : addDefaultsToValues(values),
377
+ (value, valueId) =>
378
+ ifNotUndefined(
379
+ getValidatedValue(valueId, value),
380
+ (validValue) => {
381
+ values[valueId] = validValue;
382
+ return true;
383
+ },
384
+ () => false,
385
+ ),
386
+ () => valueInvalid(),
387
+ );
388
+ const getValidatedValue = (valueId, value) =>
389
+ hasValuesSchema
390
+ ? ifNotUndefined(
391
+ mapGet(valuesSchemaMap, valueId),
392
+ (valueSchema) =>
393
+ getCellOrValueType(value) != valueSchema[TYPE]
394
+ ? valueInvalid(valueId, value, valueSchema[DEFAULT])
395
+ : value,
396
+ () => valueInvalid(valueId, value),
397
+ )
398
+ : isUndefined(getCellOrValueType(value))
399
+ ? valueInvalid(valueId, value)
400
+ : value;
339
401
  const addDefaultsToRow = (row, tableId, rowId) => {
340
402
  ifNotUndefined(
341
- mapGet(schemaRowCache, tableId),
403
+ mapGet(tablesSchemaRowCache, tableId),
342
404
  ([rowDefaulted, rowNonDefaulted]) => {
343
405
  collForEach(rowDefaulted, (cell, cellId) => {
344
406
  if (!objHas(row, cellId)) {
@@ -354,15 +416,30 @@ const createStore = () => {
354
416
  );
355
417
  return row;
356
418
  };
357
- const setValidSchema = (schema) =>
419
+ const addDefaultsToValues = (values) => {
420
+ if (hasValuesSchema) {
421
+ collForEach(valuesDefaulted, (value, valueId) => {
422
+ if (!objHas(values, valueId)) {
423
+ values[valueId] = value;
424
+ }
425
+ });
426
+ collForEach(valuesNonDefaulted, (valueId) => {
427
+ if (!objHas(values, valueId)) {
428
+ valueInvalid(valueId);
429
+ }
430
+ });
431
+ }
432
+ return values;
433
+ };
434
+ const setValidTablesSchema = (tablesSchema) =>
358
435
  transformMap(
359
- schemaMap,
360
- schema,
361
- (_schema, tableId, tableSchema) => {
436
+ tablesSchemaMap,
437
+ tablesSchema,
438
+ (_tablesSchema, tableId, tableSchema) => {
362
439
  const rowDefaulted = mapNew();
363
440
  const rowNonDefaulted = setNew();
364
441
  transformMap(
365
- mapEnsure(schemaMap, tableId, mapNew),
442
+ mapEnsure(tablesSchemaMap, tableId, mapNew),
366
443
  tableSchema,
367
444
  (tableSchemaMap, cellId, cellSchema) => {
368
445
  mapSet(tableSchemaMap, cellId, cellSchema);
@@ -373,13 +450,33 @@ const createStore = () => {
373
450
  );
374
451
  },
375
452
  );
376
- mapSet(schemaRowCache, tableId, [rowDefaulted, rowNonDefaulted]);
453
+ mapSet(tablesSchemaRowCache, tableId, [rowDefaulted, rowNonDefaulted]);
454
+ },
455
+ (_tablesSchema, tableId) => {
456
+ mapSet(tablesSchemaMap, tableId);
457
+ mapSet(tablesSchemaRowCache, tableId);
458
+ },
459
+ );
460
+ const setValidValuesSchema = (valuesSchema) =>
461
+ transformMap(
462
+ valuesSchemaMap,
463
+ valuesSchema,
464
+ (_valuesSchema, valueId, valueSchema) => {
465
+ mapSet(valuesSchemaMap, valueId, valueSchema);
466
+ ifNotUndefined(
467
+ valueSchema[DEFAULT],
468
+ (def) => mapSet(valuesDefaulted, valueId, def),
469
+ () => setAdd(valuesNonDefaulted, valueId),
470
+ );
377
471
  },
378
- (_schema, tableId) => {
379
- mapSet(schemaMap, tableId);
380
- mapSet(schemaRowCache, tableId);
472
+ (_valuesSchema, valueId) => {
473
+ mapSet(valuesSchemaMap, valueId);
474
+ mapSet(valuesDefaulted, valueId);
475
+ collDel(valuesNonDefaulted, valueId);
381
476
  },
382
477
  );
478
+ const setOrDelTables = (tables) =>
479
+ objIsEmpty(tables) ? delTables() : setTables(tables);
383
480
  const setValidTables = (tables) =>
384
481
  transformMap(
385
482
  tablesMap,
@@ -397,26 +494,26 @@ const createStore = () => {
397
494
  (tableMap, rowId, row) => setValidRow(tableId, tableMap, rowId, row),
398
495
  (tableMap, rowId) => delValidRow(tableId, tableMap, rowId),
399
496
  );
400
- const setValidRow = (tableId, tableMap, rowId, newRow, forceDel) =>
497
+ const setValidRow = (tableId, tableMap, rowId, row, forceDel) =>
401
498
  transformMap(
402
499
  mapEnsure(tableMap, rowId, () => {
403
500
  rowIdsChanged(tableId, rowId, 1);
404
501
  return mapNew();
405
502
  }),
406
- newRow,
503
+ row,
407
504
  (rowMap, cellId, cell) =>
408
505
  setValidCell(tableId, rowId, rowMap, cellId, cell),
409
506
  (rowMap, cellId) =>
410
507
  delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel),
411
508
  );
412
- const setValidCell = (tableId, rowId, rowMap, cellId, newCell) => {
509
+ const setValidCell = (tableId, rowId, rowMap, cellId, cell) => {
413
510
  if (!collHas(rowMap, cellId)) {
414
511
  cellIdsChanged(tableId, rowId, cellId, 1);
415
512
  }
416
513
  const oldCell = mapGet(rowMap, cellId);
417
- if (newCell !== oldCell) {
418
- cellChanged(tableId, rowId, cellId, oldCell, newCell);
419
- mapSet(rowMap, cellId, newCell);
514
+ if (cell !== oldCell) {
515
+ cellChanged(tableId, rowId, cellId, oldCell, cell);
516
+ mapSet(rowMap, cellId, cell);
420
517
  }
421
518
  };
422
519
  const setCellIntoDefaultRow = (tableId, tableMap, rowId, cellId, validCell) =>
@@ -431,6 +528,25 @@ const createStore = () => {
431
528
  addDefaultsToRow({[cellId]: validCell}, tableId, rowId),
432
529
  ),
433
530
  );
531
+ const setOrDelValues = (values) =>
532
+ objIsEmpty(values) ? delValues() : setValues(values);
533
+ const setValidValues = (values) =>
534
+ transformMap(
535
+ valuesMap,
536
+ values,
537
+ (_valuesMap, valueId, value) => setValidValue(valueId, value),
538
+ (_valuesMap, valueId) => delValidValue(valueId),
539
+ );
540
+ const setValidValue = (valueId, value) => {
541
+ if (!collHas(valuesMap, valueId)) {
542
+ valueIdsChanged(valueId, 1);
543
+ }
544
+ const oldValue = mapGet(valuesMap, valueId);
545
+ if (value !== oldValue) {
546
+ valueChanged(valueId, oldValue, value);
547
+ mapSet(valuesMap, valueId, value);
548
+ }
549
+ };
434
550
  const getNewRowId = (tableId) => {
435
551
  const [getId] = mapEnsure(tablePoolFunctions, tableId, getPoolFunctions);
436
552
  const rowId = getId();
@@ -452,7 +568,10 @@ const createStore = () => {
452
568
  setValidRow(tableId, tableMap, rowId, {}, true);
453
569
  };
454
570
  const delValidCell = (tableId, table, rowId, row, cellId, forceDel) => {
455
- const defaultCell = mapGet(mapGet(schemaRowCache, tableId)?.[0], cellId);
571
+ const defaultCell = mapGet(
572
+ mapGet(tablesSchemaRowCache, tableId)?.[0],
573
+ cellId,
574
+ );
456
575
  if (!isUndefined(defaultCell) && !forceDel) {
457
576
  return setValidCell(tableId, rowId, row, cellId, defaultCell);
458
577
  }
@@ -471,6 +590,15 @@ const createStore = () => {
471
590
  }
472
591
  }
473
592
  };
593
+ const delValidValue = (valueId) => {
594
+ const defaultValue = mapGet(valuesDefaulted, valueId);
595
+ if (!isUndefined(defaultValue)) {
596
+ return setValidValue(valueId, defaultValue);
597
+ }
598
+ valueChanged(valueId, mapGet(valuesMap, valueId));
599
+ valueIdsChanged(valueId, -1);
600
+ mapSet(valuesMap, valueId);
601
+ };
474
602
  const tableIdsChanged = (tableId, added) =>
475
603
  idsChanged(changedTableIds, tableId, added);
476
604
  const rowIdsChanged = (tableId, rowId, added) =>
@@ -487,6 +615,10 @@ const createStore = () => {
487
615
  cellId,
488
616
  () => [oldCell, 0],
489
617
  )[1] = newCell);
618
+ const valueIdsChanged = (valueId, added) =>
619
+ idsChanged(changedValueIds, valueId, added);
620
+ const valueChanged = (valueId, oldValue, newValue) =>
621
+ (mapEnsure(changedValues, valueId, () => [oldValue, 0])[1] = newValue);
490
622
  const cellInvalid = (tableId, rowId, cellId, invalidCell, defaultedCell) => {
491
623
  arrayPush(
492
624
  mapEnsure(
@@ -498,12 +630,25 @@ const createStore = () => {
498
630
  );
499
631
  return defaultedCell;
500
632
  };
633
+ const valueInvalid = (valueId, invalidValue, defaultedValue) => {
634
+ arrayPush(
635
+ mapEnsure(invalidValues, valueId, () => []),
636
+ invalidValue,
637
+ );
638
+ return defaultedValue;
639
+ };
501
640
  const getCellChange = (tableId, rowId, cellId) =>
502
641
  ifNotUndefined(
503
642
  mapGet(mapGet(mapGet(changedCells, tableId), rowId), cellId),
504
643
  ([oldCell, newCell]) => [true, oldCell, newCell],
505
644
  () => [false, ...pairNew(getCell(tableId, rowId, cellId))],
506
645
  );
646
+ const getValueChange = (valueId) =>
647
+ ifNotUndefined(
648
+ mapGet(changedValues, valueId),
649
+ ([oldValue, newValue]) => [true, oldValue, newValue],
650
+ () => [false, ...pairNew(getValue(valueId))],
651
+ );
507
652
  const callInvalidCellListeners = (mutator) =>
508
653
  !collIsEmpty(invalidCells) && !collIsEmpty(invalidCellListeners[mutator])
509
654
  ? collForEach(
@@ -520,13 +665,25 @@ const createStore = () => {
520
665
  ),
521
666
  )
522
667
  : 0;
668
+ const callInvalidValueListeners = (mutator) =>
669
+ !collIsEmpty(invalidValues) && !collIsEmpty(invalidValueListeners[mutator])
670
+ ? collForEach(
671
+ mutator ? mapClone(invalidValues) : invalidValues,
672
+ (invalidValue, valueId) =>
673
+ callListeners(
674
+ invalidValueListeners[mutator],
675
+ [valueId],
676
+ invalidValue,
677
+ ),
678
+ )
679
+ : 0;
523
680
  const callIdsListenersIfChanged = (listeners, changedIds, ids) => {
524
681
  if (!collIsEmpty(changedIds)) {
525
682
  callListeners(listeners, ids);
526
683
  return 1;
527
684
  }
528
685
  };
529
- const callListenersForChanges = (mutator) => {
686
+ const callTabularListenersForChanges = (mutator) => {
530
687
  const emptySortedRowIdListeners = collIsEmpty(
531
688
  sortedRowIdsListeners[mutator],
532
689
  );
@@ -628,6 +785,38 @@ const createStore = () => {
628
785
  }
629
786
  }
630
787
  };
788
+ const callKeyedValuesListenersForChanges = (mutator) => {
789
+ const emptyIdListeners = collIsEmpty(valueIdsListeners[mutator]);
790
+ const emptyOtherListeners =
791
+ collIsEmpty(valueListeners[mutator]) &&
792
+ collIsEmpty(valuesListeners[mutator]);
793
+ if (!emptyIdListeners || !emptyOtherListeners) {
794
+ const changes = mutator
795
+ ? [mapClone(changedValueIds), mapClone(changedValues)]
796
+ : [changedValueIds, changedValues];
797
+ if (!emptyIdListeners) {
798
+ callIdsListenersIfChanged(valueIdsListeners[mutator], changes[0]);
799
+ }
800
+ if (!emptyOtherListeners) {
801
+ let valuesChanged;
802
+ collForEach(changes[1], ([oldValue, newValue], valueId) => {
803
+ if (newValue !== oldValue) {
804
+ callListeners(
805
+ valueListeners[mutator],
806
+ [valueId],
807
+ newValue,
808
+ oldValue,
809
+ getValueChange,
810
+ );
811
+ valuesChanged = 1;
812
+ }
813
+ });
814
+ if (valuesChanged) {
815
+ callListeners(valuesListeners[mutator], void 0, getValueChange);
816
+ }
817
+ }
818
+ }
819
+ };
631
820
  const fluentTransaction = (actions, ...args) => {
632
821
  transaction(() => actions(...arrayMap(args, id)));
633
822
  return store;
@@ -660,14 +849,23 @@ const createStore = () => {
660
849
  mapKeys(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)));
661
850
  const getCell = (tableId, rowId, cellId) =>
662
851
  mapGet(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)), id(cellId));
852
+ const getValues = () => mapToObj(valuesMap);
853
+ const getValueIds = () => mapKeys(valuesMap);
854
+ const getValue = (valueId) => mapGet(valuesMap, id(valueId));
663
855
  const hasTables = () => !collIsEmpty(tablesMap);
664
856
  const hasTable = (tableId) => collHas(tablesMap, id(tableId));
665
857
  const hasRow = (tableId, rowId) =>
666
858
  collHas(mapGet(tablesMap, id(tableId)), id(rowId));
667
859
  const hasCell = (tableId, rowId, cellId) =>
668
860
  collHas(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)), id(cellId));
669
- const getJson = () => jsonString(tablesMap);
670
- const getSchemaJson = () => jsonString(schemaMap);
861
+ const hasValues = () => !collIsEmpty(valuesMap);
862
+ const hasValue = (valueId) => collHas(valuesMap, id(valueId));
863
+ const getTablesJson = () => jsonString(tablesMap);
864
+ const getValuesJson = () => jsonString(valuesMap);
865
+ const getJson = () => jsonString([tablesMap, valuesMap]);
866
+ const getTablesSchemaJson = () => jsonString(tablesSchemaMap);
867
+ const getValuesSchemaJson = () => jsonString(valuesSchemaMap);
868
+ const getSchemaJson = () => jsonString([tablesSchemaMap, valuesSchemaMap]);
671
869
  const setTables = (tables) =>
672
870
  fluentTransaction(() =>
673
871
  validateTables(tables) ? setValidTables(tables) : 0,
@@ -681,13 +879,8 @@ const createStore = () => {
681
879
  const setRow = (tableId, rowId, row) =>
682
880
  fluentTransaction(
683
881
  (tableId2, rowId2) =>
684
- validateRow(id(tableId2), id(rowId2), row)
685
- ? setValidRow(
686
- id(tableId2),
687
- getOrCreateTable(id(tableId2)),
688
- id(rowId2),
689
- row,
690
- )
882
+ validateRow(tableId2, rowId2, row)
883
+ ? setValidRow(tableId2, getOrCreateTable(tableId2), rowId2, row)
691
884
  : 0,
692
885
  tableId,
693
886
  rowId,
@@ -742,16 +935,56 @@ const createStore = () => {
742
935
  rowId,
743
936
  cellId,
744
937
  );
745
- const setJson = (json) => {
938
+ const setValues = (values) =>
939
+ fluentTransaction(() =>
940
+ validateValues(values) ? setValidValues(values) : 0,
941
+ );
942
+ const setPartialValues = (partialValues) =>
943
+ fluentTransaction(() =>
944
+ validateValues(partialValues, 1)
945
+ ? objMap(partialValues, (value, valueId) =>
946
+ setValidValue(valueId, value),
947
+ )
948
+ : 0,
949
+ );
950
+ const setValue = (valueId, value) =>
951
+ fluentTransaction(
952
+ (valueId2) =>
953
+ ifNotUndefined(
954
+ getValidatedValue(
955
+ valueId2,
956
+ isFunction(value) ? value(getValue(valueId2)) : value,
957
+ ),
958
+ (validValue) => setValidValue(valueId2, validValue),
959
+ ),
960
+ valueId,
961
+ );
962
+ const setTablesJson = (tablesJson) => {
746
963
  try {
747
- json === EMPTY_OBJECT ? delTables() : setTables(jsonParse(json));
964
+ setOrDelTables(jsonParse(tablesJson));
748
965
  } catch {}
749
966
  return store;
750
967
  };
751
- const setSchema = (schema) =>
968
+ const setValuesJson = (valuesJson) => {
969
+ try {
970
+ setOrDelValues(jsonParse(valuesJson));
971
+ } catch {}
972
+ return store;
973
+ };
974
+ const setJson = (tablesAndValuesJson) => {
975
+ try {
976
+ const [tables, values] = jsonParse(tablesAndValuesJson);
977
+ setOrDelTables(tables);
978
+ setOrDelValues(values);
979
+ } catch {
980
+ setTablesJson(tablesAndValuesJson);
981
+ }
982
+ return store;
983
+ };
984
+ const setTablesSchema = (tablesSchema) =>
752
985
  fluentTransaction(() => {
753
- if ((hasSchema = validateSchema(schema))) {
754
- setValidSchema(schema);
986
+ if ((hasTablesSchema = validateTablesSchema(tablesSchema))) {
987
+ setValidTablesSchema(tablesSchema);
755
988
  if (!collIsEmpty(tablesMap)) {
756
989
  const tables = getTables();
757
990
  delTables();
@@ -759,6 +992,22 @@ const createStore = () => {
759
992
  }
760
993
  }
761
994
  });
995
+ const setValuesSchema = (valuesSchema) =>
996
+ fluentTransaction(() => {
997
+ if ((hasValuesSchema = validateValuesSchema(valuesSchema))) {
998
+ const values = getValues();
999
+ delValuesSchema();
1000
+ delValues();
1001
+ hasValuesSchema = true;
1002
+ setValidValuesSchema(valuesSchema);
1003
+ setValues(values);
1004
+ }
1005
+ });
1006
+ const setSchema = (tablesSchema, valuesSchema) =>
1007
+ fluentTransaction(() => {
1008
+ setTablesSchema(tablesSchema);
1009
+ setValuesSchema(valuesSchema);
1010
+ });
762
1011
  const delTables = () => fluentTransaction(() => setValidTables({}));
763
1012
  const delTable = (tableId) =>
764
1013
  fluentTransaction(
@@ -798,10 +1047,27 @@ const createStore = () => {
798
1047
  rowId,
799
1048
  cellId,
800
1049
  );
1050
+ const delValues = () => fluentTransaction(() => setValidValues({}));
1051
+ const delValue = (valueId) =>
1052
+ fluentTransaction(
1053
+ (valueId2) =>
1054
+ collHas(valuesMap, valueId2) ? delValidValue(valueId2) : 0,
1055
+ valueId,
1056
+ );
1057
+ const delTablesSchema = () =>
1058
+ fluentTransaction(() => {
1059
+ setValidTablesSchema({});
1060
+ hasTablesSchema = false;
1061
+ });
1062
+ const delValuesSchema = () =>
1063
+ fluentTransaction(() => {
1064
+ setValidValuesSchema({});
1065
+ hasValuesSchema = false;
1066
+ });
801
1067
  const delSchema = () =>
802
1068
  fluentTransaction(() => {
803
- setValidSchema({});
804
- hasSchema = false;
1069
+ delTablesSchema();
1070
+ delValuesSchema();
805
1071
  });
806
1072
  const transaction = (actions, doRollback) => {
807
1073
  if (transactions == -1) {
@@ -821,10 +1087,15 @@ const createStore = () => {
821
1087
  transactions--;
822
1088
  if (transactions == 0) {
823
1089
  cellsTouched = !collIsEmpty(changedCells);
1090
+ valuesTouched = !collIsEmpty(changedValues);
824
1091
  transactions = 1;
825
1092
  callInvalidCellListeners(1);
826
1093
  if (cellsTouched) {
827
- callListenersForChanges(1);
1094
+ callTabularListenersForChanges(1);
1095
+ }
1096
+ callInvalidValueListeners(1);
1097
+ if (valuesTouched) {
1098
+ callKeyedValuesListenersForChanges(1);
828
1099
  }
829
1100
  transactions = -1;
830
1101
  if (
@@ -845,6 +1116,12 @@ const createStore = () => {
845
1116
  objIsEmpty,
846
1117
  ),
847
1118
  mapToObj(invalidCells, (map) => mapToObj(map, mapToObj)),
1119
+ mapToObj(
1120
+ changedValues,
1121
+ (values) => [...values],
1122
+ ([oldValue, newValue]) => oldValue === newValue,
1123
+ ),
1124
+ mapToObj(invalidValues),
848
1125
  )
849
1126
  ) {
850
1127
  transactions = 1;
@@ -855,23 +1132,43 @@ const createStore = () => {
855
1132
  ),
856
1133
  ),
857
1134
  );
1135
+ collForEach(changedValues, ([oldValue], valueId) =>
1136
+ setOrDelValue(store, valueId, oldValue),
1137
+ );
858
1138
  transactions = -1;
859
- cellsTouched = false;
1139
+ cellsTouched = valuesTouched = false;
860
1140
  }
861
- callListeners(finishTransactionListeners[0], void 0, cellsTouched);
1141
+ callListeners(
1142
+ finishTransactionListeners[0],
1143
+ void 0,
1144
+ cellsTouched,
1145
+ valuesTouched,
1146
+ );
862
1147
  callInvalidCellListeners(0);
863
1148
  if (cellsTouched) {
864
- callListenersForChanges(0);
1149
+ callTabularListenersForChanges(0);
1150
+ }
1151
+ callInvalidValueListeners(0);
1152
+ if (valuesTouched) {
1153
+ callKeyedValuesListenersForChanges(0);
865
1154
  }
866
- callListeners(finishTransactionListeners[1], void 0, cellsTouched);
1155
+ callListeners(
1156
+ finishTransactionListeners[1],
1157
+ void 0,
1158
+ cellsTouched,
1159
+ valuesTouched,
1160
+ );
867
1161
  transactions = 0;
868
1162
  arrayForEach(
869
1163
  [
870
- changedCells,
871
- invalidCells,
872
1164
  changedTableIds,
873
1165
  changedRowIds,
874
1166
  changedCellIds,
1167
+ changedCells,
1168
+ invalidCells,
1169
+ changedValueIds,
1170
+ changedValues,
1171
+ invalidValues,
875
1172
  ],
876
1173
  collClear,
877
1174
  );
@@ -895,6 +1192,7 @@ const createStore = () => {
895
1192
  );
896
1193
  const forEachCell = (tableId, rowId, cellCallback) =>
897
1194
  mapForEach(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)), cellCallback);
1195
+ const forEachValue = (valueCallback) => mapForEach(valuesMap, valueCallback);
898
1196
  const addSortedRowIdsListener = (
899
1197
  tableId,
900
1198
  cellId,
@@ -935,6 +1233,7 @@ const createStore = () => {
935
1233
  },
936
1234
  sortedRowIdsListeners[mutator ? 1 : 0],
937
1235
  [tableId, cellId],
1236
+ [getTableIds],
938
1237
  );
939
1238
  };
940
1239
  const addWillFinishTransactionListener = (listener) =>
@@ -942,9 +1241,7 @@ const createStore = () => {
942
1241
  const addDidFinishTransactionListener = (listener) =>
943
1242
  addListener(listener, finishTransactionListeners[1]);
944
1243
  const callListener = (listenerId) => {
945
- callListenerImpl(listenerId, [getTableIds, getRowIds, getCellIds], (ids) =>
946
- isUndefined(ids[2]) ? [] : pairNew(getCell(...ids)),
947
- );
1244
+ callListenerImpl(listenerId);
948
1245
  return store;
949
1246
  };
950
1247
  const delListener = (listenerId) => {
@@ -961,6 +1258,10 @@ const createStore = () => {
961
1258
  cellIds: pairCollSize2(cellIdsListeners, collSize3),
962
1259
  cell: pairCollSize2(cellListeners, collSize4),
963
1260
  invalidCell: pairCollSize2(invalidCellListeners, collSize4),
1261
+ values: pairCollSize2(valuesListeners),
1262
+ valueIds: pairCollSize2(valueIdsListeners),
1263
+ value: pairCollSize2(valueListeners),
1264
+ invalidValue: pairCollSize2(invalidValueListeners),
964
1265
  transaction: pairCollSize2(finishTransactionListeners),
965
1266
  });
966
1267
  const store = {
@@ -972,11 +1273,20 @@ const createStore = () => {
972
1273
  getRow,
973
1274
  getCellIds,
974
1275
  getCell,
1276
+ getValues,
1277
+ getValueIds,
1278
+ getValue,
975
1279
  hasTables,
976
1280
  hasTable,
977
1281
  hasRow,
978
1282
  hasCell,
1283
+ hasValues,
1284
+ hasValue,
1285
+ getTablesJson,
1286
+ getValuesJson,
979
1287
  getJson,
1288
+ getTablesSchemaJson,
1289
+ getValuesSchemaJson,
980
1290
  getSchemaJson,
981
1291
  setTables,
982
1292
  setTable,
@@ -984,12 +1294,23 @@ const createStore = () => {
984
1294
  addRow,
985
1295
  setPartialRow,
986
1296
  setCell,
1297
+ setValues,
1298
+ setPartialValues,
1299
+ setValue,
1300
+ setTablesJson,
1301
+ setValuesJson,
987
1302
  setJson,
1303
+ setTablesSchema,
1304
+ setValuesSchema,
988
1305
  setSchema,
989
1306
  delTables,
990
1307
  delTable,
991
1308
  delRow,
992
1309
  delCell,
1310
+ delValues,
1311
+ delValue,
1312
+ delTablesSchema,
1313
+ delValuesSchema,
993
1314
  delSchema,
994
1315
  transaction,
995
1316
  startTransaction,
@@ -997,6 +1318,7 @@ const createStore = () => {
997
1318
  forEachTable,
998
1319
  forEachRow,
999
1320
  forEachCell,
1321
+ forEachValue,
1000
1322
  addSortedRowIdsListener,
1001
1323
  addWillFinishTransactionListener,
1002
1324
  addDidFinishTransactionListener,
@@ -1009,19 +1331,35 @@ const createStore = () => {
1009
1331
  {
1010
1332
  [TABLES]: [0, tablesListeners],
1011
1333
  [TABLE_IDS]: [0, tableIdsListeners],
1012
- [TABLE]: [1, tableListeners],
1013
- [ROW_IDS]: [1, rowIdsListeners],
1014
- [ROW]: [2, rowListeners],
1015
- [CELL_IDS]: [2, cellIdsListeners],
1016
- [CELL]: [3, cellListeners],
1334
+ [TABLE]: [1, tableListeners, [getTableIds]],
1335
+ [ROW_IDS]: [1, rowIdsListeners, [getTableIds]],
1336
+ [ROW]: [2, rowListeners, [getTableIds, getRowIds]],
1337
+ [CELL_IDS]: [2, cellIdsListeners, [getTableIds, getRowIds]],
1338
+ [CELL]: [
1339
+ 3,
1340
+ cellListeners,
1341
+ [getTableIds, getRowIds, getCellIds],
1342
+ (ids) => pairNew(getCell(...ids)),
1343
+ ],
1017
1344
  InvalidCell: [3, invalidCellListeners],
1345
+ [VALUES]: [0, valuesListeners],
1346
+ [VALUE_IDS]: [0, valueIdsListeners],
1347
+ [VALUE]: [
1348
+ 1,
1349
+ valueListeners,
1350
+ [getValueIds],
1351
+ (ids) => pairNew(getValue(ids[0])),
1352
+ ],
1353
+ InvalidValue: [1, invalidValueListeners],
1018
1354
  },
1019
- ([argumentCount, idSetNode], listenable) => {
1355
+ ([argumentCount, idSetNode, pathGetters, extraArgsGetter], listenable) => {
1020
1356
  store[ADD + listenable + LISTENER] = (...args) =>
1021
1357
  addListener(
1022
1358
  args[argumentCount],
1023
1359
  idSetNode[args[argumentCount + 1] ? 1 : 0],
1024
1360
  argumentCount > 0 ? arraySlice(args, 0, argumentCount) : void 0,
1361
+ pathGetters,
1362
+ extraArgsGetter,
1025
1363
  );
1026
1364
  },
1027
1365
  );