tinybase 2.0.0-beta.1 → 2.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 (63) hide show
  1. package/lib/checkpoints.d.ts +4 -3
  2. package/lib/checkpoints.js +1 -1
  3. package/lib/checkpoints.js.gz +0 -0
  4. package/lib/common.js +1 -1
  5. package/lib/common.js.gz +0 -0
  6. package/lib/debug/checkpoints.d.ts +4 -3
  7. package/lib/debug/checkpoints.js +12 -12
  8. package/lib/debug/common.js +4 -1
  9. package/lib/debug/indexes.d.ts +4 -2
  10. package/lib/debug/indexes.js +12 -12
  11. package/lib/debug/metrics.d.ts +1 -1
  12. package/lib/debug/metrics.js +12 -12
  13. package/lib/debug/persisters.d.ts +6 -0
  14. package/lib/debug/queries.d.ts +206 -9
  15. package/lib/debug/queries.js +29 -9
  16. package/lib/debug/relationships.d.ts +6 -5
  17. package/lib/debug/relationships.js +12 -12
  18. package/lib/debug/store.d.ts +287 -9
  19. package/lib/debug/store.js +210 -89
  20. package/lib/debug/tinybase.js +231 -97
  21. package/lib/debug/ui-react.d.ts +767 -5
  22. package/lib/debug/ui-react.js +158 -26
  23. package/lib/indexes.d.ts +4 -2
  24. package/lib/indexes.js +1 -1
  25. package/lib/indexes.js.gz +0 -0
  26. package/lib/metrics.d.ts +1 -1
  27. package/lib/metrics.js +1 -1
  28. package/lib/metrics.js.gz +0 -0
  29. package/lib/persisters.d.ts +6 -0
  30. package/lib/queries.d.ts +206 -9
  31. package/lib/queries.js +1 -1
  32. package/lib/queries.js.gz +0 -0
  33. package/lib/relationships.d.ts +6 -5
  34. package/lib/relationships.js +1 -1
  35. package/lib/relationships.js.gz +0 -0
  36. package/lib/store.d.ts +287 -9
  37. package/lib/store.js +1 -1
  38. package/lib/store.js.gz +0 -0
  39. package/lib/tinybase.js +1 -1
  40. package/lib/tinybase.js.gz +0 -0
  41. package/lib/ui-react.d.ts +767 -5
  42. package/lib/ui-react.js +1 -1
  43. package/lib/ui-react.js.gz +0 -0
  44. package/lib/umd/checkpoints.js +1 -1
  45. package/lib/umd/checkpoints.js.gz +0 -0
  46. package/lib/umd/common.js +1 -1
  47. package/lib/umd/common.js.gz +0 -0
  48. package/lib/umd/indexes.js +1 -1
  49. package/lib/umd/indexes.js.gz +0 -0
  50. package/lib/umd/metrics.js +1 -1
  51. package/lib/umd/metrics.js.gz +0 -0
  52. package/lib/umd/queries.js +1 -1
  53. package/lib/umd/queries.js.gz +0 -0
  54. package/lib/umd/relationships.js +1 -1
  55. package/lib/umd/relationships.js.gz +0 -0
  56. package/lib/umd/store.js +1 -1
  57. package/lib/umd/store.js.gz +0 -0
  58. package/lib/umd/tinybase.js +1 -1
  59. package/lib/umd/tinybase.js.gz +0 -0
  60. package/lib/umd/ui-react.js +1 -1
  61. package/lib/umd/ui-react.js.gz +0 -0
  62. package/package.json +25 -25
  63. package/readme.md +2 -2
