tinybase 1.3.3 → 2.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/lib/checkpoints.js +1 -1
  2. package/lib/checkpoints.js.gz +0 -0
  3. package/lib/debug/checkpoints.js +67 -54
  4. package/lib/debug/indexes.js +104 -67
  5. package/lib/debug/metrics.js +185 -129
  6. package/lib/debug/persisters.js +2 -1
  7. package/lib/debug/queries.d.ts +3066 -0
  8. package/lib/debug/queries.js +883 -0
  9. package/lib/debug/relationships.d.ts +6 -5
  10. package/lib/debug/relationships.js +103 -67
  11. package/lib/debug/store.d.ts +137 -66
  12. package/lib/debug/store.js +215 -119
  13. package/lib/debug/tinybase.d.ts +1 -0
  14. package/lib/debug/tinybase.js +896 -176
  15. package/lib/debug/ui-react.d.ts +49 -2
  16. package/lib/debug/ui-react.js +85 -74
  17. package/lib/indexes.js +1 -1
  18. package/lib/indexes.js.gz +0 -0
  19. package/lib/metrics.js +1 -1
  20. package/lib/metrics.js.gz +0 -0
  21. package/lib/queries.d.ts +3066 -0
  22. package/lib/queries.js +1 -0
  23. package/lib/queries.js.gz +0 -0
  24. package/lib/relationships.d.ts +6 -5
  25. package/lib/relationships.js +1 -1
  26. package/lib/relationships.js.gz +0 -0
  27. package/lib/store.d.ts +137 -66
  28. package/lib/store.js +1 -1
  29. package/lib/store.js.gz +0 -0
  30. package/lib/tinybase.d.ts +1 -0
  31. package/lib/tinybase.js +1 -1
  32. package/lib/tinybase.js.gz +0 -0
  33. package/lib/ui-react.d.ts +49 -2
  34. package/lib/ui-react.js +1 -1
  35. package/lib/ui-react.js.gz +0 -0
  36. package/lib/umd/checkpoints.js +1 -1
  37. package/lib/umd/checkpoints.js.gz +0 -0
  38. package/lib/umd/indexes.js +1 -1
  39. package/lib/umd/indexes.js.gz +0 -0
  40. package/lib/umd/metrics.js +1 -1
  41. package/lib/umd/metrics.js.gz +0 -0
  42. package/lib/umd/queries.js +1 -0
  43. package/lib/umd/queries.js.gz +0 -0
  44. package/lib/umd/relationships.js +1 -1
  45. package/lib/umd/relationships.js.gz +0 -0
  46. package/lib/umd/store.js +1 -1
  47. package/lib/umd/store.js.gz +0 -0
  48. package/lib/umd/tinybase.js +1 -1
  49. package/lib/umd/tinybase.js.gz +0 -0
  50. package/lib/umd/ui-react.js +1 -1
  51. package/lib/umd/ui-react.js.gz +0 -0
  52. package/package.json +24 -24
  53. package/readme.md +2 -2
@@ -7,13 +7,13 @@ const AVG = 'avg';
7
7
  const MIN = 'min';
8
8
  const MAX = 'max';
9
9
 
10
+ const arrayEvery = (array, cb) => array.every(cb);
10
11
  const arrayForEach = (array, cb) => array.forEach(cb);
11
12
  const arraySum = (array) => arrayReduce(array, (i, j) => i + j, 0);
12
13
  const arrayLength = (array) => array.length;
13
14
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
14
15
  const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
15
- const arrayFromSecond = (ids) => ids.slice(1);
16
- const arrayPush = (array, value) => array.push(value);
16
+ const arrayPush = (array, ...values) => array.push(...values);
17
17
  const arrayPop = (array) => array.pop();
18
18
 
19
19
  const mathMax = Math.max;
@@ -50,6 +50,96 @@ const mapEnsure = (map, key, getDefaultValue) => {
50
50
  }
51
51
  return mapGet(map, key);
52
52
  };
