tinybase 5.0.0-beta.1 → 5.0.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.
Files changed (138) hide show
  1. package/lib/cjs/mergeable-store.cjs +1 -0
  2. package/lib/cjs/mergeable-store.cjs.gz +0 -0
  3. package/lib/cjs/persisters/persister-automerge.cjs +1 -1
  4. package/lib/cjs/persisters/persister-automerge.cjs.gz +0 -0
  5. package/lib/cjs/persisters/persister-indexed-db.cjs +1 -1
  6. package/lib/cjs/persisters/persister-indexed-db.cjs.gz +0 -0
  7. package/lib/cjs/store.cjs +1 -1
  8. package/lib/cjs/store.cjs.gz +0 -0
  9. package/lib/cjs/tinybase.cjs +1 -1
  10. package/lib/cjs/tinybase.cjs.gz +0 -0
  11. package/lib/cjs/ui-react-dom-debug.cjs +1 -1
  12. package/lib/cjs/ui-react-dom-debug.cjs.gz +0 -0
  13. package/lib/cjs/ui-react-dom.cjs +1 -1
  14. package/lib/cjs/ui-react-dom.cjs.gz +0 -0
  15. package/lib/cjs-es6/mergeable-store.cjs +1 -0
  16. package/lib/cjs-es6/mergeable-store.cjs.gz +0 -0
  17. package/lib/cjs-es6/persisters/persister-automerge.cjs +1 -1
  18. package/lib/cjs-es6/persisters/persister-automerge.cjs.gz +0 -0
  19. package/lib/cjs-es6/persisters/persister-indexed-db.cjs +1 -1
  20. package/lib/cjs-es6/persisters/persister-indexed-db.cjs.gz +0 -0
  21. package/lib/cjs-es6/store.cjs +1 -1
  22. package/lib/cjs-es6/store.cjs.gz +0 -0
  23. package/lib/cjs-es6/tinybase.cjs +1 -1
  24. package/lib/cjs-es6/tinybase.cjs.gz +0 -0
  25. package/lib/cjs-es6/ui-react-dom-debug.cjs +1 -1
  26. package/lib/cjs-es6/ui-react-dom-debug.cjs.gz +0 -0
  27. package/lib/cjs-es6/ui-react-dom.cjs +1 -1
  28. package/lib/cjs-es6/ui-react-dom.cjs.gz +0 -0
  29. package/lib/debug/mergeable-store.js +1892 -0
  30. package/lib/debug/persisters/persister-automerge.js +12 -10
  31. package/lib/debug/persisters/persister-cr-sqlite-wasm.js +6 -6
  32. package/lib/debug/persisters/persister-electric-sql.js +6 -6
  33. package/lib/debug/persisters/persister-expo-sqlite-next.js +6 -6
  34. package/lib/debug/persisters/persister-expo-sqlite.js +6 -6
  35. package/lib/debug/persisters/persister-indexed-db.js +6 -3
  36. package/lib/debug/persisters/persister-partykit-server.js +5 -5
  37. package/lib/debug/persisters/persister-sqlite-wasm.js +6 -6
  38. package/lib/debug/persisters/persister-sqlite3.js +6 -6
  39. package/lib/debug/persisters/persister-yjs.js +6 -6
  40. package/lib/debug/queries.js +2 -2
  41. package/lib/debug/store.js +20 -10
  42. package/lib/debug/tinybase.js +300 -11
  43. package/lib/debug/tools.js +4 -4
  44. package/lib/debug/ui-react-dom.js +49 -40
  45. package/lib/es6/mergeable-store.js +1 -0
  46. package/lib/es6/mergeable-store.js.gz +0 -0
  47. package/lib/es6/persisters/persister-automerge.js +1 -1
  48. package/lib/es6/persisters/persister-automerge.js.gz +0 -0
  49. package/lib/es6/persisters/persister-indexed-db.js +1 -1
  50. package/lib/es6/persisters/persister-indexed-db.js.gz +0 -0
  51. package/lib/es6/store.js +1 -1
  52. package/lib/es6/store.js.gz +0 -0
  53. package/lib/es6/tinybase.js +1 -1
  54. package/lib/es6/tinybase.js.gz +0 -0
  55. package/lib/es6/ui-react-dom-debug.js +1 -1
  56. package/lib/es6/ui-react-dom-debug.js.gz +0 -0
  57. package/lib/es6/ui-react-dom.js +1 -1
  58. package/lib/es6/ui-react-dom.js.gz +0 -0
  59. package/lib/mergeable-store.js +1 -0
  60. package/lib/mergeable-store.js.gz +0 -0
  61. package/lib/persisters/persister-automerge.js +1 -1
  62. package/lib/persisters/persister-automerge.js.gz +0 -0
  63. package/lib/persisters/persister-indexed-db.js +1 -1
  64. package/lib/persisters/persister-indexed-db.js.gz +0 -0
  65. package/lib/store.js +1 -1
  66. package/lib/store.js.gz +0 -0
  67. package/lib/tinybase.js +1 -1
  68. package/lib/tinybase.js.gz +0 -0
  69. package/lib/types/mergeable-store.d.ts +55 -0
  70. package/lib/types/persisters/persister-automerge.d.ts +8 -7
  71. package/lib/types/persisters/persister-browser.d.ts +2 -0
  72. package/lib/types/persisters/persister-cr-sqlite-wasm.d.ts +1 -0
  73. package/lib/types/persisters/persister-electric-sql.d.ts +1 -0
  74. package/lib/types/persisters/persister-expo-sqlite-next.d.ts +1 -0
  75. package/lib/types/persisters/persister-expo-sqlite.d.ts +1 -0
  76. package/lib/types/persisters/persister-file.d.ts +1 -0
  77. package/lib/types/persisters/persister-indexed-db.d.ts +1 -0
  78. package/lib/types/persisters/persister-partykit-client.d.ts +1 -0
  79. package/lib/types/persisters/persister-partykit-server.d.ts +5 -0
  80. package/lib/types/persisters/persister-remote.d.ts +1 -0
  81. package/lib/types/persisters/persister-sqlite-wasm.d.ts +1 -0
  82. package/lib/types/persisters/persister-sqlite3.d.ts +1 -0
  83. package/lib/types/persisters/persister-yjs.d.ts +1 -0
  84. package/lib/types/persisters.d.ts +3 -3
  85. package/lib/types/store.d.ts +90 -77
  86. package/lib/types/tinybase.d.ts +1 -0
  87. package/lib/types/ui-react.d.ts +1 -0
  88. package/lib/types/with-schemas/internal/store.d.ts +4 -0
  89. package/lib/types/with-schemas/mergeable-store.d.ts +85 -0
  90. package/lib/types/with-schemas/persisters/persister-automerge.d.ts +8 -7
  91. package/lib/types/with-schemas/persisters/persister-browser.d.ts +2 -0
  92. package/lib/types/with-schemas/persisters/persister-cr-sqlite-wasm.d.ts +1 -0
  93. package/lib/types/with-schemas/persisters/persister-electric-sql.d.ts +1 -0
  94. package/lib/types/with-schemas/persisters/persister-expo-sqlite-next.d.ts +1 -0
  95. package/lib/types/with-schemas/persisters/persister-expo-sqlite.d.ts +1 -0
  96. package/lib/types/with-schemas/persisters/persister-file.d.ts +1 -0
  97. package/lib/types/with-schemas/persisters/persister-indexed-db.d.ts +1 -0
  98. package/lib/types/with-schemas/persisters/persister-partykit-client.d.ts +1 -0
  99. package/lib/types/with-schemas/persisters/persister-partykit-server.d.ts +5 -0
  100. package/lib/types/with-schemas/persisters/persister-remote.d.ts +1 -0
  101. package/lib/types/with-schemas/persisters/persister-sqlite-wasm.d.ts +1 -0
  102. package/lib/types/with-schemas/persisters/persister-sqlite3.d.ts +1 -0
  103. package/lib/types/with-schemas/persisters/persister-yjs.d.ts +1 -0
  104. package/lib/types/with-schemas/persisters.d.ts +3 -3
  105. package/lib/types/with-schemas/store.d.ts +203 -141
  106. package/lib/types/with-schemas/tinybase.d.ts +1 -0
  107. package/lib/ui-react-dom.js +1 -1
  108. package/lib/ui-react-dom.js.gz +0 -0
  109. package/lib/umd/mergeable-store.js +1 -0
  110. package/lib/umd/mergeable-store.js.gz +0 -0
  111. package/lib/umd/persisters/persister-automerge.js +1 -1
  112. package/lib/umd/persisters/persister-automerge.js.gz +0 -0
  113. package/lib/umd/persisters/persister-indexed-db.js +1 -1
  114. package/lib/umd/persisters/persister-indexed-db.js.gz +0 -0
  115. package/lib/umd/store.js +1 -1
  116. package/lib/umd/store.js.gz +0 -0
  117. package/lib/umd/tinybase.js +1 -1
  118. package/lib/umd/tinybase.js.gz +0 -0
  119. package/lib/umd/ui-react-dom-debug.js +1 -1
  120. package/lib/umd/ui-react-dom-debug.js.gz +0 -0
  121. package/lib/umd/ui-react-dom.js +1 -1
  122. package/lib/umd/ui-react-dom.js.gz +0 -0
  123. package/lib/umd-es6/mergeable-store.js +1 -0
  124. package/lib/umd-es6/mergeable-store.js.gz +0 -0
  125. package/lib/umd-es6/persisters/persister-automerge.js +1 -1
  126. package/lib/umd-es6/persisters/persister-automerge.js.gz +0 -0
  127. package/lib/umd-es6/persisters/persister-indexed-db.js +1 -1
  128. package/lib/umd-es6/persisters/persister-indexed-db.js.gz +0 -0
  129. package/lib/umd-es6/store.js +1 -1
  130. package/lib/umd-es6/store.js.gz +0 -0
  131. package/lib/umd-es6/tinybase.js +1 -1
  132. package/lib/umd-es6/tinybase.js.gz +0 -0
  133. package/lib/umd-es6/ui-react-dom-debug.js +1 -1
  134. package/lib/umd-es6/ui-react-dom-debug.js.gz +0 -0
  135. package/lib/umd-es6/ui-react-dom.js +1 -1
  136. package/lib/umd-es6/ui-react-dom.js.gz +0 -0
  137. package/package.json +31 -31
  138. package/readme.md +2 -2