@@ -137,17 +137,18 @@ export type LinkedRowIdsListener = (
137
137
  */
138
138
  export type RelationshipsListenerStats = {
139
139
  /**
140
- * The number of RemoteRowIdListeners registered with the Relationships
141
- * object.
140
+ * The number of RemoteRowIdListener functions registered with the
141
+ * Relationships object.
142
142
  */
143
143
  remoteRowId?: number;
144
144
  /**
145
- * The number of LocalRowIdsListeners registered with the Relationships
146
- * object.
145
+ * The number of LocalRowIdsListener functions registered with the
146
+ * Relationships object.
147
147
  */
148
148
  localRowIds?: number;
149
149
  /**
150
- * The number of LinkedRowIds registered with the Relationships object.
150
+ * The number of LinkedRowId functions registered with the Relationships
151
+ * object.
151
152
  */
152
153
  linkedRowIds?: number;
153
154
  };
@@ -36,7 +36,7 @@ const mapSet = (map, key, value) =>
36
36
  isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
37
37
  const mapEnsure = (map, key, getDefaultValue) => {
38
38
  if (!collHas(map, key)) {
39
- map.set(key, getDefaultValue());
39
+ mapSet(map, key, getDefaultValue());
40
40
  }
41
41
  return mapGet(map, key);
42
42
  };
@@ -217,32 +217,32 @@ const getCreateFunction = (getFunction) => {
217
217
  };
218
218
 
219
219
  const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
220
- const sets = [];
221
- const deep = (set, p) =>
220
+ const leaves = [];
221
+ const deep = (node, p) =>
222
222
  p == arrayLength(path)
223
- ? arrayPush(sets, set)
224
- : arrayForEach([path[p], null], (id) => deep(mapGet(set, id), p + 1));
223
+ ? arrayPush(leaves, node)
224
+ : path[p] === null
225
+ ? collForEach(node, (node2) => deep(node2, p + 1))
226
+ : arrayForEach([path[p], null], (id) => deep(mapGet(node, id), p + 1));
225
227
  deep(deepIdSet, 0);
226
- return sets;
228
+ return leaves;
227
229
  };
228
230
  const getListenerFunctions = (getThing) => {
229
231
  let thing;
230
232
  let nextId = 0;
231
233
  const listenerPool = [];
232
234
  const allListeners = mapNew();
233
- const addListener = (listener, idSetNode, idOrNulls) => {
235
+ const addListener = (listener, idSetNode, path) => {
234
236
  thing ??= getThing();
235
237
  const id = arrayPop(listenerPool) ?? EMPTY_STRING + nextId++;
236
- mapSet(allListeners, id, [listener, idSetNode, idOrNulls]);
237
- setAdd(visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], setNew), id);
238
+ mapSet(allListeners, id, [listener, idSetNode, path]);
239
+ setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
238
240
  return id;
239
241
  };
240
242
  const callListeners = (idSetNode, ids, ...extraArgs) =>
241
243
  arrayForEach(getWildcardedLeaves(idSetNode, ids), (set) =>
242
244
  collForEach(set, (id) =>
243
- ifNotUndefined(mapGet(allListeners, id), ([listener]) =>
244
- listener(thing, ...(ids ?? []), ...extraArgs),
245
- ),
245
+ mapGet(allListeners, id)[0](thing, ...(ids ?? []), ...extraArgs),
246
246
  ),
247
247
  );
248
248
  const delListener = (id) =>