53
+ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
54
+ ifNotUndefined(
55
+ (ensureLeaf ? mapEnsure : mapGet)(
56
+ node,
57
+ path[p],
58
+ p > arrayLength(path) - 2 ? ensureLeaf : mapNew,
59
+ ),
60
+ (nodeOrLeaf) => {
61
+ if (p > arrayLength(path) - 2) {
62
+ if (pruneLeaf?.(nodeOrLeaf)) {
63
+ mapSet(node, path[p]);
64
+ }
65
+ return nodeOrLeaf;
66
+ }
67
+ const leaf = visitTree(nodeOrLeaf, path, ensureLeaf, pruneLeaf, p + 1);
68
+ if (collIsEmpty(nodeOrLeaf)) {
69
+ mapSet(node, path[p]);
70
+ }
71
+ return leaf;
72
+ },
73
+ );
74
+
75
+ const numericAggregators = mapNew([
76
+ [
77
+ AVG,
78
+ [
79
+ (numbers, length) => arraySum(numbers) / length,
80
+ (metric, add, length) => metric + (add - metric) / (length + 1),
81
+ (metric, remove, length) => metric + (metric - remove) / (length - 1),
82
+ (metric, add, remove, length) => metric + (add - remove) / length,
83
+ ],
84
+ ],
85
+ [
86
+ MAX,
87
+ [
88
+ (numbers) => mathMax(...numbers),
89
+ (metric, add) => mathMax(add, metric),
90
+ (metric, remove) => (remove == metric ? void 0 : metric),
91
+ (metric, add, remove) =>
92
+ remove == metric ? void 0 : mathMax(add, metric),
93
+ ],
94
+ ],
95
+ [
96
+ MIN,
97
+ [
98
+ (numbers) => mathMin(...numbers),
99
+ (metric, add) => mathMin(add, metric),
100
+ (metric, remove) => (remove == metric ? void 0 : metric),
101
+ (metric, add, remove) =>
102
+ remove == metric ? void 0 : mathMin(add, metric),
103
+ ],
104
+ ],
105
+ [
106
+ SUM,
107
+ [
108
+ (numbers) => arraySum(numbers),
109
+ (metric, add) => metric + add,
110
+ (metric, remove) => metric - remove,
111
+ (metric, add, remove) => metric - remove + add,
112
+ ],
113
+ ],
114
+ ]);
115
+ const getAggregateValue = (
116
+ aggregateValue,
117
+ oldLength,
118
+ newValues,
119
+ changedValues,
120
+ aggregators,
121
+ force = false,
122
+ ) => {
123
+ if (collIsEmpty(newValues)) {
124
+ return void 0;
125
+ }
126
+ const [aggregate, aggregateAdd, aggregateRemove, aggregateReplace] =
127
+ aggregators;
128
+ force ||= isUndefined(aggregateValue);
129
+ collForEach(changedValues, ([oldValue, newValue]) => {
130
+ if (!force) {
131
+ aggregateValue = isUndefined(oldValue)
132
+ ? aggregateAdd?.(aggregateValue, newValue, oldLength++)
133
+ : isUndefined(newValue)
134
+ ? aggregateRemove?.(aggregateValue, oldValue, oldLength--)
135
+ : aggregateReplace?.(aggregateValue, newValue, oldValue, oldLength);
136
+ force ||= isUndefined(aggregateValue);
137
+ }
138
+ });
139
+ return force
140
+ ? aggregate(collValues(newValues), collSize(newValues))
141
+ : aggregateValue;
142
+ };
53
143
 
54
144
  const setNew = (entries) => new Set(entries);
55
145
  const setAdd = (set, value) => set?.add(value);
@@ -68,20 +158,46 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
68
158
  const getTableId = (id) => mapGet(tableIds, id);
69
159
  const getThing = (id) => mapGet(things, id);
70
160
  const setThing = (id, thing) => mapSet(things, id, thing);
