tinybase 1.0.2 → 1.0.3

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 (54) hide show
  1. package/lib/checkpoints.d.ts +879 -0
  2. package/lib/checkpoints.js +1 -0
  3. package/lib/checkpoints.js.gz +0 -0
  4. package/lib/common.d.ts +115 -0
  5. package/lib/common.js +1 -0
  6. package/lib/common.js.gz +0 -0
  7. package/lib/debug/checkpoints.js +326 -0
  8. package/lib/debug/common.js +3 -0
  9. package/lib/debug/indexes.js +398 -0
  10. package/lib/debug/metrics.js +391 -0
  11. package/lib/debug/persisters.js +191 -0
  12. package/lib/debug/relationships.js +418 -0
  13. package/lib/debug/store.js +725 -0
  14. package/lib/indexes.d.ts +778 -0
  15. package/lib/indexes.js +1 -0
  16. package/lib/indexes.js.gz +0 -0
  17. package/lib/metrics.d.ts +757 -0
  18. package/lib/metrics.js +1 -0
  19. package/lib/metrics.js.gz +0 -0
  20. package/lib/persisters.d.ts +711 -0
  21. package/lib/persisters.js +1 -0
  22. package/lib/persisters.js.gz +0 -0
  23. package/lib/relationships.d.ts +1116 -0
  24. package/lib/relationships.js +1 -0
  25. package/lib/relationships.js.gz +0 -0
  26. package/lib/store.d.ts +2506 -0
  27. package/lib/store.js +1 -0
  28. package/lib/store.js.gz +0 -0
  29. package/lib/tinybase.d.ts +13 -0
  30. package/lib/tinybase.js +1 -0
  31. package/lib/tinybase.js.gz +0 -0
  32. package/lib/ui-react.d.ts +7185 -0
  33. package/lib/ui-react.js +1 -0
  34. package/lib/ui-react.js.gz +0 -0
  35. package/lib/umd/checkpoints.js +1 -0
  36. package/lib/umd/checkpoints.js.gz +0 -0
  37. package/lib/umd/common.js +1 -0
  38. package/lib/umd/common.js.gz +0 -0
  39. package/lib/umd/indexes.js +1 -0
  40. package/lib/umd/indexes.js.gz +0 -0
  41. package/lib/umd/metrics.js +1 -0
  42. package/lib/umd/metrics.js.gz +0 -0
  43. package/lib/umd/persisters.js +1 -0
  44. package/lib/umd/persisters.js.gz +0 -0
  45. package/lib/umd/relationships.js +1 -0
  46. package/lib/umd/relationships.js.gz +0 -0
  47. package/lib/umd/store.js +1 -0
  48. package/lib/umd/store.js.gz +0 -0
  49. package/lib/umd/tinybase.js +1 -0
  50. package/lib/umd/tinybase.js.gz +0 -0
  51. package/lib/umd/ui-react.js +1 -0
  52. package/lib/umd/ui-react.js.gz +0 -0
  53. package/package.json +1 -1
  54. package/readme.md +1 -1