@@ -284,6 +284,35 @@ export type TableListener = (
284
284
  */
285
285
  export type RowIdsListener = (store: Store, tableId: Id) => void;
286
286
 
287
+ /**
288
+ * The SortedRowIdsListener type describes a function that is used to listen to
289
+ * changes to sorted Row Ids in a Table.
290
+ *
291
+ * A SortedRowIdsListener is provided when using the addSortedRowIdsListener
292
+ * method. See that method for specific examples.
293
+ *
294
+ * When called, a SortedRowIdsListener is given a reference to the Store, the Id
295
+ * of the Table whose Row Ids sorting changed, the Cell Id being used to sort
296
+ * them, and whether descending or not. It also receives the sorted array of Ids
297
+ * itself, so that you can use them in the listener without the additional cost
298
+ * of an explicit call to getSortedRowIds.
299
+ *
300
+ * @param store A reference to the Store that changed.
301
+ * @param tableId The Id of the Table whose sorted Row Ids changed.
302
+ * @param cellId The Id of the Cell whose values were used for the sorting.
303
+ * @param descending Whether the sorting was in descending order.
304
+ * @param sortedRowIds The sorted Row Ids themselves.
305
+ * @category Listener
306
+ * @since v2.0.0
307
+ */
308
+ export type SortedRowIdsListener = (
309
+ store: Store,
310
+ tableId: Id,
311
+ cellId: Id | undefined,
312
+ descending: boolean,
313
+ sortedRowIds: Ids,
314
+ ) => void;
315
+
287
316
  /**
288
317
  * The RowListener type describes a function that is used to listen to changes
289
318
  * to a Row.
@@ -567,39 +596,43 @@ export type InvalidCells = {
567
596
  */
568
597
  export type StoreListenerStats = {
569
598
  /**
570
- * The number of TablesListeners registered with the Store.
599
+ * The number of TablesListener functions registered with the Store.
571
600
  */
572
601
  tables?: number;
573
602
  /**
574
- * The number of TableIdsListeners registered with the Store.
603
+ * The number of TableIdsListener functions registered with the Store.
575
604
  */
576
605
  tableIds?: number;
577
606
  /**
578
- * The number of TableListeners registered with the Store.
607
+ * The number of TableListener functions registered with the Store.
579
608
  */
580
609
  table?: number;
581
610
  /**
582
- * The number of RowIdsListeners registered with the Store.
611
+ * The number of RowIdsListener functions registered with the Store.
583
612
  */
584
613
  rowIds?: number;
585
614
  /**
586
- * The number of RowListeners registered with the Store.
615
+ * The number of SortedRowIdsListener functions registered with the Store.
616
+ */
617
+ sortedRowIds?: number;
618
+ /**
619
+ * The number of RowListener functions registered with the Store.
587
620
  */
588
621
  row?: number;
589
622
  /**
590
- * The number of CellIdsListeners registered with the Store.
623
+ * The number of CellIdsListener functions registered with the Store.
591
624
  */
592
625
  cellIds?: number;
593
626
  /**
594
- * The number of CellListeners registered with the Store.
627
+ * The number of CellListener functions registered with the Store.
595
628
  */
596
629
  cell?: number;
597
630
  /**
598
- * The number of InvalidCellListeners registered with the Store.
631
+ * The number of InvalidCellListener functions registered with the Store.
599
632
  */
600
633
  invalidCell?: number;
601
634
  /**
602
- * The number of TransactionListeners registered with the Store.
635
+ * The number of TransactionListener functions registered with the Store.
603
636
  */
604
637
  transaction?: number;
605
638
  };
@@ -666,6 +699,7 @@ export type StoreListenerStats = {
666
699
  * |Table Ids|getTableIds|-|-|addTableIdsListener|
667
700
  * |Table|getTable|setTable|delTable|addTableListener|
668
701
  * |Row Ids|getRowIds|-|-|addRowIdsListener|
702
+ * |Row Ids (sorted)|getSortedRowIds|-|-|addSortedRowIdsListener|
669
703
  * |Row|getRow|setRow|delRow|addRowListener|
670
704
  * |Cell Ids|getCellIds|-|-|addCellIdsListener|
671
705
  * |Cell|getCell|setCell|delCell|addCellListener|
@@ -892,6 +926,82 @@ export interface Store {
892
926
  */
893
927
  getRowIds(tableId: Id): Ids;
894
928
 
929
+ /**
930
+ * The getSortedRowIds method returns the Ids of every Row in a given Table,
931
+ * sorted according to the values in a specified Cell.
932
+ *
933
+ * The sorting of the rows is alphanumeric, and you can indicate whether it
934
+ * should be in descending order.
935
+ *
936
+ * Note that every call to this method will perform the sorting afresh - there
937
+ * is no caching of the results - and so you are advised to memoize the
938
+ * results yourself, especially when the Table is large. For a performant
939
+ * approach to tracking the sorted Row Ids when they change, use the
940
+ * addSortedRowIdsListener method.
941
+ *
942
+ * If the Table does not exist, an empty array is returned.
943
+ *
944
+ * @param tableId The Id of the Table in the Store.
945
+ * @param cellId The Id of the Cell whose values are used for the sorting, or
946
+ * `undefined` to by sort the Row Id itself.
947
+ * @param descending Whether the sorting should be in descending order.
948
+ * @returns An array of the sorted Ids of every Row in the Table.
949
+ * @example
950
+ * This example retrieves sorted Row Ids in a Table.
951
+ *
952
+ * ```js
953
+ * const store = createStore().setTables({
954
+ * pets: {
955
+ * fido: {species: 'dog'},
956
+ * felix: {species: 'cat'},
957
+ * },
958
+ * });
959
+ * console.log(store.getSortedRowIds('pets', 'species'));
960
+ * // -> ['felix', 'fido']
961
+ * ```
962
+ * @example
963
+ * This example retrieves sorted Row Ids in a Table in reverse order.
964
+ *
965
+ * ```js
966
+ * const store = createStore().setTables({
967
+ * pets: {
968
+ * fido: {species: 'dog'},
969
+ * felix: {species: 'cat'},
970
+ * cujo: {species: 'wolf'},
971
+ * },
972
+ * });
973
+ * console.log(store.getSortedRowIds('pets', 'species', true));
974
+ * // -> ['cujo', 'fido', 'felix']
975
+ * ```
976
+ * @example
977
+ * This example retrieves Row Ids sorted by their own value, since the
978
+ * `cellId` parameter is undefined.
979
+ *
980
+ * ```js
981
+ * const store = createStore().setTables({
982
+ * pets: {
983
+ * fido: {species: 'dog'},
984
+ * felix: {species: 'cat'},
985
+ * cujo: {species: 'wolf'},
986
+ * },
987
+ * });
988
+ * console.log(store.getSortedRowIds('pets'));
989
+ * // -> ['cujo', 'felix', 'fido']
990
+ * ```
991
+ * @example
992
+ * This example retrieves the sorted Row Ids of a Table that does not exist,
993
+ * returning an empty array.
994
+ *
995
+ * ```js
996
+ * const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
997
+ * console.log(store.getSortedRowIds('employees'));
998
+ * // -> []
999
+ * ```
1000
+ * @category Getter
1001
+ * @since v2.0.0
1002
+ */
1003
+ getSortedRowIds(tableId: Id, cellId?: Id, descending?: boolean): Ids;
1004
+
895
1005
  /**
896
1006
  * The getRow method returns an object containing the entire data of a single
897
1007
  * Row in a given Table.
@@ -2398,6 +2508,174 @@ export interface Store {
2398
2508
  mutator?: boolean,
2399
2509
  ): Id;
2400
2510
 
2511
+ /**
2512
+ * The addSortedRowIdsListener method registers a listener function with the
2513
+ * Store that will be called whenever sorted Row Ids in a Table change.
2514
+ *
2515
+ * The provided listener is a SortedRowIdsListener function, and will be
2516
+ * called with a reference to the Store, the Id of the Table whose Row Ids
2517
+ * sorting changed, the Cell Id being used to sort them, and whether
2518
+ * descending or not. It also receives the sorted array of Ids itself, so that
2519
+ * you can use them in the listener without the additional cost of an explicit
2520
+ * call to getSortedRowIds.
2521
+ *
2522
+ * Such a listener is called when a Row is added or removed, but also when a
2523
+ * value in the specified Cell (somewhere in the Table) has changed enough to
2524
+ * change the sorting of the Row Ids.
2525
+ *
2526
+ * Unlike most other listeners, you cannot provide wildcards (due to the cost
2527
+ * of detecting changes to the sorting). You can only listen to a single
2528
+ * specified Table, sorted by a single specified Cell.
2529
+ *
2530
+ * Use the optional mutator parameter to indicate that there is code in the
2531
+ * listener that will mutate Store data. If set to `false` (or omitted), such
2532
+ * mutations will be silently ignored. All relevant mutator listeners (with
2533
+ * this flag set to `true`) are called _before_ any non-mutator listeners
2534
+ * (since the latter may become relevant due to changes made in the former).
2535
+ * The changes made by mutator listeners do not fire other mutating listeners,
2536
+ * though they will fire non-mutator listeners.
2537
+ *
2538
+ * @param tableId The Id of the Table to listen to.
2539
+ * @param cellId The Id of the Cell whose values are used for the sorting, or
2540
+ * `undefined` to by sort the Row Id itself.
2541
+ * @param descending Whether the sorting should be in descending order.
2542
+ * @param listener The function that will be called whenever the sorted Row
2543
+ * Ids in the Table change.
2544
+ * @param mutator An optional boolean that indicates that the listener mutates
2545
+ * Store data.
2546
+ * @returns A unique Id for the listener that can later be used to call it
2547
+ * explicitly, or to remove it.
2548
+ * @example
2549
+ * This example registers a listener that responds to any change to the sorted
2550
+ * Row Ids of a specific Table.
2551
+ *
2552
+ * ```js
2553
+ * const store = createStore().setTables({
2554
+ * pets: {
2555
+ * cujo: {species: 'wolf'},
2556
+ * felix: {species: 'cat'},
2557
+ * },
2558
+ * });
2559
+ * console.log(store.getSortedRowIds('pets', 'species', false));
2560
+ * // -> ['felix', 'cujo']
2561
+ *
2562
+ * const listenerId = store.addSortedRowIdsListener(
2563
+ * 'pets',
2564
+ * 'species',
2565
+ * false,
2566
+ * (store, tableId, cellId, descending, sortedRowIds) => {
2567
+ * console.log(`Sorted Row Ids for ${tableId} table changed`);
2568
+ * console.log(sortedRowIds);
2569
+ * // ^ cheaper than calling getSortedRowIds again
2570
+ * },
2571
+ * );
2572
+ *
2573
+ * store.setRow('pets', 'fido', {species: 'dog'});
2574
+ * // -> 'Sorted Row Ids for pets table changed'
2575
+ * // -> ['felix', 'fido', 'cujo']
2576
+ *
2577
+ * store.delListener(listenerId);
2578
+ * ```
2579
+ * @example
2580
+ * This example registers a listener that responds to any change to the sorted
2581
+ * Row Ids of a specific Table. The Row Ids are sorted by their own value,
2582
+ * since the `cellId` parameter is explicitly undefined.
2583
+ *
2584
+ * ```js
2585
+ * const store = createStore().setTables({
2586
+ * pets: {
2587
+ * fido: {species: 'dog'},
2588
+ * felix: {species: 'cat'},
2589
+ * },
2590
+ * });
2591
+ * console.log(store.getSortedRowIds('pets', undefined, false));
2592
+ * // -> ['felix', 'fido']
2593
+ *
2594
+ * const listenerId = store.addSortedRowIdsListener(
2595
+ * 'pets',
2596
+ * undefined,
2597
+ * false,
2598
+ * (store, tableId, cellId, descending, sortedRowIds) => {
2599
+ * console.log(`Sorted Row Ids for ${tableId} table changed`);
2600
+ * console.log(sortedRowIds);
2601
+ * // ^ cheaper than calling getSortedRowIds again
2602
+ * },
2603
+ * );
2604
+ *
2605
+ * store.setRow('pets', 'cujo', {species: 'wolf'});
2606
+ * // -> 'Sorted Row Ids for pets table changed'
2607
+ * // -> ['cujo', 'felix', 'fido']
2608
+ *
2609
+ * store.delListener(listenerId);
2610
+ * ```
2611
+ * @example
2612
+ * This example registers a listener that responds to a change in the sorting
2613
+ * of the rows of a specific Table, even though the set of Ids themselves has
2614
+ * not changed.
2615
+ *
2616
+ * ```js
2617
+ * const store = createStore().setTables({
2618
+ * pets: {
2619
+ * fido: {species: 'dog'},
2620
+ * felix: {species: 'cat'},
2621
+ * },
2622
+ * });
2623
+ * console.log(store.getSortedRowIds('pets', 'species', false));
2624
+ * // -> ['felix', 'fido']
2625
+ *
2626
+ * const listenerId = store.addSortedRowIdsListener(
2627
+ * 'pets',
2628
+ * 'species',
2629
+ * false,
2630
+ * (store, tableId, cellId, descending, sortedRowIds) => {
2631
+ * console.log(`Sorted Row Ids for ${tableId} table changed`);
2632
+ * console.log(sortedRowIds);
2633
+ * // ^ cheaper than calling getSortedRowIds again
2634
+ * },
2635
+ * );
2636
+ *
2637
+ * store.setCell('pets', 'felix', 'species', 'tiger');
2638
+ * // -> 'Sorted Row Ids for pets table changed'
2639
+ * // -> ['fido', 'felix']
2640
+ *
2641
+ * store.delListener(listenerId);
2642
+ * ```
2643
+ * @example
2644
+ * This example registers a listener that responds to any change to the sorted
2645
+ * Row Ids of a specific Table, and which also mutates the Store itself.
2646
+ *
2647
+ * ```js
2648
+ * const store = createStore().setTables({
2649
+ * pets: {
2650
+ * cujo: {species: 'wolf'},
2651
+ * felix: {species: 'cat'},
2652
+ * },
2653
+ * });
2654
+ * const listenerId = store.addSortedRowIdsListener(
2655
+ * 'pets',
2656
+ * 'species',
2657
+ * false,
2658
+ * (store, tableId) => store.setCell('meta', 'sorted', tableId, true),
2659
+ * true, // mutator
2660
+ * );
2661
+ *
2662
+ * store.setRow('pets', 'fido', {species: 'dog'});
2663
+ * console.log(store.getTable('meta'));
2664
+ * // -> {sorted: {pets: true}}
2665
+ *
2666
+ * store.delListener(listenerId);
2667
+ * ```
2668
+ * @category Listener
2669
+ * @since v2.0.0
2670
+ */
2671
+ addSortedRowIdsListener(
2672
+ tableId: Id,
2673
+ cellId: Id | undefined,
2674
+ descending: boolean,
2675
+ listener: SortedRowIdsListener,
2676
+ mutator?: boolean,
2677
+ ): Id;
2678
+
2401
2679
  /**
2402
2680
  * The addRowListener method registers a listener function with the Store that
2403
2681
  * will be called whenever data in a Row changes.