71
- const removeStoreListeners = (id) =>
72
- ifNotUndefined(mapGet(storeListenerIds, id), (listenerIds) => {
73
- collForEach(listenerIds, store.delListener);
74
- mapSet(storeListenerIds, id);
161
+ const addStoreListeners = (id, andCall, ...listenerIds) => {
162
+ const set = mapEnsure(storeListenerIds, id, setNew);
163
+ arrayForEach(
164
+ listenerIds,
165
+ (listenerId) =>
166
+ setAdd(set, listenerId) && andCall && store.callListener(listenerId),
167
+ );
168
+ return listenerIds;
169
+ };
170
+ const delStoreListeners = (id, ...listenerIds) =>
171
+ ifNotUndefined(mapGet(storeListenerIds, id), (allListenerIds) => {
172
+ arrayForEach(
173
+ arrayIsEmpty(listenerIds) ? collValues(allListenerIds) : listenerIds,
174
+ (listenerId) => {
175
+ store.delListener(listenerId);
176
+ collDel(allListenerIds, listenerId);
177
+ },
178
+ );
179
+ if (collIsEmpty(allListenerIds)) {
180
+ mapSet(storeListenerIds, id);
181
+ }
75
182
  });
76
- const setDefinition = (id, tableId, onChanged, getRowValue, getSortKey) => {
77
- const changedRowValues = mapNew();
78
- const changedSortKeys = mapNew();
183
+ const setDefinition = (id, tableId) => {
79
184
  mapSet(tableIds, id, tableId);
80
185
  if (!collHas(things, id)) {
81
186
  mapSet(things, id, getDefaultThing());
82
187
  mapSet(allRowValues, id, mapNew());
83
188
  mapSet(allSortKeys, id, mapNew());
84
189
  }
190
+ };
191
+ const setDefinitionAndListen = (
192
+ id,
193
+ tableId,
194
+ onChanged,
195
+ getRowValue,
196
+ getSortKey,
197
+ ) => {
198
+ setDefinition(id, tableId);
199
+ const changedRowValues = mapNew();
200
+ const changedSortKeys = mapNew();
85
201
  const rowValues = mapGet(allRowValues, id);
86
202
  const sortKeys = mapGet(allSortKeys, id);
87
203
  const processRow = (rowId) => {
@@ -131,16 +247,14 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
131
247
  });
132
248
  }
133
249
  processTable(true);
134
- removeStoreListeners(id);
135
- mapSet(
136
- storeListenerIds,
250
+ delStoreListeners(id);
251
+ addStoreListeners(
137
252
  id,
138
- setNew([
139
- store.addRowListener(tableId, null, (_store, _tableId, rowId) =>
140
- processRow(rowId),
141
- ),
142
- store.addTableListener(tableId, () => processTable()),
143
- ]),
253
+ 0,
254
+ store.addRowListener(tableId, null, (_store, _tableId, rowId) =>
255
+ processRow(rowId),
256
+ ),
257
+ store.addTableListener(tableId, () => processTable()),
144
258
  );
145
259
  };
146
260
  const delDefinition = (id) => {
@@ -148,7 +262,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
148
262
  mapSet(things, id);
149
263
  mapSet(allRowValues, id);
150
264
  mapSet(allSortKeys, id);
151
- removeStoreListeners(id);
265
+ delStoreListeners(id);
152
266
  };
153
267
  const destroy = () => mapForEach(storeListenerIds, delDefinition);
154
268
  return [
@@ -160,8 +274,11 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
160
274
  getThing,
161
275
  setThing,
162
276
  setDefinition,
277
+ setDefinitionAndListen,
163
278
  delDefinition,
164
279
  destroy,
280
+ addStoreListeners,
281
+ delStoreListeners,
165
282
  ];
166
283
  };
167
284
  const getRowCellFunction = (getRowCell, defaultCellValue) =>
@@ -178,64 +295,51 @@ const getCreateFunction = (getFunction) => {
178
295
  };
179
296
  };
180
297
 
181
- const addDeepSet = (deepSet, value, ids) =>
182
- arrayLength(ids) < 2
183
- ? setAdd(
184
- arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew),
185
- value,
186
- )
187
- : addDeepSet(
188
- mapEnsure(deepSet, ids[0], mapNew),
189
- value,
190
- arrayFromSecond(ids),
191
- );
192
- const forDeepSet = (valueDo) => {
193
- const deep = (deepIdSet, arg, ...ids) =>
194
- ifNotUndefined(deepIdSet, (deepIdSet2) =>
195
- arrayIsEmpty(ids)
196
- ? valueDo(deepIdSet2, arg)
197
- : arrayForEach([ids[0], null], (id) =>
198
- deep(mapGet(deepIdSet2, id), arg, ...arrayFromSecond(ids)),
199
- ),
200
- );
201
- return deep;
298
+ const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
299
+ const sets = [];
300
+ const deep = (set, p) =>
301
+ p == arrayLength(path)
302
+ ? arrayPush(sets, set)
303
+ : arrayForEach([path[p], null], (id) => deep(mapGet(set, id), p + 1));
304
+ deep(deepIdSet, 0);
305
+ return sets;
202
306
  };