@@ -0,0 +1,725 @@
1
+ const getTypeOf = (thing) => typeof thing;
2
+ const EMPTY_OBJECT = '{}';
3
+ const EMPTY_STRING = '';
4
+ const STRING = getTypeOf(EMPTY_STRING);
5
+ const BOOLEAN = getTypeOf(true);
6
+ const NUMBER = getTypeOf(0);
7
+ const FUNCTION = getTypeOf(getTypeOf);
8
+ const TYPE = 'type';
9
+ const DEFAULT = 'default';
10
+
11
+ const arrayHas = (array, value) => array.includes(value);
12
+ const arrayForEach = (array, cb) => array.forEach(cb);
13
+ const arrayLength = (array) => array.length;
14
+ const arrayIsEmpty = (array) => arrayLength(array) == 0;
15
+ const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
16
+ const arrayFilter = (array, cb) => array.filter(cb);
17
+ const arrayFromSecond = (ids) => ids.slice(1);
18
+
19
+ const jsonString = (obj) =>
20
+ JSON.stringify(obj, (_key, value) =>
21
+ isInstanceOf(value, Map)
22
+ ? arrayReduce(
23
+ [...value],
24
+ (obj2, [key, value2]) => {
25
+ obj2[key] = value2;
26
+ return obj2;
27
+ },
28
+ {},
29
+ )
30
+ : value,
31
+ );
32
+ const jsonParse = JSON.parse;
33
+ const isFiniteNumber = isFinite;
34
+ const isInstanceOf = (thing, cls) => thing instanceof cls;
35
+ const isUndefined = (thing) => thing == void 0;
36
+ const ifNotUndefined = (value, then, otherwise) =>
37
+ isUndefined(value) ? otherwise?.() : then(value);
38
+ const isTypeStringOrBoolean = (type) => type == STRING || type == BOOLEAN;
39
+ const isFunction = (thing) => getTypeOf(thing) == FUNCTION;
40
+
41
+ const collSizeN = (collSizer) => (coll) =>
42
+ arrayReduce(collValues(coll), (total, coll2) => total + collSizer(coll2), 0);
43
+ const collSize = (coll) => coll.size;
44
+ const collSize2 = collSizeN(collSize);
45
+ const collSize3 = collSizeN(collSize2);
46
+ const collSize4 = collSizeN(collSize3);
47
+ const collPairSize = (pair, func = collSize) => func(pair[0]) + func(pair[1]);
48
+ const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
49
+ const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
50
+ const collValues = (coll) => [...(coll?.values() ?? [])];
51
+ const collClear = (coll) => coll.clear();
52
+ const collForEach = (coll, cb) => coll?.forEach(cb);
53
+ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
54
+
55
+ const mapNew = (entries) => new Map(entries);
56
+ const mapNewPair = (newFunction = mapNew) => [newFunction(), newFunction()];
57
+ const mapKeys = (map) => [...(map?.keys() ?? [])];
58
+ const mapGet = (map, key) => map?.get(key);
59
+ const mapForEach = (map, cb) =>
60
+ collForEach(map, (value, key) => cb(key, value));
61
+ const mapSet = (map, key, value) =>
62
+ isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
63
+ const mapEnsure = (map, key, defaultValue, onWillAdd) => {
64
+ if (!collHas(map, key)) {
65
+ onWillAdd?.(defaultValue);
66
+ map.set(key, defaultValue);
67
+ }
68
+ return mapGet(map, key);
69
+ };
70
+ const mapToObj = (map, childMapper) => {
71
+ const obj = {};
72
+ const mapper = childMapper ?? ((mapValue) => mapValue);
73
+ collForEach(map, (value, key) => (obj[key] = mapper(value)));
74
+ return obj;
75
+ };
76
+ const mapClone = (map, childMapper) => {
77
+ const map2 = mapNew();
78
+ const mapper = childMapper ?? ((mapValue) => mapValue);
79
+ collForEach(map, (value, key) => map2.set(key, mapper(value)));
80
+ return map2;
81
+ };
82
+
83
+ const object = Object;
84
+ const objIds = object.keys;
85
+ const objFrozen = object.isFrozen;
86
+ const objFreeze = object.freeze;
87
+ const isObject = (obj) =>
88
+ isInstanceOf(obj, object) && obj.constructor == object;
89
+ const objGet = (obj, id) => ifNotUndefined(obj, (obj2) => obj2[id]);
90
+ const objHas = (obj, id) => !isUndefined(objGet(obj, id));
91
+ const objDel = (obj, id) => delete obj[id];
92
+ const objForEach = (obj, cb) =>
93
+ arrayForEach(object.entries(obj), ([id, value]) => cb(value, id));
94
+ const objIsEmpty = (obj) => arrayIsEmpty(objIds(obj));
95
+
96
+ const setNew = (entries) => new Set(entries);
97
+ const setAdd = (set, value) => set?.add(value);
98
+
99
+ const addDeepSet = (deepSet, value, ids) =>
100
+ arrayLength(ids) < 2
101
+ ? setAdd(
102
+ arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew()),
103
+ value,
104
+ )
105
+ : addDeepSet(
106
+ mapEnsure(deepSet, ids[0], mapNew()),
107
+ value,
108
+ arrayFromSecond(ids),
109
+ );
110
+ const forDeepSet = (valueDo) => {
111
+ const deep = (deepIdSet, arg, ...ids) =>
112
+ ifNotUndefined(deepIdSet, (deepIdSet2) =>
113
+ arrayIsEmpty(ids)
114
+ ? valueDo(deepIdSet2, arg)
115
+ : arrayForEach([ids[0], null], (id) =>
116
+ deep(mapGet(deepIdSet2, id), arg, ...arrayFromSecond(ids)),
117
+ ),
118
+ );
119
+ return deep;
120
+ };
121
+ const getListenerFunctions = (getThing) => {
122
+ let thing;
123
+ let nextId = 0;
124
+ const listenerPool = [];
125
+ const allListeners = mapNew();
126
+ const addListener = (listener, deepSet, idOrNulls = []) => {
127
+ thing ??= getThing();
128
+ const id = listenerPool.pop() ?? '' + nextId++;
129
+ mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
130
+ addDeepSet(deepSet, id, idOrNulls);
131
+ return id;
132
+ };
133
+ const callListeners = (deepSet, ids = [], ...extraArgs) =>
134
+ forDeepSet(collForEach)(
135
+ deepSet,
136
+ (id) =>
137
+ ifNotUndefined(mapGet(allListeners, id), ([listener]) =>
138
+ listener(thing, ...ids, ...extraArgs),
139
+ ),
140
+ ...ids,
141
+ );
142
+ const delListener = (id) =>
143
+ ifNotUndefined(
144
+ mapGet(allListeners, id),
145
+ ([, deepSet, idOrNulls]) => {
146
+ forDeepSet(collDel)(deepSet, id, ...idOrNulls);
147
+ mapSet(allListeners, id);
148
+ if (arrayLength(listenerPool) < 1e3) {
149
+ listenerPool.push(id);
150
+ }
151
+ return idOrNulls;
152
+ },
153
+ () => [],
154
+ );
155
+ const callListener = (id, idNullGetters, extraArgsGetter) =>
156
+ ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls]) => {
157
+ const callWithIds = (...ids) => {
158
+ const index = arrayLength(ids);
159
+ index == arrayLength(idOrNulls)
160
+ ? listener(thing, ...ids, ...extraArgsGetter(ids))
161
+ : isUndefined(idOrNulls[index])
162
+ ? arrayForEach(idNullGetters[index](...ids), (id2) =>
163
+ callWithIds(...ids, id2),
164
+ )
165
+ : callWithIds(...ids, idOrNulls[index]);
166
+ };
167
+ callWithIds();
168
+ });
169
+ return [addListener, callListeners, delListener, callListener];
170
+ };
171
+
172
+ const transformMap = (map, toBeLikeObject, setId, delId = mapSet) => {
173
+ const idsToDelete = arrayFilter(
174
+ mapKeys(map),
175
+ (id) => !objHas(toBeLikeObject, id),
176
+ );
177
+ arrayForEach(objIds(toBeLikeObject), (id) =>
178
+ setId(map, id, toBeLikeObject[id]),
179
+ );
180
+ arrayForEach(idsToDelete, (id) => delId(map, id));
181
+ return map;
182
+ };
183
+ const getCellType = (cell) => {
184
+ const type = getTypeOf(cell);
185
+ return isTypeStringOrBoolean(type) || (type == NUMBER && isFiniteNumber(cell))
186
+ ? type
187
+ : void 0;
188
+ };
189
+ const validate = (obj, validateChild) => {
190
+ if (isUndefined(obj) || !isObject(obj) || objFrozen(obj)) {
191
+ return false;
192
+ }
193
+ objForEach(obj, (child, id) => {
194
+ if (!validateChild(child, id)) {
195
+ objDel(obj, id);
196
+ }
197
+ });
198
+ return !objIsEmpty(obj);
199
+ };
200
+ const idsChanged = (ids, id, added) =>
201
+ mapSet(ids, id, mapGet(ids, id) == -added ? void 0 : added);
202
+ const createStore = () => {
203
+ let hasSchema;
204
+ let nextRowId = 0;
205
+ let transactions = 0;
206
+ const changedTableIds = mapNew();
207
+ const changedRowIds = mapNew();
208
+ const changedCellIds = mapNew();
209
+ const changedCells = mapNew();
210
+ const schemaMap = mapNew();
211
+ const schemaDefaultRows = mapNew();
212
+ const tablesMap = mapNew();
213
+ const tablesListeners = mapNewPair(setNew);
214
+ const tableIdsListeners = mapNewPair(setNew);
215
+ const tableListeners = mapNewPair();
216
+ const rowIdsListeners = mapNewPair();
217
+ const rowListeners = mapNewPair();
218
+ const cellIdsListeners = mapNewPair();
219
+ const cellListeners = mapNewPair();
220
+ const [addListener, callListeners, delListenerImpl, callListenerImpl] =
221
+ getListenerFunctions(() => store);
222
+ const validateSchema = (schema) =>
223
+ validate(schema, (tableSchema) =>
224
+ validate(tableSchema, (cellSchema) => {
225
+ if (
226
+ !validate(cellSchema, (_child, id) => arrayHas([TYPE, DEFAULT], id))
227
+ ) {
228
+ return false;
229
+ }
230
+ const type = cellSchema[TYPE];
231
+ if (!isTypeStringOrBoolean(type) && type != NUMBER) {
232
+ return false;
233
+ }
234
+ if (getCellType(cellSchema[DEFAULT]) != type) {
235
+ objDel(cellSchema, DEFAULT);
236
+ }
237
+ return true;
238
+ }),
239
+ );
240
+ const validateTables = (tables) => validate(tables, validateTable);
241
+ const validateTable = (table, tableId) =>
242
+ (!hasSchema || collHas(schemaMap, tableId)) &&
243
+ validate(table, (row) => validateRow(tableId, row));
244
+ const validateRow = (tableId, row, skipDefaults) =>
245
+ validate(
246
+ skipDefaults ? row : addDefaultsToRow(row, tableId),
247
+ (cell, cellId) =>
248
+ ifNotUndefined(
249
+ getValidatedCell(tableId, cellId, cell),
250
+ (validCell) => {
251
+ row[cellId] = validCell;
252
+ return true;
253
+ },
254
+ () => false,
255
+ ),
256
+ );
257
+ const getValidatedCell = (tableId, cellId, cell) =>
258
+ hasSchema
259
+ ? ifNotUndefined(
260
+ mapGet(mapGet(schemaMap, tableId), cellId),
261
+ (cellSchema) =>
262
+ getCellType(cell) != cellSchema[TYPE] ? cellSchema[DEFAULT] : cell,
263
+ )
264
+ : isUndefined(getCellType(cell))
265
+ ? void 0
266
+ : cell;
267
+ const addDefaultsToRow = (row, tableId) => {
268
+ ifNotUndefined(mapGet(schemaDefaultRows, tableId), (defaultRow) =>
269
+ objForEach(defaultRow, (cell, cellId) => {
270
+ if (!objHas(row, cellId)) {
271
+ row[cellId] = cell;
272
+ }
273
+ }),
274
+ );
275
+ return row;
276
+ };
277
+ const setValidSchema = (schema) =>
278
+ transformMap(
279
+ schemaMap,
280
+ schema,
281
+ (_schema, tableId, tableSchema) => {
282
+ const defaultRow = {};
283
+ transformMap(
284
+ mapEnsure(schemaMap, tableId, mapNew()),
285
+ tableSchema,
286
+ (tableSchemaMap, cellId, cellSchema) => {
287
+ mapSet(tableSchemaMap, cellId, cellSchema);
288
+ ifNotUndefined(
289
+ cellSchema[DEFAULT],
290
+ (def) => (defaultRow[cellId] = def),
291
+ );
292
+ },
293
+ );
294
+ mapSet(schemaDefaultRows, tableId, defaultRow);
295
+ },
296
+ (_schema, tableId) => {
297
+ mapSet(schemaMap, tableId);
298
+ mapSet(schemaDefaultRows, tableId);
299
+ },
300
+ );
301
+ const setValidTables = (tables) =>
302
+ transformMap(
303
+ tablesMap,
304
+ tables,
305
+ (_tables, tableId, table) => setValidTable(tableId, table),
306
+ (_tables, tableId) => delValidTable(tableId),
307
+ );
308
+ const setValidTable = (tableId, table) =>
309
+ transformMap(
310
+ mapEnsure(tablesMap, tableId, mapNew(), () =>
311
+ tableIdsChanged(tableId, 1),
312
+ ),
313
+ table,
314
+ (tableMap, rowId, row) => setValidRow(tableId, tableMap, rowId, row),
315
+ (tableMap, rowId) => delValidRow(tableId, tableMap, rowId),
316
+ );
317
+ const setValidRow = (tableId, tableMap, rowId, newRow, forceDel) =>
318
+ transformMap(
319
+ mapEnsure(tableMap, rowId, mapNew(), () =>
320
+ rowIdsChanged(tableId, rowId, 1),
321
+ ),
322
+ newRow,
323
+ (rowMap, cellId, cell) =>
324
+ setValidCell(tableId, rowId, rowMap, cellId, cell),
325
+ (rowMap, cellId) =>
326
+ delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel),
327
+ );
328
+ const setValidCell = (tableId, rowId, rowMap, cellId, newCell) => {
329
+ if (!collHas(rowMap, cellId)) {
330
+ cellIdsChanged(tableId, rowId, cellId, 1);
331
+ }
332
+ const oldCell = mapGet(rowMap, cellId);
333
+ if (newCell !== oldCell) {
334
+ cellChanged(tableId, rowId, cellId, oldCell);
335
+ mapSet(rowMap, cellId, newCell);
336
+ }
337
+ };
338
+ const setValidRowTransaction = (tableId, rowId, row) =>
339
+ transaction(() =>
340
+ setValidRow(tableId, getOrCreateTable(tableId), rowId, row),
341
+ );
342
+ const setCellIntoDefaultRow = (tableId, tableMap, rowId, cellId, validCell) =>
343
+ ifNotUndefined(
344
+ mapGet(tableMap, rowId),
345
+ (rowMap) => setValidCell(tableId, rowId, rowMap, cellId, validCell),
346
+ () =>
347
+ setValidRow(
348
+ tableId,
349
+ tableMap,
350
+ rowId,
351
+ addDefaultsToRow({[cellId]: validCell}, tableId),
352
+ ),
353
+ );
354
+ const getNewRowId = (tableMap) => {
355
+ const rowId = '' + nextRowId++;
356
+ if (!collHas(tableMap, rowId)) {
357
+ return rowId;
358
+ }
359
+ return getNewRowId(tableMap);
360
+ };
361
+ const getOrCreateTable = (tableId) =>
362
+ mapGet(tablesMap, tableId) ?? setValidTable(tableId, {});
363
+ const delValidTable = (tableId) => setValidTable(tableId, {});
364
+ const delValidRow = (tableId, tableMap, rowId) =>
365
+ setValidRow(tableId, tableMap, rowId, {}, true);
366
+ const delValidCell = (tableId, table, rowId, row, cellId, forceDel) => {
367
+ const defaultCell = mapGet(schemaDefaultRows, tableId)?.[cellId];
368
+ if (!isUndefined(defaultCell) && !forceDel) {
369
+ return setValidCell(tableId, rowId, row, cellId, defaultCell);
370
+ }
371
+ const delCell2 = (cellId2) => {
372
+ cellChanged(tableId, rowId, cellId2, mapGet(row, cellId2));
373
+ cellIdsChanged(tableId, rowId, cellId2, -1);
374
+ mapSet(row, cellId2);
375
+ };
376
+ isUndefined(defaultCell) ? delCell2(cellId) : mapForEach(row, delCell2);
377
+ if (collIsEmpty(row)) {
378
+ rowIdsChanged(tableId, rowId, -1);
379
+ if (collIsEmpty(mapSet(table, rowId))) {
380
+ tableIdsChanged(tableId, -1);
381
+ mapSet(tablesMap, tableId);
382
+ }
383
+ }
384
+ };
385
+ const tableIdsChanged = (tableId, added) =>
386
+ idsChanged(changedTableIds, tableId, added);
387
+ const rowIdsChanged = (tableId, rowId, added) =>
388
+ idsChanged(mapEnsure(changedRowIds, tableId, mapNew()), rowId, added);
389
+ const cellIdsChanged = (tableId, rowId, cellId, added) =>
390
+ idsChanged(
391
+ mapEnsure(mapEnsure(changedCellIds, tableId, mapNew()), rowId, mapNew()),
392
+ cellId,
393
+ added,
394
+ );
395
+ const cellChanged = (tableId, rowId, cellId, oldCell) =>
396
+ mapEnsure(
397
+ mapEnsure(mapEnsure(changedCells, tableId, mapNew()), rowId, mapNew()),
398
+ cellId,
399
+ oldCell,
400
+ );
401
+ const getCellChange = (tableId, rowId, cellId) => {
402
+ const changedRow = mapGet(mapGet(changedCells, tableId), rowId);
403
+ const newCell = getCell(tableId, rowId, cellId);
404
+ return collHas(changedRow, cellId)
405
+ ? [true, mapGet(changedRow, cellId), newCell]
406
+ : [false, newCell, newCell];
407
+ };
408
+ const callListenersForChanges = (mutator) => {
409
+ const emptyIdListeners =
410
+ collIsEmpty(cellIdsListeners[mutator]) &&
411
+ collIsEmpty(rowIdsListeners[mutator]) &&
412
+ collIsEmpty(tableIdsListeners[mutator]);
413
+ const emptyOtherListeners =
414
+ collIsEmpty(cellListeners[mutator]) &&
415
+ collIsEmpty(rowListeners[mutator]) &&
416
+ collIsEmpty(tableListeners[mutator]) &&
417
+ collIsEmpty(tablesListeners[mutator]);
418
+ if (emptyIdListeners && emptyOtherListeners) {
419
+ return;
420
+ }
421
+ const changes = mutator
422
+ ? [
423
+ mapClone(changedTableIds),
424
+ mapClone(changedRowIds, mapClone),
425
+ mapClone(changedCellIds, (table) => mapClone(table, mapClone)),
426
+ mapClone(changedCells, (table) => mapClone(table, mapClone)),
427
+ ]
428
+ : [changedTableIds, changedRowIds, changedCellIds, changedCells];
429
+ if (!emptyIdListeners) {
430
+ collForEach(changes[2], (rowCellIds, tableId) =>
431
+ collForEach(rowCellIds, (changedIds, rowId) => {
432
+ if (!collIsEmpty(changedIds)) {
433
+ callListeners(cellIdsListeners[mutator], [tableId, rowId]);
434
+ }
435
+ }),
436
+ );
437
+ collForEach(changes[1], (changedIds, tableId) => {
438
+ if (!collIsEmpty(changedIds)) {
439
+ callListeners(rowIdsListeners[mutator], [tableId]);
440
+ }
441
+ });
442
+ if (!collIsEmpty(changes[0])) {
443
+ callListeners(tableIdsListeners[mutator]);
444
+ }
445
+ }
446
+ if (!emptyOtherListeners) {
447
+ let tablesChanged;
448
+ collForEach(changes[3], (rows, tableId) => {
449
+ let tableChanged;
450
+ collForEach(rows, (cells, rowId) => {
451
+ let rowChanged;
452
+ collForEach(cells, (oldCell, cellId) => {
453
+ const newCell = getCell(tableId, rowId, cellId);
454
+ if (newCell !== oldCell) {
455
+ callListeners(
456
+ cellListeners[mutator],
457
+ [tableId, rowId, cellId],
458
+ newCell,
459
+ oldCell,
460
+ getCellChange,
461
+ );
462
+ tablesChanged = tableChanged = rowChanged = 1;
463
+ }
464
+ });
465
+ if (rowChanged) {
466
+ callListeners(
467
+ rowListeners[mutator],
468
+ [tableId, rowId],
469
+ getCellChange,
470
+ );
471
+ }
472
+ });
473
+ if (tableChanged) {
474
+ callListeners(tableListeners[mutator], [tableId], getCellChange);
475
+ }
476
+ });
477
+ if (tablesChanged) {
478
+ callListeners(tablesListeners[mutator], [], getCellChange);
479
+ }
480
+ }
481
+ };
482
+ const getTables = () =>
483
+ mapToObj(tablesMap, (tableMap) => mapToObj(tableMap, mapToObj));
484
+ const getTableIds = () => mapKeys(tablesMap);
485
+ const getTable = (tableId) => mapToObj(mapGet(tablesMap, tableId), mapToObj);
486
+ const getRowIds = (tableId) => mapKeys(mapGet(tablesMap, tableId));
487
+ const getRow = (tableId, rowId) =>
488
+ mapToObj(mapGet(mapGet(tablesMap, tableId), rowId));
489
+ const getCellIds = (tableId, rowId) =>
490
+ mapKeys(mapGet(mapGet(tablesMap, tableId), rowId));
491
+ const getCell = (tableId, rowId, cellId) =>
492
+ mapGet(mapGet(mapGet(tablesMap, tableId), rowId), cellId);
493
+ const hasTable = (tableId) => collHas(tablesMap, tableId);
494
+ const hasRow = (tableId, rowId) => collHas(mapGet(tablesMap, tableId), rowId);
495
+ const hasCell = (tableId, rowId, cellId) =>
496
+ collHas(mapGet(mapGet(tablesMap, tableId), rowId), cellId);
497
+ const getJson = () => jsonString(tablesMap);
498
+ const getSchemaJson = () => jsonString(schemaMap);
499
+ const setTables = (tables) => {
500
+ if (validateTables(tables)) {
501
+ transaction(() => setValidTables(tables));
502
+ }
503
+ return store;
504
+ };
505
+ const setTable = (tableId, table) => {
506
+ if (validateTable(table, tableId)) {
507
+ transaction(() => setValidTable(tableId, table));
508
+ }
509
+ return store;
510
+ };
511
+ const setRow = (tableId, rowId, row) => {
512
+ if (validateRow(tableId, row)) {
513
+ setValidRowTransaction(tableId, rowId, row);
514
+ }
515
+ return store;
516
+ };
517
+ const addRow = (tableId, row) => {
518
+ let rowId = void 0;
519
+ if (validateRow(tableId, row)) {
520
+ rowId = getNewRowId(mapGet(tablesMap, tableId));
521
+ setValidRowTransaction(tableId, rowId, row);
522
+ }
523
+ return rowId;
524
+ };
525
+ const setPartialRow = (tableId, rowId, partialRow) => {
526
+ if (validateRow(tableId, partialRow, 1)) {
527
+ transaction(() => {
528
+ const table = getOrCreateTable(tableId);
529
+ objForEach(partialRow, (cell, cellId) =>
530
+ setCellIntoDefaultRow(tableId, table, rowId, cellId, cell),
531
+ );
532
+ });
533
+ }
534
+ return store;
535
+ };
536
+ const setCell = (tableId, rowId, cellId, cell) => {
537
+ ifNotUndefined(
538
+ getValidatedCell(
539
+ tableId,
540
+ cellId,
541
+ isFunction(cell) ? cell(getCell(tableId, rowId, cellId)) : cell,
542
+ ),
543
+ (validCell) =>
544
+ transaction(() =>
545
+ setCellIntoDefaultRow(
546
+ tableId,
547
+ getOrCreateTable(tableId),
548
+ rowId,
549
+ cellId,
550
+ validCell,
551
+ ),
552
+ ),
553
+ );
554
+ return store;
555
+ };
556
+ const setJson = (json) => {
557
+ try {
558
+ json === EMPTY_OBJECT ? delTables() : setTables(jsonParse(json));
559
+ } catch {}
560
+ return store;
561
+ };
562
+ const setSchema = (schema) => {
563
+ if ((hasSchema = validateSchema(schema))) {
564
+ setValidSchema(schema);
565
+ if (!collIsEmpty(tablesMap)) {
566
+ const tables = getTables();
567
+ delTables();
568
+ setTables(tables);
569
+ }
570
+ }
571
+ return store;
572
+ };
573
+ const delTables = () => {
574
+ transaction(() => setValidTables({}));
575
+ return store;
576
+ };
577
+ const delTable = (tableId) => {
578
+ if (collHas(tablesMap, tableId)) {
579
+ transaction(() => delValidTable(tableId));
580
+ }
581
+ return store;
582
+ };
583
+ const delRow = (tableId, rowId) => {
584
+ ifNotUndefined(mapGet(tablesMap, tableId), (tableMap) => {
585
+ if (collHas(tableMap, rowId)) {
586
+ transaction(() => delValidRow(tableId, tableMap, rowId));
587
+ }
588
+ });
589
+ return store;
590
+ };
591
+ const delCell = (tableId, rowId, cellId, forceDel) => {
592
+ ifNotUndefined(mapGet(tablesMap, tableId), (tableMap) =>
593
+ ifNotUndefined(mapGet(tableMap, rowId), (rowMap) => {
594
+ if (collHas(rowMap, cellId)) {
595
+ transaction(() =>
596
+ delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel),
597
+ );
598
+ }
599
+ }),
600
+ );
601
+ return store;
602
+ };
603
+ const delSchema = () => {
604
+ setValidSchema({});
605
+ hasSchema = false;
606
+ return store;
607
+ };
608
+ const transaction = (actions) => {
609
+ if (transactions == -1) {
610
+ return;
611
+ }
612
+ transactions++;
613
+ const result = actions();
614
+ transactions--;
615
+ if (transactions == 0) {
616
+ transactions = 1;
617
+ callListenersForChanges(1);
618
+ transactions = -1;
619
+ callListenersForChanges(0);
620
+ transactions = 0;
621
+ arrayForEach(
622
+ [changedCells, changedTableIds, changedRowIds, changedCellIds],
623
+ collClear,
624
+ );
625
+ }
626
+ return result;
627
+ };
628
+ const forEachTable = (tableCallback) =>
629
+ collForEach(tablesMap, (tableMap, tableId) =>
630
+ tableCallback(tableId, (rowCallback) =>
631
+ collForEach(tableMap, (rowMap, rowId) =>
632
+ rowCallback(rowId, (cellCallback) =>
633
+ mapForEach(rowMap, cellCallback),
634
+ ),
635
+ ),
636
+ ),
637
+ );
638
+ const forEachRow = (tableId, rowCallback) =>
639
+ collForEach(mapGet(tablesMap, tableId), (rowMap, rowId) =>
640
+ rowCallback(rowId, (cellCallback) => mapForEach(rowMap, cellCallback)),
641
+ );
642
+ const forEachCell = (tableId, rowId, cellCallback) =>
643
+ mapForEach(mapGet(mapGet(tablesMap, tableId), rowId), cellCallback);
644
+ const addTablesListener = (listener, mutator) =>
645
+ addListener(listener, tablesListeners[mutator ? 1 : 0]);
646
+ const addTableIdsListener = (listener, mutator) =>
647
+ addListener(listener, tableIdsListeners[mutator ? 1 : 0]);
648
+ const addTableListener = (tableId, listener, mutator) =>
649
+ addListener(listener, tableListeners[mutator ? 1 : 0], [tableId]);
650
+ const addRowIdsListener = (tableId, listener, mutator) =>
651
+ addListener(listener, rowIdsListeners[mutator ? 1 : 0], [tableId]);
652
+ const addRowListener = (tableId, rowId, listener, mutator) =>
653
+ addListener(listener, rowListeners[mutator ? 1 : 0], [tableId, rowId]);
654
+ const addCellIdsListener = (tableId, rowId, listener, mutator) =>
655
+ addListener(listener, cellIdsListeners[mutator ? 1 : 0], [tableId, rowId]);
656
+ const addCellListener = (tableId, rowId, cellId, listener, mutator) =>
657
+ addListener(listener, cellListeners[mutator ? 1 : 0], [
658
+ tableId,
659
+ rowId,
660
+ cellId,
661
+ ]);
662
+ const callListener = (listenerId) => {
663
+ callListenerImpl(listenerId, [getTableIds, getRowIds, getCellIds], (ids) =>
664
+ isUndefined(ids[2]) ? [] : Array(2).fill(getCell(...ids)),
665
+ );
666
+ return store;
667
+ };
668
+ const delListener = (listenerId) => {
669
+ delListenerImpl(listenerId);
670
+ return store;
671
+ };
672
+ const getListenerStats = () => ({
673
+ tables: collPairSize(tablesListeners),
674
+ tableIds: collPairSize(tableIdsListeners),
675
+ table: collPairSize(tableListeners, collSize2),
676
+ rowIds: collPairSize(rowIdsListeners, collSize2),
677
+ row: collPairSize(rowListeners, collSize3),
678
+ cellIds: collPairSize(cellIdsListeners, collSize3),
679
+ cell: collPairSize(cellListeners, collSize4),
680
+ });
681
+ const store = {
682
+ getTables,
683
+ getTableIds,
684
+ getTable,
685
+ getRowIds,
686
+ getRow,
687
+ getCellIds,
688
+ getCell,
689
+ hasTable,
690
+ hasRow,
691
+ hasCell,
692
+ getJson,
693
+ getSchemaJson,
694
+ setTables,
695
+ setTable,
696
+ setRow,
697
+ addRow,
698
+ setPartialRow,
699
+ setCell,
700
+ setJson,
701
+ setSchema,
702
+ delTables,
703
+ delTable,
704
+ delRow,
705
+ delCell,
706
+ delSchema,
707
+ transaction,
708
+ forEachTable,
709
+ forEachRow,
710
+ forEachCell,
711
+ addTablesListener,
712
+ addTableIdsListener,
713
+ addTableListener,
714
+ addRowIdsListener,
715
+ addRowListener,
716
+ addCellIdsListener,
717
+ addCellListener,
718
+ callListener,
719
+ delListener,
720
+ getListenerStats,
721
+ };
722
+ return objFreeze(store);
723
+ };
724
+
725
+ export {createStore};