@@ -0,0 +1,1892 @@
1
+ const getTypeOf = (thing) => typeof thing;
2
+ const EMPTY_STRING = '';
3
+ const STRING = getTypeOf(EMPTY_STRING);
4
+ const BOOLEAN = getTypeOf(true);
5
+ const NUMBER = getTypeOf(0);
6
+ const FUNCTION = getTypeOf(getTypeOf);
7
+ const TYPE = 'type';
8
+ const DEFAULT = 'default';
9
+ const LISTENER = 'Listener';
10
+ const ADD = 'add';
11
+ const HAS = 'Has';
12
+ const IDS = 'Ids';
13
+ const TABLE = 'Table';
14
+ const TABLES = TABLE + 's';
15
+ const TABLE_IDS = TABLE + IDS;
16
+ const ROW = 'Row';
17
+ const ROW_COUNT = ROW + 'Count';
18
+ const ROW_IDS = ROW + IDS;
19
+ const CELL = 'Cell';
20
+ const CELL_IDS = CELL + IDS;
21
+ const VALUE = 'Value';
22
+ const VALUES = VALUE + 's';
23
+ const VALUE_IDS = VALUE + IDS;
24
+ const id = (key) => EMPTY_STRING + key;
25
+ const strStartsWith = (str, prefix) => str.startsWith(prefix);
26
+ const strEndsWith = (str, suffix) => str.endsWith(suffix);
27
+ const strSplit = (str, separator = '', limit) => str.split(separator, limit);
28
+ const strCharCodeAt = (str, position = 0) => str.charCodeAt(position);
29
+
30
+ const isFiniteNumber = isFinite;
31
+ const isInstanceOf = (thing, cls) => thing instanceof cls;
32
+ const isUndefined = (thing) => thing == void 0;
33
+ const ifNotUndefined = (value, then, otherwise) =>
34
+ isUndefined(value) ? otherwise?.() : then(value);
35
+ const isTypeStringOrBoolean = (type) => type == STRING || type == BOOLEAN;
36
+ const isFunction = (thing) => getTypeOf(thing) == FUNCTION;
37
+ const isArray = (thing) => Array.isArray(thing);
38
+ const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
39
+ const size = (arrayOrString) => arrayOrString.length;
40
+ const test = (regex, subject) => regex.test(subject);
41
+
42
+ const arrayHas = (array, value) => array.includes(value);
43
+ const arrayEvery = (array, cb) => array.every(cb);
44
+ const arrayIsEqual = (array1, array2) =>
45
+ size(array1) === size(array2) &&
46
+ arrayEvery(array1, (value1, index) => array2[index] === value1);
47
+ const arraySort = (array, sorter) => array.sort(sorter);
48
+ const arrayForEach = (array, cb) => array.forEach(cb);
49
+ const arrayMap = (array, cb) => array.map(cb);
50
+ const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
51
+ const arrayPush = (array, ...values) => array.push(...values);
52
+ const arrayShift = (array) => array.shift();
53
+
54
+ const object = Object;
55
+ const getPrototypeOf = (obj) => object.getPrototypeOf(obj);
56
+ const objEntries = object.entries;
57
+ const objIds = object.keys;
58
+ const objFrozen = object.isFrozen;
59
+ const objFreeze = object.freeze;
60
+ const isObject = (obj) =>
61
+ !isUndefined(obj) &&
62
+ ifNotUndefined(
63
+ getPrototypeOf(obj),
64
+ (objPrototype) =>
65
+ objPrototype == object.prototype ||
66
+ isUndefined(getPrototypeOf(objPrototype)),
67
+ /* istanbul ignore next */
68
+ () => true,
69
+ );
70
+ const objGet = (obj, id) => ifNotUndefined(obj, (obj2) => obj2[id]);
71
+ const objHas = (obj, id) => !isUndefined(objGet(obj, id));
72
+ const objDel = (obj, id) => {
73
+ delete obj[id];
74
+ return obj;
75
+ };
76
+ const objForEach = (obj, cb) =>
77
+ arrayForEach(objEntries(obj), ([id, value]) => cb(value, id));
78
+ const objToArray = (obj, cb) =>
79
+ arrayMap(objEntries(obj), ([id, value]) => cb(value, id));
80
+ const objSize = (obj) => size(objIds(obj));
81
+ const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
82
+
83
+ const collSizeN = (collSizer) => (coll) =>
84
+ arrayReduce(collValues(coll), (total, coll2) => total + collSizer(coll2), 0);
85
+ const collSize = (coll) => coll?.size ?? 0;
86
+ const collSize2 = collSizeN(collSize);
87
+ const collSize3 = collSizeN(collSize2);
88
+ const collSize4 = collSizeN(collSize3);
89
+ const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
90
+ const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
91
+ const collValues = (coll) => [...(coll?.values() ?? [])];
92
+ const collClear = (coll) => coll.clear();
93
+ const collForEach = (coll, cb) => coll?.forEach(cb);
94
+ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
95
+
96
+ const mapNew = (entries) => new Map(entries);
97
+ const mapKeys = (map) => [...(map?.keys() ?? [])];
98
+ const mapGet = (map, key) => map?.get(key);
99
+ const mapForEach = (map, cb) =>
100
+ collForEach(map, (value, key) => cb(key, value));
101
+ const mapMap = (coll, cb) =>
102
+ arrayMap([...(coll?.entries() ?? [])], ([key, value]) => cb(value, key));
103
+ const mapSet = (map, key, value) =>
104
+ isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
105
+ const mapEnsure = (map, key, getDefaultValue) => {
106
+ if (!collHas(map, key)) {
107
+ mapSet(map, key, getDefaultValue());
108
+ }
109
+ return mapGet(map, key);
110
+ };
111
+ const mapMatch = (map, obj, set, del = mapSet) => {
112
+ objToArray(obj, (value, id) => set(map, id, value));
113
+ mapForEach(map, (id) => (objHas(obj, id) ? 0 : del(map, id)));
114
+ return map;
115
+ };
116
+ const mapToObj = (map, mapValue, excludeValue) => {
117
+ const obj = {};
118
+ collForEach(map, (value, id) => {
119
+ const mappedValue = mapValue ? mapValue(value, id) : value;
120
+ excludeValue?.(mappedValue, value) ? 0 : (obj[id] = mappedValue);
121
+ });
122
+ return obj;
123
+ };
124
+ const mapToObj2 = (map, mapValue, excludeValue) =>
125
+ mapToObj(
126
+ map,
127
+ (childMap) => mapToObj(childMap, mapValue, excludeValue),
128
+ objIsEmpty,
129
+ );
130
+ const mapToObj3 = (map, mapValue, excludeValue) =>
131
+ mapToObj(
132
+ map,
133
+ (childMap) => mapToObj2(childMap, mapValue, excludeValue),
134
+ objIsEmpty,
135
+ );
136
+ const mapClone = (map, mapValue) => {
137
+ const map2 = mapNew();
138
+ collForEach(map, (value, key) => map2.set(key, mapValue?.(value) ?? value));
139
+ return map2;
140
+ };
141
+ const mapClone2 = (map) => mapClone(map, mapClone);
142
+ const mapClone3 = (map) => mapClone(map, mapClone2);
143
+ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
144
+ ifNotUndefined(
145
+ (ensureLeaf ? mapEnsure : mapGet)(
146
+ node,
147
+ path[p],
148
+ p > size(path) - 2 ? ensureLeaf : mapNew,
149
+ ),
150
+ (nodeOrLeaf) => {
151
+ if (p > size(path) - 2) {
152
+ if (pruneLeaf?.(nodeOrLeaf)) {
153
+ mapSet(node, path[p]);
154
+ }
155
+ return nodeOrLeaf;
156
+ }
157
+ const leaf = visitTree(nodeOrLeaf, path, ensureLeaf, pruneLeaf, p + 1);
158
+ if (collIsEmpty(nodeOrLeaf)) {
159
+ mapSet(node, path[p]);
160
+ }
161
+ return leaf;
162
+ },
163
+ );
164
+
165
+ const newStamped = () => [EMPTY_STRING, null];
166
+ const newStampedMap = () => [EMPTY_STRING, mapNew()];
167
+ const mapStampedMapToObj = (stampedMap, mapper) =>
168
+ mapStamped(stampedMap, (map, stamp) => [
169
+ stamp,
170
+ isUndefined(map) ? null : mapToObj(map, mapper),
171
+ ]);
172
+ const mapStamped = ([stamp, value], mapper) => mapper(value, stamp);
173
+ const mergeStamp = (
174
+ [newStamp, newThing],
175
+ currentStampedThing,
176
+ getNextCurrentThing,
177
+ ifNewer = 0,
178
+ ) => {
179
+ const isNewer = newStamp > currentStampedThing[0];
180
+ if ((!ifNewer && currentStampedThing[1] !== null) || isNewer) {
181
+ currentStampedThing[1] = getNextCurrentThing(
182
+ newThing,
183
+ currentStampedThing[1],
184
+ );
185
+ }
186
+ if (isNewer) {
187
+ currentStampedThing[0] = newStamp;
188
+ }
189
+ return currentStampedThing;
190
+ };
191
+ const mergeEachStamp = (thingStamps, allThingStamps, changes, forEachThing) => {
192
+ objForEach(thingStamps, (thingStamp, thingId) =>
193
+ mergeStamp(
194
+ thingStamp,
195
+ mapEnsure(allThingStamps, thingId, newStamped),
196
+ (newThing, currentThing) => {
197
+ if (!forEachThing || isUndefined(newThing)) {
198
+ return (changes[thingId] = newThing ?? null);
199
+ }
200
+ currentThing ??= mapNew();
201
+ changes[thingId] = {};
202
+ forEachThing(newThing, currentThing, thingId);
203
+ return currentThing;
204
+ },
205
+ forEachThing ? 0 : 1,
206
+ ),
207
+ );
208
+ return allThingStamps;
209
+ };
210
+
211
+ const setNew = (entryOrEntries) =>
212
+ new Set(
213
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
214
+ ? entryOrEntries
215
+ : [entryOrEntries],
216
+ );
217
+ const setAdd = (set, value) => set?.add(value);
218
+
219
+ const INTEGER = /^\d+$/;
220
+ const getPoolFunctions = () => {
221
+ const pool = [];
222
+ let nextId = 0;
223
+ return [
224
+ (reuse) => (reuse ? arrayShift(pool) : null) ?? EMPTY_STRING + nextId++,
225
+ (id) => {
226
+ if (test(INTEGER, id) && size(pool) < 1e3) {
227
+ arrayPush(pool, id);
228
+ }
229
+ },
230
+ ];
231
+ };
232
+
233
+ const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
234
+ const leaves = [];
235
+ const deep = (node, p) =>
236
+ p == size(path)
237
+ ? arrayPush(leaves, node)
238
+ : path[p] === null
239
+ ? collForEach(node, (node2) => deep(node2, p + 1))
240
+ : arrayForEach([path[p], null], (id) => deep(mapGet(node, id), p + 1));
241
+ deep(deepIdSet, 0);
242
+ return leaves;
243
+ };
244
+ const getListenerFunctions = (getThing) => {
245
+ let thing;
246
+ const [getId, releaseId] = getPoolFunctions();
247
+ const allListeners = mapNew();
248
+ const addListener = (
249
+ listener,
250
+ idSetNode,
251
+ path,
252
+ pathGetters = [],
253
+ extraArgsGetter = () => [],
254
+ ) => {
255
+ thing ??= getThing();
256
+ const id = getId(1);
257
+ mapSet(allListeners, id, [
258
+ listener,
259
+ idSetNode,
260
+ path,
261
+ pathGetters,
262
+ extraArgsGetter,
263
+ ]);
264
+ setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
265
+ return id;
266
+ };
267
+ const callListeners = (idSetNode, ids, ...extraArgs) =>
268
+ arrayForEach(getWildcardedLeaves(idSetNode, ids), (set) =>
269
+ collForEach(set, (id) =>
270
+ mapGet(allListeners, id)[0](thing, ...(ids ?? []), ...extraArgs),
271
+ ),
272
+ );
273
+ const delListener = (id) =>
274
+ ifNotUndefined(mapGet(allListeners, id), ([, idSetNode, idOrNulls]) => {
275
+ visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], void 0, (idSet) => {
276
+ collDel(idSet, id);
277
+ return collIsEmpty(idSet) ? 1 : 0;
278
+ });
279
+ mapSet(allListeners, id);
280
+ releaseId(id);
281
+ return idOrNulls;
282
+ });
283
+ const callListener = (id) =>
284
+ ifNotUndefined(
285
+ mapGet(allListeners, id),
286
+ ([listener, , path = [], pathGetters, extraArgsGetter]) => {
287
+ const callWithIds = (...ids) => {
288
+ const index = size(ids);
289
+ index == size(path)
290
+ ? listener(thing, ...ids, ...extraArgsGetter(ids))
291
+ : isUndefined(path[index])
292
+ ? arrayForEach(pathGetters[index]?.(...ids) ?? [], (id2) =>
293
+ callWithIds(...ids, id2),
294
+ )
295
+ : callWithIds(...ids, path[index]);
296
+ };
297
+ callWithIds();
298
+ },
299
+ );
300
+ return [addListener, callListeners, delListener, callListener];
301
+ };
302
+
303
+ const pairNew = (value) => [value, value];
304
+ const pairCollSize2 = (pair, func = collSize2) => func(pair[0]) + func(pair[1]);
305
+ const pairNewMap = () => [mapNew(), mapNew()];
306
+ const pairClone = (array) => [...array];
307
+ const pairIsEqual = ([entry1, entry2]) => entry1 === entry2;
308
+
309
+ const getCellOrValueType = (cell) => {
310
+ const type = getTypeOf(cell);
311
+ return isTypeStringOrBoolean(type) || (type == NUMBER && isFiniteNumber(cell))
312
+ ? type
313
+ : void 0;
314
+ };
315
+ const setOrDelCell = (store, tableId, rowId, cellId, cell) =>
316
+ isUndefined(cell)
317
+ ? store.delCell(tableId, rowId, cellId, true)
318
+ : store.setCell(tableId, rowId, cellId, cell);
319
+ const setOrDelValue = (store, valueId, value) =>
320
+ isUndefined(value) ? store.delValue(valueId) : store.setValue(valueId, value);
321
+
322
+ const jsonString = (obj) =>
323
+ JSON.stringify(obj, (_key, value) =>
324
+ isInstanceOf(value, Map) ? object.fromEntries([...value]) : value,
325
+ );
326
+ const jsonParse = JSON.parse;
327
+
328
+ const defaultSorter = (sortKey1, sortKey2) =>
329
+ (sortKey1 ?? 0) < (sortKey2 ?? 0) ? -1 : 1;
330
+
331
+ const validate = (obj, validateChild, onInvalidObj) => {
332
+ if (isUndefined(obj) || !isObject(obj) || objIsEmpty(obj) || objFrozen(obj)) {
333
+ onInvalidObj?.();
334
+ return false;
335
+ }
336
+ objToArray(obj, (child, id2) => {
337
+ if (!validateChild(child, id2)) {
338
+ objDel(obj, id2);
339
+ }
340
+ });
341
+ return !objIsEmpty(obj);
342
+ };
343
+ const idsChanged = (changedIds, id2, addedOrRemoved) =>
344
+ mapSet(
345
+ changedIds,
346
+ id2,
347
+ mapGet(changedIds, id2) == -addedOrRemoved ? void 0 : addedOrRemoved,
348
+ );
349
+ const createStore = () => {
350
+ let hasTablesSchema;
351
+ let hasValuesSchema;
352
+ let cellsTouched = false;
353
+ let valuesTouched = false;
354
+ let hadTables = false;
355
+ let hadValues = false;
356
+ let transactions = 0;
357
+ let postTransactionListener;
358
+ const changedTableIds = mapNew();
359
+ const changedTableCellIds = mapNew();
360
+ const changedRowCount = mapNew();
361
+ const changedRowIds = mapNew();
362
+ const changedCellIds = mapNew();
363
+ const changedCells = mapNew();
364
+ const changedValueIds = mapNew();
365
+ const changedValues = mapNew();
366
+ const invalidCells = mapNew();
367
+ const invalidValues = mapNew();
368
+ const tablesSchemaMap = mapNew();
369
+ const tablesSchemaRowCache = mapNew();
370
+ const valuesSchemaMap = mapNew();
371
+ const valuesDefaulted = mapNew();
372
+ const valuesNonDefaulted = setNew();
373
+ const tablePoolFunctions = mapNew();
374
+ const tableCellIds = mapNew();
375
+ const tablesMap = mapNew();
376
+ const valuesMap = mapNew();
377
+ const hasTablesListeners = pairNewMap();
378
+ const tablesListeners = pairNewMap();
379
+ const tableIdsListeners = pairNewMap();
380
+ const hasTableListeners = pairNewMap();
381
+ const tableListeners = pairNewMap();
382
+ const tableCellIdsListeners = pairNewMap();
383
+ const hasTableCellListeners = pairNewMap();
384
+ const rowCountListeners = pairNewMap();
385
+ const rowIdsListeners = pairNewMap();
386
+ const sortedRowIdsListeners = pairNewMap();
387
+ const hasRowListeners = pairNewMap();
388
+ const rowListeners = pairNewMap();
389
+ const cellIdsListeners = pairNewMap();
390
+ const hasCellListeners = pairNewMap();
391
+ const cellListeners = pairNewMap();
392
+ const invalidCellListeners = pairNewMap();
393
+ const invalidValueListeners = pairNewMap();
394
+ const hasValuesListeners = pairNewMap();
395
+ const valuesListeners = pairNewMap();
396
+ const valueIdsListeners = pairNewMap();
397
+ const hasValueListeners = pairNewMap();
398
+ const valueListeners = pairNewMap();
399
+ const startTransactionListeners = mapNew();
400
+ const finishTransactionListeners = pairNewMap();
401
+ const [addListener, callListeners, delListenerImpl, callListenerImpl] =
402
+ getListenerFunctions(() => store);
403
+ const validateTablesSchema = (tableSchema) =>
404
+ validate(tableSchema, (tableSchema2) =>
405
+ validate(tableSchema2, validateCellOrValueSchema),
406
+ );
407
+ const validateValuesSchema = (valuesSchema) =>
408
+ validate(valuesSchema, validateCellOrValueSchema);
409
+ const validateCellOrValueSchema = (schema) => {
410
+ if (!validate(schema, (_child, id2) => arrayHas([TYPE, DEFAULT], id2))) {
411
+ return false;
412
+ }
413
+ const type = schema[TYPE];
414
+ if (!isTypeStringOrBoolean(type) && type != NUMBER) {
415
+ return false;
416
+ }
417
+ if (getCellOrValueType(schema[DEFAULT]) != type) {
418
+ objDel(schema, DEFAULT);
419
+ }
420
+ return true;
421
+ };
422
+ const validateTables = (tables) =>
423
+ validate(tables, validateTable, cellInvalid);
424
+ const validateTable = (table, tableId) =>
425
+ (!hasTablesSchema ||
426
+ collHas(tablesSchemaMap, tableId) ||
427
+ cellInvalid(tableId)) &&
428
+ validate(
429
+ table,
430
+ (row, rowId) => validateRow(tableId, rowId, row),
431
+ () => cellInvalid(tableId),
432
+ );
433
+ const validateRow = (tableId, rowId, row, skipDefaults) =>
434
+ validate(
435
+ skipDefaults ? row : addDefaultsToRow(row, tableId, rowId),
436
+ (cell, cellId) =>
437
+ ifNotUndefined(
438
+ getValidatedCell(tableId, rowId, cellId, cell),
439
+ (validCell) => {
440
+ row[cellId] = validCell;
441
+ return true;
442
+ },
443
+ () => false,
444
+ ),
445
+ () => cellInvalid(tableId, rowId),
446
+ );
447
+ const getValidatedCell = (tableId, rowId, cellId, cell) =>
448
+ hasTablesSchema
449
+ ? ifNotUndefined(
450
+ mapGet(mapGet(tablesSchemaMap, tableId), cellId),
451
+ (cellSchema) =>
452
+ getCellOrValueType(cell) != cellSchema[TYPE]
453
+ ? cellInvalid(tableId, rowId, cellId, cell, cellSchema[DEFAULT])
454
+ : cell,
455
+ () => cellInvalid(tableId, rowId, cellId, cell),
456
+ )
457
+ : isUndefined(getCellOrValueType(cell))
458
+ ? cellInvalid(tableId, rowId, cellId, cell)
459
+ : cell;
460
+ const validateValues = (values, skipDefaults) =>
461
+ validate(
462
+ skipDefaults ? values : addDefaultsToValues(values),
463
+ (value, valueId) =>
464
+ ifNotUndefined(
465
+ getValidatedValue(valueId, value),
466
+ (validValue) => {
467
+ values[valueId] = validValue;
468
+ return true;
469
+ },
470
+ () => false,
471
+ ),
472
+ () => valueInvalid(),
473
+ );
474
+ const getValidatedValue = (valueId, value) =>
475
+ hasValuesSchema
476
+ ? ifNotUndefined(
477
+ mapGet(valuesSchemaMap, valueId),
478
+ (valueSchema) =>
479
+ getCellOrValueType(value) != valueSchema[TYPE]
480
+ ? valueInvalid(valueId, value, valueSchema[DEFAULT])
481
+ : value,
482
+ () => valueInvalid(valueId, value),
483
+ )
484
+ : isUndefined(getCellOrValueType(value))
485
+ ? valueInvalid(valueId, value)
486
+ : value;
487
+ const addDefaultsToRow = (row, tableId, rowId) => {
488
+ ifNotUndefined(
489
+ mapGet(tablesSchemaRowCache, tableId),
490
+ ([rowDefaulted, rowNonDefaulted]) => {
491
+ collForEach(rowDefaulted, (cell, cellId) => {
492
+ if (!objHas(row, cellId)) {
493
+ row[cellId] = cell;
494
+ }
495
+ });
496
+ collForEach(rowNonDefaulted, (cellId) => {
497
+ if (!objHas(row, cellId)) {
498
+ cellInvalid(tableId, rowId, cellId);
499
+ }
500
+ });
501
+ },
502
+ );
503
+ return row;
504
+ };
505
+ const addDefaultsToValues = (values) => {
506
+ if (hasValuesSchema) {
507
+ collForEach(valuesDefaulted, (value, valueId) => {
508
+ if (!objHas(values, valueId)) {
509
+ values[valueId] = value;
510
+ }
511
+ });
512
+ collForEach(valuesNonDefaulted, (valueId) => {
513
+ if (!objHas(values, valueId)) {
514
+ valueInvalid(valueId);
515
+ }
516
+ });
517
+ }
518
+ return values;
519
+ };
520
+ const setValidTablesSchema = (tablesSchema) =>
521
+ mapMatch(
522
+ tablesSchemaMap,
523
+ tablesSchema,
524
+ (_tablesSchema, tableId, tableSchema) => {
525
+ const rowDefaulted = mapNew();
526
+ const rowNonDefaulted = setNew();
527
+ mapMatch(
528
+ mapEnsure(tablesSchemaMap, tableId, mapNew),
529
+ tableSchema,
530
+ (tableSchemaMap, cellId, cellSchema) => {
531
+ mapSet(tableSchemaMap, cellId, cellSchema);
532
+ ifNotUndefined(
533
+ cellSchema[DEFAULT],
534
+ (def) => mapSet(rowDefaulted, cellId, def),
535
+ () => setAdd(rowNonDefaulted, cellId),
536
+ );
537
+ },
538
+ );
539
+ mapSet(tablesSchemaRowCache, tableId, [rowDefaulted, rowNonDefaulted]);
540
+ },
541
+ (_tablesSchema, tableId) => {
542
+ mapSet(tablesSchemaMap, tableId);
543
+ mapSet(tablesSchemaRowCache, tableId);
544
+ },
545
+ );
546
+ const setValidValuesSchema = (valuesSchema) =>
547
+ mapMatch(
548
+ valuesSchemaMap,
549
+ valuesSchema,
550
+ (_valuesSchema, valueId, valueSchema) => {
551
+ mapSet(valuesSchemaMap, valueId, valueSchema);
552
+ ifNotUndefined(
553
+ valueSchema[DEFAULT],
554
+ (def) => mapSet(valuesDefaulted, valueId, def),
555
+ () => setAdd(valuesNonDefaulted, valueId),
556
+ );
557
+ },
558
+ (_valuesSchema, valueId) => {
559
+ mapSet(valuesSchemaMap, valueId);
560
+ mapSet(valuesDefaulted, valueId);
561
+ collDel(valuesNonDefaulted, valueId);
562
+ },
563
+ );
564
+ const setOrDelTables = (tables) =>
565
+ objIsEmpty(tables) ? delTables() : setTables(tables);
566
+ const setValidTables = (tables) =>
567
+ mapMatch(
568
+ tablesMap,
569
+ tables,
570
+ (_tables, tableId, table) => setValidTable(tableId, table),
571
+ (_tables, tableId) => delValidTable(tableId),
572
+ );
573
+ const setValidTable = (tableId, table) =>
574
+ mapMatch(
575
+ mapEnsure(tablesMap, tableId, () => {
576
+ tableIdsChanged(tableId, 1);
577
+ mapSet(tablePoolFunctions, tableId, getPoolFunctions());
578
+ mapSet(tableCellIds, tableId, mapNew());
579
+ return mapNew();
580
+ }),
581
+ table,
582
+ (tableMap, rowId, row) => setValidRow(tableId, tableMap, rowId, row),
583
+ (tableMap, rowId) => delValidRow(tableId, tableMap, rowId),
584
+ );
585
+ const setValidRow = (tableId, tableMap, rowId, row, forceDel) =>
586
+ mapMatch(
587
+ mapEnsure(tableMap, rowId, () => {
588
+ rowIdsChanged(tableId, rowId, 1);
589
+ return mapNew();
590
+ }),
591
+ row,
592
+ (rowMap, cellId, cell) =>
593
+ setValidCell(tableId, rowId, rowMap, cellId, cell),
594
+ (rowMap, cellId) =>
595
+ delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel),
596
+ );
597
+ const setValidCell = (tableId, rowId, rowMap, cellId, cell) => {
598
+ if (!collHas(rowMap, cellId)) {
599
+ cellIdsChanged(tableId, rowId, cellId, 1);
600
+ }
601
+ const oldCell = mapGet(rowMap, cellId);
602
+ if (cell !== oldCell) {
603
+ cellChanged(tableId, rowId, cellId, oldCell, cell);
604
+ mapSet(rowMap, cellId, cell);
605
+ }
606
+ };
607
+ const setCellIntoDefaultRow = (tableId, tableMap, rowId, cellId, validCell) =>
608
+ ifNotUndefined(
609
+ mapGet(tableMap, rowId),
610
+ (rowMap) => setValidCell(tableId, rowId, rowMap, cellId, validCell),
611
+ () =>
612
+ setValidRow(
613
+ tableId,
614
+ tableMap,
615
+ rowId,
616
+ addDefaultsToRow({[cellId]: validCell}, tableId, rowId),
617
+ ),
618
+ );
619
+ const setOrDelValues = (values) =>
620
+ objIsEmpty(values) ? delValues() : setValues(values);
621
+ const setValidValues = (values) =>
622
+ mapMatch(
623
+ valuesMap,
624
+ values,
625
+ (_valuesMap, valueId, value) => setValidValue(valueId, value),
626
+ (_valuesMap, valueId) => delValidValue(valueId),
627
+ );
628
+ const setValidValue = (valueId, value) => {
629
+ if (!collHas(valuesMap, valueId)) {
630
+ valueIdsChanged(valueId, 1);
631
+ }
632
+ const oldValue = mapGet(valuesMap, valueId);
633
+ if (value !== oldValue) {
634
+ valueChanged(valueId, oldValue, value);
635
+ mapSet(valuesMap, valueId, value);
636
+ }
637
+ };
638
+ const getNewRowId = (tableId, reuse) => {
639
+ const [getId] = mapGet(tablePoolFunctions, tableId);
640
+ const rowId = getId(reuse);
641
+ if (!collHas(mapGet(tablesMap, tableId), rowId)) {
642
+ return rowId;
643
+ }
644
+ return getNewRowId(tableId, reuse);
645
+ };
646
+ const getOrCreateTable = (tableId) =>
647
+ mapGet(tablesMap, tableId) ?? setValidTable(tableId, {});
648
+ const delValidTable = (tableId) => setValidTable(tableId, {});
649
+ const delValidRow = (tableId, tableMap, rowId) => {
650
+ const [, releaseId] = mapGet(tablePoolFunctions, tableId);
651
+ releaseId(rowId);
652
+ setValidRow(tableId, tableMap, rowId, {}, true);
653
+ };
654
+ const delValidCell = (tableId, table, rowId, row, cellId, forceDel) => {
655
+ const defaultCell = mapGet(
656
+ mapGet(tablesSchemaRowCache, tableId)?.[0],
657
+ cellId,
658
+ );
659
+ if (!isUndefined(defaultCell) && !forceDel) {
660
+ return setValidCell(tableId, rowId, row, cellId, defaultCell);
661
+ }
662
+ const delCell2 = (cellId2) => {
663
+ cellChanged(tableId, rowId, cellId2, mapGet(row, cellId2));
664
+ cellIdsChanged(tableId, rowId, cellId2, -1);
665
+ mapSet(row, cellId2);
666
+ };
667
+ isUndefined(defaultCell) ? delCell2(cellId) : mapForEach(row, delCell2);
668
+ if (collIsEmpty(row)) {
669
+ rowIdsChanged(tableId, rowId, -1);
670
+ if (collIsEmpty(mapSet(table, rowId))) {
671
+ tableIdsChanged(tableId, -1);
672
+ mapSet(tablesMap, tableId);
673
+ mapSet(tablePoolFunctions, tableId);
674
+ mapSet(tableCellIds, tableId);
675
+ }
676
+ }
677
+ };
678
+ const delValidValue = (valueId) => {
679
+ const defaultValue = mapGet(valuesDefaulted, valueId);
680
+ if (!isUndefined(defaultValue)) {
681
+ return setValidValue(valueId, defaultValue);
682
+ }
683
+ valueChanged(valueId, mapGet(valuesMap, valueId));
684
+ valueIdsChanged(valueId, -1);
685
+ mapSet(valuesMap, valueId);
686
+ };
687
+ const tableIdsChanged = (tableId, addedOrRemoved) =>
688
+ idsChanged(changedTableIds, tableId, addedOrRemoved);
689
+ const rowIdsChanged = (tableId, rowId, addedOrRemoved) =>
690
+ idsChanged(
691
+ mapEnsure(changedRowIds, tableId, mapNew),
692
+ rowId,
693
+ addedOrRemoved,
694
+ ) &&
695
+ mapSet(
696
+ changedRowCount,
697
+ tableId,
698
+ mapEnsure(changedRowCount, tableId, () => 0) + addedOrRemoved,
699
+ );
700
+ const cellIdsChanged = (tableId, rowId, cellId, addedOrRemoved) => {
701
+ const cellIds = mapGet(tableCellIds, tableId);
702
+ const count = mapGet(cellIds, cellId) ?? 0;
703
+ if (
704
+ (count == 0 && addedOrRemoved == 1) ||
705
+ (count == 1 && addedOrRemoved == -1)
706
+ ) {
707
+ idsChanged(
708
+ mapEnsure(changedTableCellIds, tableId, mapNew),
709
+ cellId,
710
+ addedOrRemoved,
711
+ );
712
+ }
713
+ mapSet(
714
+ cellIds,
715
+ cellId,
716
+ count != -addedOrRemoved ? count + addedOrRemoved : null,
717
+ );
718
+ idsChanged(
719
+ mapEnsure(mapEnsure(changedCellIds, tableId, mapNew), rowId, mapNew),
720
+ cellId,
721
+ addedOrRemoved,
722
+ );
723
+ };
724
+ const cellChanged = (tableId, rowId, cellId, oldCell, newCell) =>
725
+ (mapEnsure(
726
+ mapEnsure(mapEnsure(changedCells, tableId, mapNew), rowId, mapNew),
727
+ cellId,
728
+ () => [oldCell, 0],
729
+ )[1] = newCell);
730
+ const valueIdsChanged = (valueId, addedOrRemoved) =>
731
+ idsChanged(changedValueIds, valueId, addedOrRemoved);
732
+ const valueChanged = (valueId, oldValue, newValue) =>
733
+ (mapEnsure(changedValues, valueId, () => [oldValue, 0])[1] = newValue);
734
+ const cellInvalid = (tableId, rowId, cellId, invalidCell, defaultedCell) => {
735
+ arrayPush(
736
+ mapEnsure(
737
+ mapEnsure(mapEnsure(invalidCells, tableId, mapNew), rowId, mapNew),
738
+ cellId,
739
+ () => [],
740
+ ),
741
+ invalidCell,
742
+ );
743
+ return defaultedCell;
744
+ };
745
+ const valueInvalid = (valueId, invalidValue, defaultedValue) => {
746
+ arrayPush(
747
+ mapEnsure(invalidValues, valueId, () => []),
748
+ invalidValue,
749
+ );
750
+ return defaultedValue;
751
+ };
752
+ const getCellChange = (tableId, rowId, cellId) =>
753
+ ifNotUndefined(
754
+ mapGet(mapGet(mapGet(changedCells, tableId), rowId), cellId),
755
+ ([oldCell, newCell]) => [true, oldCell, newCell],
756
+ () => [false, ...pairNew(getCell(tableId, rowId, cellId))],
757
+ );
758
+ const getValueChange = (valueId) =>
759
+ ifNotUndefined(
760
+ mapGet(changedValues, valueId),
761
+ ([oldValue, newValue]) => [true, oldValue, newValue],
762
+ () => [false, ...pairNew(getValue(valueId))],
763
+ );
764
+ const callInvalidCellListeners = (mutator) =>
765
+ !collIsEmpty(invalidCells) && !collIsEmpty(invalidCellListeners[mutator])
766
+ ? collForEach(
767
+ mutator ? mapClone3(invalidCells) : invalidCells,
768
+ (rows, tableId) =>
769
+ collForEach(rows, (cells, rowId) =>
770
+ collForEach(cells, (invalidCell, cellId) =>
771
+ callListeners(
772
+ invalidCellListeners[mutator],
773
+ [tableId, rowId, cellId],
774
+ invalidCell,
775
+ ),
776
+ ),
777
+ ),
778
+ )
779
+ : 0;
780
+ const callInvalidValueListeners = (mutator) =>
781
+ !collIsEmpty(invalidValues) && !collIsEmpty(invalidValueListeners[mutator])
782
+ ? collForEach(
783
+ mutator ? mapClone(invalidValues) : invalidValues,
784
+ (invalidValue, valueId) =>
785
+ callListeners(
786
+ invalidValueListeners[mutator],
787
+ [valueId],
788
+ invalidValue,
789
+ ),
790
+ )
791
+ : 0;
792
+ const callIdsAndHasListenersIfChanged = (
793
+ changedIds,
794
+ idListeners,
795
+ hasListeners,
796
+ ids,
797
+ ) => {
798
+ if (!collIsEmpty(changedIds)) {
799
+ callListeners(idListeners, ids, () => mapToObj(changedIds));
800
+ mapForEach(changedIds, (changedId, changed) =>
801
+ callListeners(hasListeners, [...(ids ?? []), changedId], changed == 1),
802
+ );
803
+ return 1;
804
+ }
805
+ };
806
+ const callTabularListenersForChanges = (mutator) => {
807
+ const hasTablesNow = hasTables();
808
+ if (hasTablesNow != hadTables) {
809
+ callListeners(hasTablesListeners[mutator], void 0, hasTablesNow);
810
+ }
811
+ const emptySortedRowIdListeners = collIsEmpty(
812
+ sortedRowIdsListeners[mutator],
813
+ );
814
+ const emptyIdAndHasListeners =
815
+ collIsEmpty(cellIdsListeners[mutator]) &&
816
+ collIsEmpty(hasCellListeners[mutator]) &&
817
+ collIsEmpty(rowIdsListeners[mutator]) &&
818
+ collIsEmpty(hasRowListeners[mutator]) &&
819
+ collIsEmpty(tableCellIdsListeners[mutator]) &&
820
+ collIsEmpty(hasTableCellListeners[mutator]) &&
821
+ collIsEmpty(rowCountListeners[mutator]) &&
822
+ emptySortedRowIdListeners &&
823
+ collIsEmpty(tableIdsListeners[mutator]) &&
824
+ collIsEmpty(hasTableListeners[mutator]);
825
+ const emptyOtherListeners =
826
+ collIsEmpty(cellListeners[mutator]) &&
827
+ collIsEmpty(rowListeners[mutator]) &&
828
+ collIsEmpty(tableListeners[mutator]) &&
829
+ collIsEmpty(tablesListeners[mutator]);
830
+ if (!emptyIdAndHasListeners || !emptyOtherListeners) {
831
+ const changes = mutator
832
+ ? [
833
+ mapClone(changedTableIds),
834
+ mapClone2(changedTableCellIds),
835
+ mapClone(changedRowCount),
836
+ mapClone2(changedRowIds),
837
+ mapClone3(changedCellIds),
838
+ mapClone3(changedCells),
839
+ ]
840
+ : [
841
+ changedTableIds,
842
+ changedTableCellIds,
843
+ changedRowCount,
844
+ changedRowIds,
845
+ changedCellIds,
846
+ changedCells,
847
+ ];
848
+ if (!emptyIdAndHasListeners) {
849
+ callIdsAndHasListenersIfChanged(
850
+ changes[0],
851
+ tableIdsListeners[mutator],
852
+ hasTableListeners[mutator],
853
+ );
854
+ collForEach(changes[1], (changedIds, tableId) =>
855
+ callIdsAndHasListenersIfChanged(
856
+ changedIds,
857
+ tableCellIdsListeners[mutator],
858
+ hasTableCellListeners[mutator],
859
+ [tableId],
860
+ ),
861
+ );
862
+ collForEach(changes[2], (changedCount, tableId) => {
863
+ if (changedCount != 0) {
864
+ callListeners(
865
+ rowCountListeners[mutator],
866
+ [tableId],
867
+ getRowCount(tableId),
868
+ );
869
+ }
870
+ });
871
+ const calledSortableTableIds = setNew();
872
+ collForEach(changes[3], (changedIds, tableId) => {
873
+ if (
874
+ callIdsAndHasListenersIfChanged(
875
+ changedIds,
876
+ rowIdsListeners[mutator],
877
+ hasRowListeners[mutator],
878
+ [tableId],
879
+ ) &&
880
+ !emptySortedRowIdListeners
881
+ ) {
882
+ callListeners(sortedRowIdsListeners[mutator], [tableId, null]);
883
+ setAdd(calledSortableTableIds, tableId);
884
+ }
885
+ });
886
+ if (!emptySortedRowIdListeners) {
887
+ collForEach(changes[5], (rows, tableId) => {
888
+ if (!collHas(calledSortableTableIds, tableId)) {
889
+ const sortableCellIds = setNew();
890
+ collForEach(rows, (cells) =>
891
+ collForEach(cells, ([oldCell, newCell], cellId) =>
892
+ newCell !== oldCell
893
+ ? setAdd(sortableCellIds, cellId)
894
+ : collDel(cells, cellId),
895
+ ),
896
+ );
897
+ collForEach(sortableCellIds, (cellId) =>
898
+ callListeners(sortedRowIdsListeners[mutator], [
899
+ tableId,
900
+ cellId,
901
+ ]),
902
+ );
903
+ }
904
+ });
905
+ }
906
+ collForEach(changes[4], (rowCellIds, tableId) =>
907
+ collForEach(rowCellIds, (changedIds, rowId) =>
908
+ callIdsAndHasListenersIfChanged(
909
+ changedIds,
910
+ cellIdsListeners[mutator],
911
+ hasCellListeners[mutator],
912
+ [tableId, rowId],
913
+ ),
914
+ ),
915
+ );
916
+ }
917
+ if (!emptyOtherListeners) {
918
+ let tablesChanged;
919
+ collForEach(changes[5], (rows, tableId) => {
920
+ let tableChanged;
921
+ collForEach(rows, (cells, rowId) => {
922
+ let rowChanged;
923
+ collForEach(cells, ([oldCell, newCell], cellId) => {
924
+ if (newCell !== oldCell) {
925
+ callListeners(
926
+ cellListeners[mutator],
927
+ [tableId, rowId, cellId],
928
+ newCell,
929
+ oldCell,
930
+ getCellChange,
931
+ );
932
+ tablesChanged = tableChanged = rowChanged = 1;
933
+ }
934
+ });
935
+ if (rowChanged) {
936
+ callListeners(
937
+ rowListeners[mutator],
938
+ [tableId, rowId],
939
+ getCellChange,
940
+ );
941
+ }
942
+ });
943
+ if (tableChanged) {
944
+ callListeners(tableListeners[mutator], [tableId], getCellChange);
945
+ }
946
+ });
947
+ if (tablesChanged) {
948
+ callListeners(tablesListeners[mutator], void 0, getCellChange);
949
+ }
950
+ }
951
+ }
952
+ };
953
+ const callValuesListenersForChanges = (mutator) => {
954
+ const hasValuesNow = hasValues();
955
+ if (hasValuesNow != hadValues) {
956
+ callListeners(hasValuesListeners[mutator], void 0, hasValuesNow);
957
+ }
958
+ const emptyIdAndHasListeners =
959
+ collIsEmpty(valueIdsListeners[mutator]) &&
960
+ collIsEmpty(hasValueListeners[mutator]);
961
+ const emptyOtherListeners =
962
+ collIsEmpty(valueListeners[mutator]) &&
963
+ collIsEmpty(valuesListeners[mutator]);
964
+ if (!emptyIdAndHasListeners || !emptyOtherListeners) {
965
+ const changes = mutator
966
+ ? [mapClone(changedValueIds), mapClone(changedValues)]
967
+ : [changedValueIds, changedValues];
968
+ if (!emptyIdAndHasListeners) {
969
+ callIdsAndHasListenersIfChanged(
970
+ changes[0],
971
+ valueIdsListeners[mutator],
972
+ hasValueListeners[mutator],
973
+ );
974
+ }
975
+ if (!emptyOtherListeners) {
976
+ let valuesChanged;
977
+ collForEach(changes[1], ([oldValue, newValue], valueId) => {
978
+ if (newValue !== oldValue) {
979
+ callListeners(
980
+ valueListeners[mutator],
981
+ [valueId],
982
+ newValue,
983
+ oldValue,
984
+ getValueChange,
985
+ );
986
+ valuesChanged = 1;
987
+ }
988
+ });
989
+ if (valuesChanged) {
990
+ callListeners(valuesListeners[mutator], void 0, getValueChange);
991
+ }
992
+ }
993
+ }
994
+ };
995
+ const fluentTransaction = (actions, ...args) => {
996
+ transaction(() => actions(...arrayMap(args, id)));
997
+ return store;
998
+ };
999
+ const getTransactionChanges = () => [
1000
+ mapToObj(
1001
+ changedCells,
1002
+ (table, tableId) =>
1003
+ mapGet(changedTableIds, tableId) === -1
1004
+ ? null
1005
+ : mapToObj(
1006
+ table,
1007
+ (row, rowId) =>
1008
+ mapGet(mapGet(changedRowIds, tableId), rowId) === -1
1009
+ ? null
1010
+ : mapToObj(
1011
+ row,
1012
+ ([, newCell]) => newCell ?? null,
1013
+ (_, changedCell) => pairIsEqual(changedCell),
1014
+ ),
1015
+ objIsEmpty,
1016
+ ),
1017
+ objIsEmpty,
1018
+ ),
1019
+ mapToObj(
1020
+ changedValues,
1021
+ ([, newValue]) => newValue ?? null,
1022
+ (_, changedValue) => pairIsEqual(changedValue),
1023
+ ),
1024
+ ];
1025
+ const getTransactionLog = () => ({
1026
+ cellsTouched,
1027
+ valuesTouched,
1028
+ changedCells: mapToObj3(changedCells, pairClone, pairIsEqual),
1029
+ invalidCells: mapToObj3(invalidCells),
1030
+ changedValues: mapToObj(changedValues, pairClone, pairIsEqual),
1031
+ invalidValues: mapToObj(invalidValues),
1032
+ changedTableIds: mapToObj(changedTableIds),
1033
+ changedRowIds: mapToObj2(changedRowIds),
1034
+ changedCellIds: mapToObj3(changedCellIds),
1035
+ changedValueIds: mapToObj(changedValueIds),
1036
+ });
1037
+ const getContent = () => [getTables(), getValues()];
1038
+ const getTables = () => mapToObj3(tablesMap);
1039
+ const getTableIds = () => mapKeys(tablesMap);
1040
+ const getTable = (tableId) => mapToObj2(mapGet(tablesMap, id(tableId)));
1041
+ const getTableCellIds = (tableId) =>
1042
+ mapKeys(mapGet(tableCellIds, id(tableId)));
1043
+ const getRowCount = (tableId) => collSize(mapGet(tablesMap, id(tableId)));
1044
+ const getRowIds = (tableId) => mapKeys(mapGet(tablesMap, id(tableId)));
1045
+ const getSortedRowIds = (tableId, cellId, descending, offset = 0, limit) =>
1046
+ arrayMap(
1047
+ slice(
1048
+ arraySort(
1049
+ mapMap(mapGet(tablesMap, id(tableId)), (row, rowId) => [
1050
+ isUndefined(cellId) ? rowId : mapGet(row, id(cellId)),
1051
+ rowId,
1052
+ ]),
1053
+ ([cell1], [cell2]) =>
1054
+ defaultSorter(cell1, cell2) * (descending ? -1 : 1),
1055
+ ),
1056
+ offset,
1057
+ isUndefined(limit) ? limit : offset + limit,
1058
+ ),
1059
+ ([, rowId]) => rowId,
1060
+ );
1061
+ const getRow = (tableId, rowId) =>
1062
+ mapToObj(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)));
1063
+ const getCellIds = (tableId, rowId) =>
1064
+ mapKeys(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)));
1065
+ const getCell = (tableId, rowId, cellId) =>
1066
+ mapGet(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)), id(cellId));
1067
+ const getValues = () => mapToObj(valuesMap);
1068
+ const getValueIds = () => mapKeys(valuesMap);
1069
+ const getValue = (valueId) => mapGet(valuesMap, id(valueId));
1070
+ const hasTables = () => !collIsEmpty(tablesMap);
1071
+ const hasTable = (tableId) => collHas(tablesMap, id(tableId));
1072
+ const hasTableCell = (tableId, cellId) =>
1073
+ collHas(mapGet(tableCellIds, id(tableId)), id(cellId));
1074
+ const hasRow = (tableId, rowId) =>
1075
+ collHas(mapGet(tablesMap, id(tableId)), id(rowId));
1076
+ const hasCell = (tableId, rowId, cellId) =>
1077
+ collHas(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)), id(cellId));
1078
+ const hasValues = () => !collIsEmpty(valuesMap);
1079
+ const hasValue = (valueId) => collHas(valuesMap, id(valueId));
1080
+ const getTablesJson = () => jsonString(tablesMap);
1081
+ const getValuesJson = () => jsonString(valuesMap);
1082
+ const getJson = () => jsonString([tablesMap, valuesMap]);
1083
+ const getTablesSchemaJson = () => jsonString(tablesSchemaMap);
1084
+ const getValuesSchemaJson = () => jsonString(valuesSchemaMap);
1085
+ const getSchemaJson = () => jsonString([tablesSchemaMap, valuesSchemaMap]);
1086
+ const setContent = ([tables, values]) =>
1087
+ fluentTransaction(() => {
1088
+ (objIsEmpty(tables) ? delTables : setTables)(tables);
1089
+ (objIsEmpty(values) ? delValues : setValues)(values);
1090
+ });
1091
+ const setTables = (tables) =>
1092
+ fluentTransaction(() =>
1093
+ validateTables(tables) ? setValidTables(tables) : 0,
1094
+ );
1095
+ const setTable = (tableId, table) =>
1096
+ fluentTransaction(
1097
+ (tableId2) =>
1098
+ validateTable(table, tableId2) ? setValidTable(tableId2, table) : 0,
1099
+ tableId,
1100
+ );
1101
+ const setRow = (tableId, rowId, row) =>
1102
+ fluentTransaction(
1103
+ (tableId2, rowId2) =>
1104
+ validateRow(tableId2, rowId2, row)
1105
+ ? setValidRow(tableId2, getOrCreateTable(tableId2), rowId2, row)
1106
+ : 0,
1107
+ tableId,
1108
+ rowId,
1109
+ );
1110
+ const addRow = (tableId, row, reuseRowIds = true) =>
1111
+ transaction(() => {
1112
+ let rowId = void 0;
1113
+ if (validateRow(tableId, rowId, row)) {
1114
+ tableId = id(tableId);
1115
+ setValidRow(
1116
+ tableId,
1117
+ getOrCreateTable(tableId),
1118
+ (rowId = getNewRowId(tableId, reuseRowIds ? 1 : 0)),
1119
+ row,
1120
+ );
1121
+ }
1122
+ return rowId;
1123
+ });
1124
+ const setPartialRow = (tableId, rowId, partialRow) =>
1125
+ fluentTransaction(
1126
+ (tableId2, rowId2) => {
1127
+ if (validateRow(tableId2, rowId2, partialRow, 1)) {
1128
+ const table = getOrCreateTable(tableId2);
1129
+ objToArray(partialRow, (cell, cellId) =>
1130
+ setCellIntoDefaultRow(tableId2, table, rowId2, cellId, cell),
1131
+ );
1132
+ }
1133
+ },
1134
+ tableId,
1135
+ rowId,
1136
+ );
1137
+ const setCell = (tableId, rowId, cellId, cell) =>
1138
+ fluentTransaction(
1139
+ (tableId2, rowId2, cellId2) =>
1140
+ ifNotUndefined(
1141
+ getValidatedCell(
1142
+ tableId2,
1143
+ rowId2,
1144
+ cellId2,
1145
+ isFunction(cell) ? cell(getCell(tableId2, rowId2, cellId2)) : cell,
1146
+ ),
1147
+ (validCell) =>
1148
+ setCellIntoDefaultRow(
1149
+ tableId2,
1150
+ getOrCreateTable(tableId2),
1151
+ rowId2,
1152
+ cellId2,
1153
+ validCell,
1154
+ ),
1155
+ ),
1156
+ tableId,
1157
+ rowId,
1158
+ cellId,
1159
+ );
1160
+ const setValues = (values) =>
1161
+ fluentTransaction(() =>
1162
+ validateValues(values) ? setValidValues(values) : 0,
1163
+ );
1164
+ const setPartialValues = (partialValues) =>
1165
+ fluentTransaction(() =>
1166
+ validateValues(partialValues, 1)
1167
+ ? objToArray(partialValues, (value, valueId) =>
1168
+ setValidValue(valueId, value),
1169
+ )
1170
+ : 0,
1171
+ );
1172
+ const setValue = (valueId, value) =>
1173
+ fluentTransaction(
1174
+ (valueId2) =>
1175
+ ifNotUndefined(
1176
+ getValidatedValue(
1177
+ valueId2,
1178
+ isFunction(value) ? value(getValue(valueId2)) : value,
1179
+ ),
1180
+ (validValue) => setValidValue(valueId2, validValue),
1181
+ ),
1182
+ valueId,
1183
+ );
1184
+ const setTransactionChanges = (transactionChanges) =>
1185
+ fluentTransaction(() => {
1186
+ objToArray(transactionChanges[0], (table, tableId) =>
1187
+ isUndefined(table)
1188
+ ? delTable(tableId)
1189
+ : objToArray(table, (row, rowId) =>
1190
+ isUndefined(row)
1191
+ ? delRow(tableId, rowId)
1192
+ : objToArray(row, (cell, cellId) =>
1193
+ setOrDelCell(store, tableId, rowId, cellId, cell),
1194
+ ),
1195
+ ),
1196
+ );
1197
+ objToArray(transactionChanges[1], (value, valueId) =>
1198
+ setOrDelValue(store, valueId, value),
1199
+ );
1200
+ });
1201
+ const setTablesJson = (tablesJson) => {
1202
+ try {
1203
+ setOrDelTables(jsonParse(tablesJson));
1204
+ } catch {}
1205
+ return store;
1206
+ };
1207
+ const setValuesJson = (valuesJson) => {
1208
+ try {
1209
+ setOrDelValues(jsonParse(valuesJson));
1210
+ } catch {}
1211
+ return store;
1212
+ };
1213
+ const setJson = (tablesAndValuesJson) =>
1214
+ fluentTransaction(() => {
1215
+ try {
1216
+ const [tables, values] = jsonParse(tablesAndValuesJson);
1217
+ setOrDelTables(tables);
1218
+ setOrDelValues(values);
1219
+ } catch {
1220
+ setTablesJson(tablesAndValuesJson);
1221
+ }
1222
+ });
1223
+ const setTablesSchema = (tablesSchema) =>
1224
+ fluentTransaction(() => {
1225
+ if ((hasTablesSchema = validateTablesSchema(tablesSchema))) {
1226
+ setValidTablesSchema(tablesSchema);
1227
+ if (!collIsEmpty(tablesMap)) {
1228
+ const tables = getTables();
1229
+ delTables();
1230
+ setTables(tables);
1231
+ }
1232
+ }
1233
+ });
1234
+ const setValuesSchema = (valuesSchema) =>
1235
+ fluentTransaction(() => {
1236
+ if ((hasValuesSchema = validateValuesSchema(valuesSchema))) {
1237
+ const values = getValues();
1238
+ delValuesSchema();
1239
+ delValues();
1240
+ hasValuesSchema = true;
1241
+ setValidValuesSchema(valuesSchema);
1242
+ setValues(values);
1243
+ }
1244
+ });
1245
+ const setSchema = (tablesSchema, valuesSchema) =>
1246
+ fluentTransaction(() => {
1247
+ setTablesSchema(tablesSchema);
1248
+ setValuesSchema(valuesSchema);
1249
+ });
1250
+ const delTables = () => fluentTransaction(() => setValidTables({}));
1251
+ const delTable = (tableId) =>
1252
+ fluentTransaction(
1253
+ (tableId2) =>
1254
+ collHas(tablesMap, tableId2) ? delValidTable(tableId2) : 0,
1255
+ tableId,
1256
+ );
1257
+ const delRow = (tableId, rowId) =>
1258
+ fluentTransaction(
1259
+ (tableId2, rowId2) =>
1260
+ ifNotUndefined(mapGet(tablesMap, tableId2), (tableMap) =>
1261
+ collHas(tableMap, rowId2)
1262
+ ? delValidRow(tableId2, tableMap, rowId2)
1263
+ : 0,
1264
+ ),
1265
+ tableId,
1266
+ rowId,
1267
+ );
1268
+ const delCell = (tableId, rowId, cellId, forceDel) =>
1269
+ fluentTransaction(
1270
+ (tableId2, rowId2, cellId2) =>
1271
+ ifNotUndefined(mapGet(tablesMap, tableId2), (tableMap) =>
1272
+ ifNotUndefined(mapGet(tableMap, rowId2), (rowMap) =>
1273
+ collHas(rowMap, cellId2)
1274
+ ? delValidCell(
1275
+ tableId2,
1276
+ tableMap,
1277
+ rowId2,
1278
+ rowMap,
1279
+ cellId2,
1280
+ forceDel,
1281
+ )
1282
+ : 0,
1283
+ ),
1284
+ ),
1285
+ tableId,
1286
+ rowId,
1287
+ cellId,
1288
+ );
1289
+ const delValues = () => fluentTransaction(() => setValidValues({}));
1290
+ const delValue = (valueId) =>
1291
+ fluentTransaction(
1292
+ (valueId2) =>
1293
+ collHas(valuesMap, valueId2) ? delValidValue(valueId2) : 0,
1294
+ valueId,
1295
+ );
1296
+ const delTablesSchema = () =>
1297
+ fluentTransaction(() => {
1298
+ setValidTablesSchema({});
1299
+ hasTablesSchema = false;
1300
+ });
1301
+ const delValuesSchema = () =>
1302
+ fluentTransaction(() => {
1303
+ setValidValuesSchema({});
1304
+ hasValuesSchema = false;
1305
+ });
1306
+ const delSchema = () =>
1307
+ fluentTransaction(() => {
1308
+ delTablesSchema();
1309
+ delValuesSchema();
1310
+ });
1311
+ const transaction = (actions, doRollback) => {
1312
+ if (transactions != -1) {
1313
+ startTransaction();
1314
+ const result = actions();
1315
+ finishTransaction(doRollback);
1316
+ return result;
1317
+ }
1318
+ };
1319
+ const startTransaction = () => {
1320
+ if (transactions != -1) {
1321
+ transactions++;
1322
+ }
1323
+ if (transactions == 1) {
1324
+ callListeners(
1325
+ startTransactionListeners,
1326
+ void 0,
1327
+ getTransactionChanges,
1328
+ getTransactionLog,
1329
+ );
1330
+ }
1331
+ return store;
1332
+ };
1333
+ const finishTransaction = (doRollback) => {
1334
+ if (transactions > 0) {
1335
+ transactions--;
1336
+ if (transactions == 0) {
1337
+ cellsTouched = !collIsEmpty(changedCells);
1338
+ valuesTouched = !collIsEmpty(changedValues);
1339
+ transactions = 1;
1340
+ callInvalidCellListeners(1);
1341
+ if (cellsTouched) {
1342
+ callTabularListenersForChanges(1);
1343
+ }
1344
+ callInvalidValueListeners(1);
1345
+ if (valuesTouched) {
1346
+ callValuesListenersForChanges(1);
1347
+ }
1348
+ if (doRollback?.(getTransactionChanges, getTransactionLog)) {
1349
+ collForEach(changedCells, (table, tableId) =>
1350
+ collForEach(table, (row, rowId) =>
1351
+ collForEach(row, ([oldCell], cellId) =>
1352
+ setOrDelCell(store, tableId, rowId, cellId, oldCell),
1353
+ ),
1354
+ ),
1355
+ );
1356
+ collForEach(changedValues, ([oldValue], valueId) =>
1357
+ setOrDelValue(store, valueId, oldValue),
1358
+ );
1359
+ cellsTouched = valuesTouched = false;
1360
+ }
1361
+ callListeners(
1362
+ finishTransactionListeners[0],
1363
+ void 0,
1364
+ getTransactionChanges,
1365
+ getTransactionLog,
1366
+ );
1367
+ transactions = -1;
1368
+ callInvalidCellListeners(0);
1369
+ if (cellsTouched) {
1370
+ callTabularListenersForChanges(0);
1371
+ }
1372
+ callInvalidValueListeners(0);
1373
+ if (valuesTouched) {
1374
+ callValuesListenersForChanges(0);
1375
+ }
1376
+ callListeners(
1377
+ finishTransactionListeners[1],
1378
+ void 0,
1379
+ getTransactionChanges,
1380
+ getTransactionLog,
1381
+ );
1382
+ postTransactionListener?.(
1383
+ store,
1384
+ getTransactionChanges,
1385
+ getTransactionLog,
1386
+ );
1387
+ transactions = 0;
1388
+ cellsTouched = valuesTouched = false;
1389
+ hadTables = hasTables();
1390
+ hadValues = hasValues();
1391
+ arrayForEach(
1392
+ [
1393
+ changedTableIds,
1394
+ changedTableCellIds,
1395
+ changedRowCount,
1396
+ changedRowIds,
1397
+ changedCellIds,
1398
+ changedCells,
1399
+ invalidCells,
1400
+ changedValueIds,
1401
+ changedValues,
1402
+ invalidValues,
1403
+ ],
1404
+ collClear,
1405
+ );
1406
+ }
1407
+ }
1408
+ return store;
1409
+ };
1410
+ const forEachTable = (tableCallback) =>
1411
+ collForEach(tablesMap, (tableMap, tableId) =>
1412
+ tableCallback(tableId, (rowCallback) =>
1413
+ collForEach(tableMap, (rowMap, rowId) =>
1414
+ rowCallback(rowId, (cellCallback) =>
1415
+ mapForEach(rowMap, cellCallback),
1416
+ ),
1417
+ ),
1418
+ ),
1419
+ );
1420
+ const forEachTableCell = (tableId, tableCellCallback) =>
1421
+ mapForEach(mapGet(tableCellIds, id(tableId)), tableCellCallback);
1422
+ const forEachRow = (tableId, rowCallback) =>
1423
+ collForEach(mapGet(tablesMap, id(tableId)), (rowMap, rowId) =>
1424
+ rowCallback(rowId, (cellCallback) => mapForEach(rowMap, cellCallback)),
1425
+ );
1426
+ const forEachCell = (tableId, rowId, cellCallback) =>
1427
+ mapForEach(mapGet(mapGet(tablesMap, id(tableId)), id(rowId)), cellCallback);
1428
+ const forEachValue = (valueCallback) => mapForEach(valuesMap, valueCallback);
1429
+ const addSortedRowIdsListener = (
1430
+ tableId,
1431
+ cellId,
1432
+ descending,
1433
+ offset,
1434
+ limit,
1435
+ listener,
1436
+ mutator,
1437
+ ) => {
1438
+ let sortedRowIds = getSortedRowIds(
1439
+ tableId,
1440
+ cellId,
1441
+ descending,
1442
+ offset,
1443
+ limit,
1444
+ );
1445
+ return addListener(
1446
+ () => {
1447
+ const newSortedRowIds = getSortedRowIds(
1448
+ tableId,
1449
+ cellId,
1450
+ descending,
1451
+ offset,
1452
+ limit,
1453
+ );
1454
+ if (!arrayIsEqual(newSortedRowIds, sortedRowIds)) {
1455
+ sortedRowIds = newSortedRowIds;
1456
+ listener(
1457
+ store,
1458
+ tableId,
1459
+ cellId,
1460
+ descending,
1461
+ offset,
1462
+ limit,
1463
+ sortedRowIds,
1464
+ );
1465
+ }
1466
+ },
1467
+ sortedRowIdsListeners[mutator ? 1 : 0],
1468
+ [tableId, cellId],
1469
+ [getTableIds],
1470
+ );
1471
+ };
1472
+ const addStartTransactionListener = (listener) =>
1473
+ addListener(listener, startTransactionListeners);
1474
+ const addWillFinishTransactionListener = (listener) =>
1475
+ addListener(listener, finishTransactionListeners[0]);
1476
+ const addDidFinishTransactionListener = (listener) =>
1477
+ addListener(listener, finishTransactionListeners[1]);
1478
+ const callListener = (listenerId) => {
1479
+ callListenerImpl(listenerId);
1480
+ return store;
1481
+ };
1482
+ const delListener = (listenerId) => {
1483
+ delListenerImpl(listenerId);
1484
+ return store;
1485
+ };
1486
+ const getListenerStats = () => ({
1487
+ hasTables: pairCollSize2(hasTablesListeners),
1488
+ tables: pairCollSize2(tablesListeners),
1489
+ tableIds: pairCollSize2(tableIdsListeners),
1490
+ hasTable: pairCollSize2(hasTableListeners),
1491
+ table: pairCollSize2(tableListeners),
1492
+ tableCellIds: pairCollSize2(tableCellIdsListeners),
1493
+ hasTableCell: pairCollSize2(hasTableCellListeners, collSize3),
1494
+ rowCount: pairCollSize2(rowCountListeners),
1495
+ rowIds: pairCollSize2(rowIdsListeners),
1496
+ sortedRowIds: pairCollSize2(sortedRowIdsListeners),
1497
+ hasRow: pairCollSize2(hasRowListeners, collSize3),
1498
+ row: pairCollSize2(rowListeners, collSize3),
1499
+ cellIds: pairCollSize2(cellIdsListeners, collSize3),
1500
+ hasCell: pairCollSize2(hasCellListeners, collSize4),
1501
+ cell: pairCollSize2(cellListeners, collSize4),
1502
+ invalidCell: pairCollSize2(invalidCellListeners, collSize4),
1503
+ hasValues: pairCollSize2(hasValuesListeners),
1504
+ values: pairCollSize2(valuesListeners),
1505
+ valueIds: pairCollSize2(valueIdsListeners),
1506
+ hasValue: pairCollSize2(hasValueListeners),
1507
+ value: pairCollSize2(valueListeners),
1508
+ invalidValue: pairCollSize2(invalidValueListeners),
1509
+ transaction:
1510
+ collSize2(startTransactionListeners) +
1511
+ pairCollSize2(finishTransactionListeners),
1512
+ });
1513
+ const addPostTransactionListener = (listener) => {
1514
+ postTransactionListener = listener;
1515
+ };
1516
+ const store = {
1517
+ getContent,
1518
+ getTables,
1519
+ getTableIds,
1520
+ getTable,
1521
+ getTableCellIds,
1522
+ getRowCount,
1523
+ getRowIds,
1524
+ getSortedRowIds,
1525
+ getRow,
1526
+ getCellIds,
1527
+ getCell,
1528
+ getValues,
1529
+ getValueIds,
1530
+ getValue,
1531
+ hasTables,
1532
+ hasTable,
1533
+ hasTableCell,
1534
+ hasRow,
1535
+ hasCell,
1536
+ hasValues,
1537
+ hasValue,
1538
+ getTablesJson,
1539
+ getValuesJson,
1540
+ getJson,
1541
+ getTablesSchemaJson,
1542
+ getValuesSchemaJson,
1543
+ getSchemaJson,
1544
+ hasTablesSchema: () => hasTablesSchema,
1545
+ hasValuesSchema: () => hasValuesSchema,
1546
+ setContent,
1547
+ setTables,
1548
+ setTable,
1549
+ setRow,
1550
+ addRow,
1551
+ setPartialRow,
1552
+ setCell,
1553
+ setValues,
1554
+ setPartialValues,
1555
+ setValue,
1556
+ setTransactionChanges,
1557
+ setTablesJson,
1558
+ setValuesJson,
1559
+ setJson,
1560
+ setTablesSchema,
1561
+ setValuesSchema,
1562
+ setSchema,
1563
+ delTables,
1564
+ delTable,
1565
+ delRow,
1566
+ delCell,
1567
+ delValues,
1568
+ delValue,
1569
+ delTablesSchema,
1570
+ delValuesSchema,
1571
+ delSchema,
1572
+ transaction,
1573
+ startTransaction,
1574
+ finishTransaction,
1575
+ forEachTable,
1576
+ forEachTableCell,
1577
+ forEachRow,
1578
+ forEachCell,
1579
+ forEachValue,
1580
+ addSortedRowIdsListener,
1581
+ addStartTransactionListener,
1582
+ addWillFinishTransactionListener,
1583
+ addDidFinishTransactionListener,
1584
+ callListener,
1585
+ delListener,
1586
+ getListenerStats,
1587
+ // only used internally by other modules
1588
+ createStore,
1589
+ addListener,
1590
+ callListeners,
1591
+ addPostTransactionListener,
1592
+ };
1593
+ objToArray(
1594
+ {
1595
+ [HAS + TABLES]: [0, hasTablesListeners, [], () => [hasTables()]],
1596
+ [TABLES]: [0, tablesListeners],
1597
+ [TABLE_IDS]: [0, tableIdsListeners],
1598
+ [HAS + TABLE]: [
1599
+ 1,
1600
+ hasTableListeners,
1601
+ [getTableIds],
1602
+ (ids) => [hasTable(...ids)],
1603
+ ],
1604
+ [TABLE]: [1, tableListeners, [getTableIds]],
1605
+ [TABLE + CELL_IDS]: [1, tableCellIdsListeners, [getTableIds]],
1606
+ [HAS + TABLE + CELL]: [
1607
+ 2,
1608
+ hasTableCellListeners,
1609
+ [getTableIds, getTableCellIds],
1610
+ (ids) => [hasTableCell(...ids)],
1611
+ ],
1612
+ [ROW_COUNT]: [1, rowCountListeners, [getTableIds]],
1613
+ [ROW_IDS]: [1, rowIdsListeners, [getTableIds]],
1614
+ [HAS + ROW]: [
1615
+ 2,
1616
+ hasRowListeners,
1617
+ [getTableIds, getRowIds],
1618
+ (ids) => [hasRow(...ids)],
1619
+ ],
1620
+ [ROW]: [2, rowListeners, [getTableIds, getRowIds]],
1621
+ [CELL_IDS]: [2, cellIdsListeners, [getTableIds, getRowIds]],
1622
+ [HAS + CELL]: [
1623
+ 3,
1624
+ hasCellListeners,
1625
+ [getTableIds, getRowIds, getCellIds],
1626
+ (ids) => [hasCell(...ids)],
1627
+ ],
1628
+ [CELL]: [
1629
+ 3,
1630
+ cellListeners,
1631
+ [getTableIds, getRowIds, getCellIds],
1632
+ (ids) => pairNew(getCell(...ids)),
1633
+ ],
1634
+ InvalidCell: [3, invalidCellListeners],
1635
+ [HAS + VALUES]: [0, hasValuesListeners, [], () => [hasValues()]],
1636
+ [VALUES]: [0, valuesListeners],
1637
+ [VALUE_IDS]: [0, valueIdsListeners],
1638
+ [HAS + VALUE]: [
1639
+ 1,
1640
+ hasValueListeners,
1641
+ [getValueIds],
1642
+ (ids) => [hasValue(...ids)],
1643
+ ],
1644
+ [VALUE]: [
1645
+ 1,
1646
+ valueListeners,
1647
+ [getValueIds],
1648
+ (ids) => pairNew(getValue(ids[0])),
1649
+ ],
1650
+ InvalidValue: [1, invalidValueListeners],
1651
+ },
1652
+ ([argumentCount, idSetNode, pathGetters, extraArgsGetter], listenable) => {
1653
+ store[ADD + listenable + LISTENER] = (...args) =>
1654
+ addListener(
1655
+ args[argumentCount],
1656
+ idSetNode[args[argumentCount + 1] ? 1 : 0],
1657
+ argumentCount > 0 ? slice(args, 0, argumentCount) : void 0,
1658
+ pathGetters,
1659
+ extraArgsGetter,
1660
+ );
1661
+ },
1662
+ );
1663
+ return objFreeze(store);
1664
+ };
1665
+
1666
+ const MASK6 = 63;
1667
+ const SHIFT36 = 2 ** 36;
1668
+ const SHIFT30 = 2 ** 30;
1669
+ const SHIFT24 = 2 ** 24;
1670
+ const SHIFT18 = 2 ** 18;
1671
+ const SHIFT12 = 2 ** 12;
1672
+ const SHIFT6 = 2 ** 6;
1673
+ const toB64 = (num) => String.fromCharCode(48 + (num & MASK6));
1674
+ const fromB64 = (str, pos) => strCharCodeAt(str, pos) - 48;
1675
+ const hash = (value) =>
1676
+ arrayReduce(
1677
+ strSplit(value),
1678
+ (hash2, char) => ((hash2 << 5) + hash2) ^ strCharCodeAt(char),
1679
+ 5381,
1680
+ ) >>> 0;
1681
+ const encodeHlc = (logicalTime42, counter24, clientHash30) =>
1682
+ toB64(logicalTime42 / SHIFT36) +
1683
+ toB64(logicalTime42 / SHIFT30) +
1684
+ toB64(logicalTime42 / SHIFT24) +
1685
+ toB64(logicalTime42 / SHIFT18) +
1686
+ toB64(logicalTime42 / SHIFT12) +
1687
+ toB64(logicalTime42 / SHIFT6) +
1688
+ toB64(logicalTime42) +
1689
+ toB64(counter24 / SHIFT18) +
1690
+ toB64(counter24 / SHIFT12) +
1691
+ toB64(counter24 / SHIFT6) +
1692
+ toB64(counter24) +
1693
+ toB64(clientHash30 / SHIFT24) +
1694
+ toB64(clientHash30 / SHIFT18) +
1695
+ toB64(clientHash30 / SHIFT12) +
1696
+ toB64(clientHash30 / SHIFT6) +
1697
+ toB64(clientHash30);
1698
+ const decodeHlc = (hlc16) => [
1699
+ fromB64(hlc16, 0) * SHIFT36 +
1700
+ fromB64(hlc16, 1) * SHIFT30 +
1701
+ fromB64(hlc16, 2) * SHIFT24 +
1702
+ fromB64(hlc16, 3) * SHIFT18 +
1703
+ fromB64(hlc16, 4) * SHIFT12 +
1704
+ fromB64(hlc16, 5) * SHIFT6 +
1705
+ fromB64(hlc16, 6),
1706
+ fromB64(hlc16, 7) * SHIFT18 +
1707
+ fromB64(hlc16, 8) * SHIFT12 +
1708
+ fromB64(hlc16, 9) * SHIFT6 +
1709
+ fromB64(hlc16, 10),
1710
+ fromB64(hlc16, 11) * SHIFT24 +
1711
+ fromB64(hlc16, 12) * SHIFT18 +
1712
+ fromB64(hlc16, 13) * SHIFT12 +
1713
+ fromB64(hlc16, 14) * SHIFT6 +
1714
+ fromB64(hlc16, 15),
1715
+ ];
1716
+ const getHlcFunctions = (uniqueId) => {
1717
+ let logicalTime = 0;
1718
+ let counter = 0;
1719
+ const uniqueIdHash = hash(uniqueId);
1720
+ const getHlc = () => {
1721
+ seenHlc();
1722
+ return encodeHlc(logicalTime, ++counter, uniqueIdHash);
1723
+ };
1724
+ const seenHlc = (hlc) => {
1725
+ const previousLogicalTime = logicalTime;
1726
+ const [remoteLogicalTime, remoteCounter] = isUndefined(hlc)
1727
+ ? [0, 0]
1728
+ : decodeHlc(hlc);
1729
+ logicalTime = Math.max(previousLogicalTime, remoteLogicalTime, Date.now());
1730
+ counter =
1731
+ logicalTime == previousLogicalTime
1732
+ ? logicalTime == remoteLogicalTime
1733
+ ? Math.max(counter, remoteCounter)
1734
+ : counter
1735
+ : logicalTime == remoteLogicalTime
1736
+ ? remoteCounter
1737
+ : -1;
1738
+ };
1739
+ return [getHlc, seenHlc];
1740
+ };
1741
+
1742
+ const LISTENER_ARGS = {
1743
+ HasTable: 1,
1744
+ Table: 1,
1745
+ TableCellIds: 1,
1746
+ HasTableCell: 2,
1747
+ RowCount: 1,
1748
+ RowIds: 1,
1749
+ SortedRowIds: 5,
1750
+ HasRow: 2,
1751
+ Row: 2,
1752
+ CellIds: 2,
1753
+ HasCell: 3,
1754
+ Cell: 3,
1755
+ HasValue: 1,
1756
+ Value: 1,
1757
+ InvalidCell: 3,
1758
+ InvalidValue: 1,
1759
+ };
1760
+ const createMergeableStore = (id) => {
1761
+ let listening = 1;
1762
+ const [getHlc, seenHlc] = getHlcFunctions(id);
1763
+ const store = createStore();
1764
+ const allContentStamp = [EMPTY_STRING, [newStampedMap(), newStampedMap()]];
1765
+ const postTransactionListener = (_, getTransactionChanges) => {
1766
+ if (listening) {
1767
+ const stamp = getHlc();
1768
+ const [tablesChanges, valuesChanges] = getTransactionChanges();
1769
+ const [allTablesStamp, allValuesStamp] = allContentStamp[1];
1770
+ allContentStamp[0] = stamp;
1771
+ if (!objIsEmpty(tablesChanges)) {
1772
+ allTablesStamp[0] = stamp;
1773
+ objToArray(tablesChanges, (tableChanges, tableId) => {
1774
+ const allTableStamp = mapEnsure(
1775
+ allTablesStamp[1],
1776
+ tableId,
1777
+ newStamped,
1778
+ );
1779
+ allTableStamp[0] = stamp;
1780
+ if (isUndefined(tableChanges)) {
1781
+ allTableStamp[1] = null;
1782
+ } else {
1783
+ const allRowsStamp = (allTableStamp[1] ??= mapNew());
1784
+ objToArray(tableChanges, (rowChanges, rowId) => {
1785
+ const allRowStamp = mapEnsure(allRowsStamp, rowId, newStamped);
1786
+ allRowStamp[0] = stamp;
1787
+ if (isUndefined(rowChanges)) {
1788
+ allRowStamp[1] = null;
1789
+ } else {
1790
+ const allCellStamps = (allRowStamp[1] ??= mapNew());
1791
+ objToArray(rowChanges, (cellChanges, cellId) =>
1792
+ mapSet(allCellStamps, cellId, [stamp, cellChanges]),
1793
+ );
1794
+ }
1795
+ });
1796
+ }
1797
+ });
1798
+ }
1799
+ if (!objIsEmpty(valuesChanges)) {
1800
+ allValuesStamp[0] = stamp;
1801
+ objToArray(valuesChanges, (valueChanges, valueId) => {
1802
+ mapSet(allValuesStamp[1], valueId, [stamp, valueChanges]);
1803
+ });
1804
+ }
1805
+ }
1806
+ };
1807
+ const merge = (mergeableStore2) => {
1808
+ const mergeableContent = mergeableStore.getMergeableContent();
1809
+ const mergeableContent2 = mergeableStore2.getMergeableContent();
1810
+ mergeableStore2.applyMergeableContent(mergeableContent);
1811
+ return applyMergeableContent(mergeableContent2);
1812
+ };
1813
+ const getMergeableContent = () =>
1814
+ mapStamped(allContentStamp, ([allTablesStamp, allValuesStamp], stamp) => [
1815
+ stamp,
1816
+ [
1817
+ mapStampedMapToObj(allTablesStamp, (allRowStamp) =>
1818
+ mapStampedMapToObj(allRowStamp, (allCellsStamp) =>
1819
+ mapStampedMapToObj(allCellsStamp, pairClone),
1820
+ ),
1821
+ ),
1822
+ mapStampedMapToObj(allValuesStamp, pairClone),
1823
+ ],
1824
+ ]);
1825
+ const applyMergeableContent = (mergeableContent) => {
1826
+ const changes = [{}, {}];
1827
+ seenHlc(mergeableContent[0]);
1828
+ mergeStamp(
1829
+ mergeableContent,
1830
+ allContentStamp,
1831
+ ([tablesStamp, valuesStamp], [allTablesStamp, allValuesStamp]) => [
1832
+ mergeStamp(tablesStamp, allTablesStamp, (tableStamps, allTableStamps) =>
1833
+ mergeEachStamp(
1834
+ tableStamps,
1835
+ allTableStamps,
1836
+ changes[0],
1837
+ (rowStamps, allRowStamps, tableId) =>
1838
+ mergeEachStamp(
1839
+ rowStamps,
1840
+ allRowStamps,
1841
+ changes[0][tableId],
1842
+ (cellStamps, allCellStamps, rowId) =>
1843
+ mergeEachStamp(
1844
+ cellStamps,
1845
+ allCellStamps,
1846
+ changes[0][tableId][rowId],
1847
+ ),
1848
+ ),
1849
+ ),
1850
+ ),
1851
+ mergeStamp(valuesStamp, allValuesStamp, (valueStamps, allValueStamps) =>
1852
+ mergeEachStamp(valueStamps, allValueStamps, changes[1]),
1853
+ ),
1854
+ ],
1855
+ );
1856
+ listening = 0;
1857
+ store.setTransactionChanges(changes);
1858
+ listening = 1;
1859
+ return mergeableStore;
1860
+ };
1861
+ const mergeableStore = {
1862
+ getMergeableContent,
1863
+ applyMergeableContent,
1864
+ merge,
1865
+ };
1866
+ store.addPostTransactionListener(postTransactionListener);
1867
+ objToArray(
1868
+ store,
1869
+ (method, name) =>
1870
+ (mergeableStore[name] = // fluent methods
1871
+ strStartsWith(name, 'set') ||
1872
+ strStartsWith(name, 'del') ||
1873
+ strEndsWith(name, 'Transaction') ||
1874
+ name == 'callListener'
1875
+ ? (...args) => {
1876
+ method(...args);
1877
+ return mergeableStore;
1878
+ }
1879
+ : strStartsWith(name, 'add') && strEndsWith(name, 'Listener')
1880
+ ? (...args) => {
1881
+ const listenerArg = LISTENER_ARGS[slice(name, 3, -8)] ?? 0;
1882
+ const listener = args[listenerArg];
1883
+ args[listenerArg] = (_store, ...args2) =>
1884
+ listener(mergeableStore, ...args2);
1885
+ return method(...args);
1886
+ }
1887
+ : method),
1888
+ );
1889
+ return objFreeze(mergeableStore);
1890
+ };
1891
+
1892
+ export {createMergeableStore};