203
307
  const getListenerFunctions = (getThing) => {
204
308
  let thing;
205
309
  let nextId = 0;
206
310
  const listenerPool = [];
207
311
  const allListeners = mapNew();
208
- const addListener = (listener, deepSet, idOrNulls = []) => {
312
+ const addListener = (listener, idSetNode, idOrNulls) => {
209
313
  thing ??= getThing();
210
- const id = arrayPop(listenerPool) ?? '' + nextId++;
211
- mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
212
- addDeepSet(deepSet, id, idOrNulls);
314
+ const id = arrayPop(listenerPool) ?? EMPTY_STRING + nextId++;
315
+ mapSet(allListeners, id, [listener, idSetNode, idOrNulls]);
316
+ setAdd(visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], setNew), id);
213
317
  return id;
214
318
  };
215
- const callListeners = (deepSet, ids = [], ...extraArgs) =>
216
- forDeepSet(collForEach)(
217
- deepSet,
218
- (id) =>
319
+ const callListeners = (idSetNode, ids, ...extraArgs) =>
320
+ arrayForEach(getWildcardedLeaves(idSetNode, ids), (set) =>
321
+ collForEach(set, (id) =>
219
322
  ifNotUndefined(mapGet(allListeners, id), ([listener]) =>
220
- listener(thing, ...ids, ...extraArgs),
323
+ listener(thing, ...(ids ?? []), ...extraArgs),
221
324
  ),
222
- ...ids,
325
+ ),
223
326
  );
224
327
  const delListener = (id) =>
225
- ifNotUndefined(
226
- mapGet(allListeners, id),
227
- ([, deepSet, idOrNulls]) => {
228
- forDeepSet(collDel)(deepSet, id, ...idOrNulls);
229
- mapSet(allListeners, id);
230
- if (arrayLength(listenerPool) < 1e3) {
231
- arrayPush(listenerPool, id);
232
- }
233
- return idOrNulls;
234
- },
235
- () => [],
236
- );
328
+ ifNotUndefined(mapGet(allListeners, id), ([, idSetNode, idOrNulls]) => {
329
+ visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], void 0, (idSet) => {
330
+ collDel(idSet, id);
331
+ return collIsEmpty(idSet) ? 1 : 0;
332
+ });
333
+ mapSet(allListeners, id);
334
+ if (arrayLength(listenerPool) < 1e3) {
335
+ arrayPush(listenerPool, id);
336
+ }
337
+ return idOrNulls;
338
+ });
339
+ const hasListeners = (idSetNode, ids) =>
340
+ !arrayEvery(getWildcardedLeaves(idSetNode, ids), isUndefined);
237
341
  const callListener = (id, idNullGetters, extraArgsGetter) =>
238
- ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls]) => {
342
+ ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls = []]) => {
239
343
  const callWithIds = (...ids) => {
240
344
  const index = arrayLength(ids);
241
345
  index == arrayLength(idOrNulls)
@@ -248,52 +352,12 @@ const getListenerFunctions = (getThing) => {
248
352
  };
249
353
  callWithIds();
250
354
  });
251
- return [addListener, callListeners, delListener, callListener];
355
+ return [addListener, callListeners, delListener, hasListeners, callListener];
252
356
  };
253
357
 
254
358
  const object = Object;
255
359
  const objFreeze = object.freeze;
256
360
 
257
- const aggregators = mapNew([
258
- [
259
- AVG,
260
- [
261
- (numbers, length) => arraySum(numbers) / length,
262
- (metric, add, length) => metric + (add - metric) / (length + 1),
263
- (metric, remove, length) => metric + (metric - remove) / (length - 1),
264
- (metric, add, remove, length) => metric + (add - remove) / length,
265
- ],
266
- ],
267
- [
268
- MAX,
269
- [
270
- (numbers) => mathMax(...numbers),
271
- (metric, add) => mathMax(add, metric),
272
- (metric, remove) => (remove == metric ? void 0 : metric),
273
- (metric, add, remove) =>
274
- remove == metric ? void 0 : mathMax(add, metric),
275
- ],
276
- ],
277
- [
278
- MIN,
279
- [
280
- (numbers) => mathMin(...numbers),
281
- (metric, add) => mathMin(add, metric),
282
- (metric, remove) => (remove == metric ? void 0 : metric),
283
- (metric, add, remove) =>
284
- remove == metric ? void 0 : mathMin(add, metric),
285
- ],
286
- ],
287
- [
288
- SUM,
289
- [
290
- (numbers) => arraySum(numbers),
291
- (metric, add) => metric + add,
292
- (metric, remove) => metric - remove,
293
- (metric, add, remove) => metric - remove + add,
294
- ],
295
- ],
296
- ]);
297
361
  const createMetrics = getCreateFunction((store) => {
298
362
  const metricListeners = mapNew();
299
363
  const [
@@ -304,7 +368,8 @@ const createMetrics = getCreateFunction((store) => {
304
368
  getTableId,
305
369
  getMetric,
306
370
  setMetric,
307
- setDefinition,
371
+ ,
372
+ setDefinitionAndListen,
308
373
  delDefinition,
309
374
  destroy,
310
375
  ] = getDefinableFunctions(store, getUndefined, (value) =>
@@ -328,38 +393,29 @@ const createMetrics = getCreateFunction((store) => {
328
393
  aggregateRemove,
329
394
  aggregateReplace,
330
395
  ) => {
331
- const metricAggregators = isFunction(aggregate)
396
+ const aggregators = isFunction(aggregate)
332
397
  ? [aggregate, aggregateAdd, aggregateRemove, aggregateReplace]
333
- : mapGet(aggregators, aggregate) ?? mapGet(aggregators, SUM);
334
- setDefinition(
398
+ : mapGet(numericAggregators, aggregate) ??
399
+ mapGet(numericAggregators, SUM);
400
+ setDefinitionAndListen(
335
401
  metricId,
336
402
  tableId,
337
403
  (change, changedNumbers, _changedSortKeys, numbers, _sortKeys, force) => {
338
- let newMetric = getMetric(metricId);
339
- let length = collSize(numbers);
340
- const [aggregate2, aggregateAdd2, aggregateRemove2, aggregateReplace2] =
341
- metricAggregators;
342
- force = force || isUndefined(newMetric);
343
- collForEach(changedNumbers, ([oldNumber, newNumber]) => {
344
- if (!force) {
345
- newMetric = isUndefined(oldNumber)
346
- ? aggregateAdd2?.(newMetric, newNumber, length++)
347
- : isUndefined(newNumber)
348
- ? aggregateRemove2?.(newMetric, oldNumber, length--)
349
- : aggregateReplace2?.(newMetric, newNumber, oldNumber, length);
350
- }
351
- force = force || isUndefined(newMetric);
352
- });
404
+ const oldMetric = getMetric(metricId);
405
+ const oldLength = collSize(numbers);
406
+ force ||= isUndefined(oldMetric);
353
407
  change();
354
- if (collIsEmpty(numbers)) {
355
- newMetric = void 0;
356
- } else if (force) {
357
- newMetric = aggregate2(collValues(numbers), collSize(numbers));
358
- }
408
+ let newMetric = getAggregateValue(
409
+ oldMetric,
410
+ oldLength,
411
+ numbers,
412
+ changedNumbers,
413
+ aggregators,
414
+ force,
415
+ );
359
416
  if (!isFiniteNumber(newMetric)) {
360
417
  newMetric = void 0;
361
418
  }
362
- const oldMetric = getMetric(metricId);
363
419
  if (newMetric != oldMetric) {
364
420
  setMetric(metricId, newMetric);
365
421
  callListeners(metricListeners, [metricId], newMetric, oldMetric);
@@ -1,5 +1,6 @@
1
1
  import {promises, watch} from 'fs';
2
2
 
3
+ const EMPTY_STRING = '';
3
4
  const UTF8 = 'utf8';
4
5
 
5
6
  const isUndefined = (thing) => thing == void 0;
@@ -29,7 +30,7 @@ const createCustomPersister = (
29
30
  loads++;
30
31
  }
31
32
  const body = await getPersisted();
32
- if (!isUndefined(body) && body != '') {
33
+ if (!isUndefined(body) && body != EMPTY_STRING) {
33
34
  store.setJson(body);
34
35
  } else {
35
36
  store.setTables(initialTables);