tinybase 0.0.0 → 0.9.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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/lib/checkpoints.d.ts +861 -0
  3. package/lib/checkpoints.js +1 -0
  4. package/lib/checkpoints.js.gz +0 -0
  5. package/lib/common.d.ts +59 -0
  6. package/lib/debug/checkpoints.d.ts +861 -0
  7. package/lib/debug/checkpoints.js +326 -0
  8. package/lib/debug/common.d.ts +59 -0
  9. package/lib/debug/indexes.d.ts +815 -0
  10. package/lib/debug/indexes.js +390 -0
  11. package/lib/debug/metrics.d.ts +728 -0
  12. package/lib/debug/metrics.js +391 -0
  13. package/lib/debug/persisters.d.ts +521 -0
  14. package/lib/debug/persisters.js +191 -0
  15. package/lib/debug/react.d.ts +7077 -0
  16. package/lib/debug/react.js +1037 -0
  17. package/lib/debug/relationships.d.ts +1091 -0
  18. package/lib/debug/relationships.js +418 -0
  19. package/lib/debug/store.d.ts +2424 -0
  20. package/lib/debug/store.js +725 -0
  21. package/lib/debug/tinybase.d.ts +14 -0
  22. package/lib/debug/tinybase.js +2727 -0
  23. package/lib/indexes.d.ts +815 -0
  24. package/lib/indexes.js +1 -0
  25. package/lib/indexes.js.gz +0 -0
  26. package/lib/metrics.d.ts +728 -0
  27. package/lib/metrics.js +1 -0
  28. package/lib/metrics.js.gz +0 -0
  29. package/lib/persisters.d.ts +521 -0
  30. package/lib/persisters.js +1 -0
  31. package/lib/persisters.js.gz +0 -0
  32. package/lib/react.d.ts +7077 -0
  33. package/lib/react.js +1 -0
  34. package/lib/react.js.gz +0 -0
  35. package/lib/relationships.d.ts +1091 -0
  36. package/lib/relationships.js +1 -0
  37. package/lib/relationships.js.gz +0 -0
  38. package/lib/store.d.ts +2424 -0
  39. package/lib/store.js +1 -0
  40. package/lib/store.js.gz +0 -0
  41. package/lib/tinybase.d.ts +14 -0
  42. package/lib/tinybase.js +1 -0
  43. package/lib/tinybase.js.gz +0 -0
  44. package/lib/umd/checkpoints.js +1 -0
  45. package/lib/umd/checkpoints.js.gz +0 -0
  46. package/lib/umd/indexes.js +1 -0
  47. package/lib/umd/indexes.js.gz +0 -0
  48. package/lib/umd/metrics.js +1 -0
  49. package/lib/umd/metrics.js.gz +0 -0
  50. package/lib/umd/persisters.js +1 -0
  51. package/lib/umd/persisters.js.gz +0 -0
  52. package/lib/umd/react.js +1 -0
  53. package/lib/umd/react.js.gz +0 -0
  54. package/lib/umd/relationships.js +1 -0
  55. package/lib/umd/relationships.js.gz +0 -0
  56. package/lib/umd/store.js +1 -0
  57. package/lib/umd/store.js.gz +0 -0
  58. package/lib/umd/tinybase.js +1 -0
  59. package/lib/umd/tinybase.js.gz +0 -0
  60. package/package.json +93 -2
  61. package/readme.md +195 -0
@@ -0,0 +1,815 @@
1
+ /**
2
+ * The indexes module of the TinyBase project provides the ability to create
3
+ * and track indexes of the data in Store objects.
4
+ *
5
+ * The main entry point to this module is the createIndexes function, which
6
+ * returns a new Indexes object. From there, you can create new index
7
+ * definitions, access the contents of those indexes directly, and register
8
+ * listeners for when they change.
9
+ *
10
+ * @packageDocumentation
11
+ * @module indexes
12
+ */
13
+
14
+ import {GetCell, Store} from './store.d';
15
+ import {Id, IdOrNull, Ids} from './common.d';
16
+
17
+ /**
18
+ * The Index type represents the concept of a map of Slice objects, keyed by Id.
19
+ *
20
+ * The Ids in a Slice represent Row objects from a Table that all have a derived
21
+ * string value in common, as described by the setIndexDefinition method. Those
22
+ * values are used as the key for each Slice in the overall Index object.
23
+ *
24
+ * Note that the Index type is not actually used in the API, and you instead
25
+ * enumerate and access its structure with the getSliceIds method and
26
+ * getSliceRowIds method.
27
+ *
28
+ * @category Concept
29
+ */
30
+ export type Index = {[sliceId: Id]: Slice};
31
+
32
+ /**
33
+ * The Slice type represents the concept of a set of Row objects that comprise
34
+ * part of an Index.
35
+ *
36
+ * The Ids in a Slice represent Row objects from a Table that all have a derived
37
+ * string value in common, as described by the setIndexDefinition method.
38
+ *
39
+ * Note that the Slice type is not actually used in the API, and you instead get
40
+ * Row Ids directly with the getSliceRowIds method.
41
+ *
42
+ * @category Concept
43
+ */
44
+ export type Slice = Ids;
45
+
46
+ /**
47
+ * The SortKey type represents a value that can be used by a sort function.
48
+ *
49
+ * @category Parameter
50
+ */
51
+ export type SortKey = string | number | boolean;
52
+
53
+ /**
54
+ * The SliceIdsListener type describes a function that is used to listen to
55
+ * changes to the Slice Ids in an Index.
56
+ *
57
+ * A SliceIdsListener is provided when using the addSliceIdsListener method. See
58
+ * that method for specific examples.
59
+ *
60
+ * When called, a SliceIdsListener is given a reference to the Indexes object,
61
+ * and the Id of the Index that changed.
62
+ *
63
+ * @category Listener
64
+ */
65
+ export type SliceIdsListener = (indexes: Indexes, indexId: Id) => void;
66
+
67
+ /**
68
+ * The SliceRowIdsListener type describes a function that is used to listen to
69
+ * changes to the Row Ids in a Slice.
70
+ *
71
+ * A SliceRowIdsListener is provided when using the addSliceRowIdsListener
72
+ * method. See that method for specific examples.
73
+ *
74
+ * When called, a SliceRowIdsListener is given a reference to the Indexes
75
+ * object, the Id of the Index that changed, and the Id of the Slice whose Row
76
+ * Ids changed.
77
+ *
78
+ * @category Listener
79
+ */
80
+ export type SliceRowIdsListener = (
81
+ indexes: Indexes,
82
+ indexId: Id,
83
+ sliceId: Id,
84
+ ) => void;
85
+
86
+ /**
87
+ * The IndexesListenerStats type describes the number of listeners registered
88
+ * with the Indexes object, and can be used for debugging purposes.
89
+ *
90
+ * A IndexesListenerStats object is returned from the getListenerStats method,
91
+ * and is only populated in a debug build.
92
+ *
93
+ * @category Development
94
+ */
95
+ export type IndexesListenerStats = {
96
+ sliceIds?: number;
97
+ sliceRowIds?: number;
98
+ };
99
+
100
+ /**
101
+ * An Indexes object lets you look up all the Row objects in a Table that have a
102
+ * certain Cell value.
103
+ *
104
+ * This is useful for creating filtered views of a Table, or simple search
105
+ * functionality.
106
+ *
107
+ * Create an Indexes object easily with the createIndexes function. From there,
108
+ * you can add new Index definitions (with the setIndexDefinition method), query
109
+ * their contents (with the getSliceIds method and getSliceRowIds method), and
110
+ * add listeners for when they change (with the addSliceIdsListener method and
111
+ * addSliceRowIdsListener method).
112
+ *
113
+ * This module defaults to indexing Row objects by one of their Cell values.
114
+ * However, far more complex indexes can be configured with a custom function.
115
+ *
116
+ * @example
117
+ * This example shows a very simple lifecycle of an Indexes object: from
118
+ * creation, to adding a definition, getting its contents, and then registering
119
+ * and removing a listener for it.
120
+ *
121
+ * ```tsx
122
+ * const store = createStore().setTable('pets', {
123
+ * fido: {species: 'dog'},
124
+ * felix: {species: 'cat'},
125
+ * cujo: {species: 'dog'},
126
+ * });
127
+ *
128
+ * const indexes = createIndexes(store);
129
+ * indexes.setIndexDefinition(
130
+ * 'bySpecies', // indexId
131
+ * 'pets', // tableId to index
132
+ * 'species', // cellId to index
133
+ * );
134
+ *
135
+ * console.log(indexes.getSliceIds('bySpecies'));
136
+ * // -> ['dog', 'cat']
137
+ * console.log(indexes.getSliceRowIds('bySpecies', 'dog'));
138
+ * // -> ['fido', 'cujo']
139
+ *
140
+ * const listenerId = indexes.addSliceIdsListener('bySpecies', () => {
141
+ * console.log(indexes.getSliceIds('bySpecies'));
142
+ * });
143
+ * store.setRow('pets', 'lowly', {species: 'worm'});
144
+ * // -> ['dog', 'cat', 'worm']
145
+ *
146
+ * indexes.delListener(listenerId);
147
+ * indexes.destroy();
148
+ * ```
149
+ */
150
+ export interface Indexes {
151
+ /**
152
+ * The setIndexDefinition method lets you set the definition of an Index.
153
+ *
154
+ * Every Index definition is identified by a unique Id, and if you re-use an
155
+ * existing Id with this method, the previous definition is overwritten.
156
+ *
157
+ * An Index is a keyed map of Slice objects, each of which is a list of Row
158
+ * Ids from a given Table. Therefore the definition must specify the Table (by
159
+ * its Id) to be indexed.
160
+ *
161
+ * The Ids in a Slice represent Row objects from a Table that all have a
162
+ * derived string value in common, as described by this method. Those values
163
+ * are used as the key for each Slice in the overall Index object.
164
+ *
165
+ * Without the third `getSliceId` parameter, the Index will simply have a
166
+ * single Slice, keyed by an empty string. But more often you will specify a
167
+ * Cell value containing the Slice Id that the Row should belong to.
168
+ * Alternatively, a custom function can be provided that produces your own
169
+ * Slice Id from the local Row as a whole.
170
+ *
171
+ * The fourth `getSortKey` parameter specifies a Cell Id to get a value (or a
172
+ * function that processes a whole Row to get a value) that is used to sort
173
+ * the Row Ids within each Slice in the Index.
174
+ *
175
+ * The fifth parameter, `sliceIdSorter`, lets you specify a way to sort the
176
+ * Slice Ids when you access the Index, which may be useful if you are trying
177
+ * to create an alphabetic Index of Row entries. If not specified, the order
178
+ * of the Slice Ids will match the order of Row insertion.
179
+ *
180
+ * The final parameter, `rowIdSorter`, lets you specify a way to sort the Row
181
+ * Ids within each Slice, based on the `getSortKey` parameter. This may be
182
+ * useful if you are trying to keep Rows in a determined order relative to
183
+ * each other in the Index. If omitted, the Row Ids are sorted alphabetically,
184
+ * based on the `getSortKey` parameter.
185
+ *
186
+ * The two 'sorter' parameters, `sliceIdSorter` and `rowIdSorter`, are
187
+ * functions that take two values and return a positive or negative number for
188
+ * when they are in the wrong or right order, respectively. This is exactly
189
+ * the same as the 'compareFunction' that is used in the standard JavaScript
190
+ * array `sort` method, with the addition that `rowIdSorter` also takes the
191
+ * Slice Id parameter, in case you want to sort Row Ids differently in each
192
+ * Slice. You can use the convenient defaultSorter function to default this to
193
+ * be alphanumeric.
194
+ *
195
+ * @param indexId The Id of the Index to define.
196
+ * @param tableId The Id of the Table the Index will be generated from.
197
+ * @param getSliceId Either the Id of the Cell containing, or a function that
198
+ * produces, the Id that is used to indicate which Slice in the Index the Row
199
+ * Id should be in. Defaults to a function that returns `''` (meaning that if
200
+ * this `getSliceId` parameter is omitted, the Index will simply contain a
201
+ * single Slice containing all the Row Ids in the Table).
202
+ * @param getSortKey Either the Id of the Cell containing, or a function that
203
+ * produces, the value that is used to sort the Row Ids in each Slice.
204
+ * @param sliceIdSorter A function that takes two Slice Id values and returns
205
+ * a positive or negative number to indicate how they should be sorted.
206
+ * @param rowIdSorter A function that takes two Row Id values (and a slice Id)
207
+ * and returns a positive or negative number to indicate how they should be
208
+ * sorted.
209
+ * @returns A reference to the Indexes object.
210
+ * @example
211
+ * This example creates a Store, creates an Indexes object, and defines a
212
+ * simple Index based on the values in the `species` Cell.
213
+ *
214
+ * ```tsx
215
+ * const store = createStore().setTable('pets', {
216
+ * fido: {species: 'dog'},
217
+ * felix: {species: 'cat'},
218
+ * cujo: {species: 'dog'},
219
+ * });
220
+ *
221
+ * const indexes = createIndexes(store);
222
+ * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
223
+ *
224
+ * console.log(indexes.getSliceIds('bySpecies'));
225
+ * // -> ['dog', 'cat']
226
+ * console.log(indexes.getSliceRowIds('bySpecies', 'dog'));
227
+ * // -> ['fido', 'cujo']
228
+ * ```
229
+ * @example
230
+ * This example creates a Store, creates an Indexes object, and defines an
231
+ * Index based on the first letter of the pets' names.
232
+ *
233
+ * ```tsx
234
+ * const store = createStore().setTable('pets', {
235
+ * fido: {species: 'dog'},
236
+ * felix: {species: 'cat'},
237
+ * cujo: {species: 'dog'},
238
+ * });
239
+ *
240
+ * const indexes = createIndexes(store);
241
+ * indexes.setIndexDefinition('byFirst', 'pets', (_, rowId) => rowId[0]);
242
+ *
243
+ * console.log(indexes.getSliceIds('byFirst'));
244
+ * // -> ['f', 'c']
245
+ * console.log(indexes.getSliceRowIds('byFirst', 'f'));
246
+ * // -> ['fido', 'felix']
247
+ * ```
248
+ * @example
249
+ * This example creates a Store, creates an Indexes object, and defines an
250
+ * Index based on the first letter of the pets' names. The Slice Ids (and Row
251
+ * Ids within them) are alphabetically sorted.
252
+ *
253
+ * ```tsx
254
+ * const store = createStore().setTable('pets', {
255
+ * fido: {species: 'dog'},
256
+ * felix: {species: 'cat'},
257
+ * cujo: {species: 'dog'},
258
+ * });
259
+ *
260
+ * const indexes = createIndexes(store);
261
+ * indexes.setIndexDefinition(
262
+ * 'byFirst', // indexId
263
+ * 'pets', // tableId
264
+ * (_, rowId) => rowId[0], // each Row's sliceId
265
+ * (_, rowId) => rowId, // each Row's sort key
266
+ * defaultSorter, // sort Slice Ids
267
+ * defaultSorter, // sort Row Ids
268
+ * );
269
+ *
270
+ * console.log(indexes.getSliceIds('byFirst'));
271
+ * // -> ['c', 'f']
272
+ * console.log(indexes.getSliceRowIds('byFirst', 'f'));
273
+ * // -> ['felix', 'fido']
274
+ * ```
275
+ * @category Configuration
276
+ */
277
+ setIndexDefinition(
278
+ indexId: Id,
279
+ tableId: Id,
280
+ getSliceId?: Id | ((getCell: GetCell, rowId: Id) => Id),
281
+ getSortKey?: Id | ((getCell: GetCell, rowId: Id) => SortKey),
282
+ sliceIdSorter?: (sliceId1: Id, sliceId2: Id) => number,
283
+ rowIdSorter?: (sortKey1: SortKey, sortKey2: SortKey, sliceId: Id) => number,
284
+ ): Indexes;
285
+
286
+ /**
287
+ * The delIndexDefinition method removes an existing Index definition.
288
+ *
289
+ * @param indexId The Id of the Index to remove.
290
+ * @returns A reference to the Indexes object.
291
+ * @example
292
+ * This example creates a Store, creates an Indexes object, defines a simple
293
+ * Index, and then removes it.
294
+ *
295
+ * ```tsx
296
+ * const store = createStore().setTable('pets', {
297
+ * fido: {species: 'dog'},
298
+ * felix: {species: 'cat'},
299
+ * cujo: {species: 'dog'},
300
+ * });
301
+ *
302
+ * const indexes = createIndexes(store);
303
+ * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
304
+ * console.log(indexes.getIndexIds());
305
+ * // -> ['bySpecies']
306
+ *
307
+ * indexes.delIndexDefinition('bySpecies');
308
+ * console.log(indexes.getIndexIds());
309
+ * // -> []
310
+ * ```
311
+ * @category Configuration
312
+ */
313
+ delIndexDefinition(indexId: Id): Indexes;
314
+
315
+ /**
316
+ * The getStore method returns a reference to the underlying Store that is
317
+ * backing this Indexes object.
318
+ *
319
+ * @returns A reference to the Store.
320
+ * @example
321
+ * This example creates an Indexes object against a newly-created Store and
322
+ * then gets its reference in order to update its data.
323
+ *
324
+ * ```tsx
325
+ * const indexes = createIndexes(createStore());
326
+ * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
327
+ * indexes.getStore().setCell('pets', 'fido', 'species', 'dog');
328
+ * console.log(indexes.getSliceIds('bySpecies'));
329
+ * // -> ['dog']
330
+ * ```
331
+ * @category Getter
332
+ */
333
+ getStore(): Store;
334
+
335
+ /**
336
+ * The getIndexIds method returns an array of the Index Ids registered with
337
+ * this Indexes object.
338
+ *
339
+ * @returns An array of Ids.
340
+ * @example
341
+ * This example creates an Indexes object with two definitions, and then gets
342
+ * the Ids of the definitions.
343
+ *
344
+ * ```tsx
345
+ * const indexes = createIndexes(createStore())
346
+ * .setIndexDefinition('bySpecies', 'pets', 'species')
347
+ * .setIndexDefinition('byColor', 'pets', 'color');
348
+ *
349
+ * console.log(indexes.getIndexIds());
350
+ * // -> ['bySpecies', 'byColor']
351
+ * ```
352
+ * @category Getter
353
+ */
354
+ getIndexIds(): Ids;
355
+
356
+ /**
357
+ * The getTableId method returns the Id of the underlying Table that is
358
+ * backing an Index.
359
+ *
360
+ * If the Index Id is invalid, the method returns `undefined`.
361
+ *
362
+ * @param indexId The Id of an Index.
363
+ * @returns The Id of the Table backing the Index, or `undefined`.
364
+ * @example
365
+ * This example creates an Indexes object, a single Index definition, and then
366
+ * queries it (and a non-existent definition) to get the underlying Table Id.
367
+ *
368
+ * ```tsx
369
+ * const indexes = createIndexes(createStore());
370
+ * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
371
+ *
372
+ * console.log(indexes.getTableId('bySpecies'));
373
+ * // -> 'pets'
374
+ * console.log(indexes.getTableId('byColor'));
375
+ * // -> undefined
376
+ * ```
377
+ * @category Getter
378
+ */
379
+ getTableId(indexId: Id): Id;
380
+
381
+ /**
382
+ * The getSliceIds method gets the list of Slice Ids in an Index.
383
+ *
384
+ * If the identified Index does not exist (or if the definition references a
385
+ * Table that does not exist) then an empty array is returned.
386
+ *
387
+ * @param indexId The Id of the Index.
388
+ * @returns The Slice Ids in the Index, or an empty array.
389
+ * @example
390
+ * This example creates a Store, creates an Indexes object, and defines a
391
+ * simple Index. It then uses getSliceIds to see the available Slice Ids in
392
+ * the Index (and also the Slice Ids in an Index that has not been defined).
393
+ *
394
+ * ```tsx
395
+ * const store = createStore().setTable('pets', {
396
+ * fido: {species: 'dog'},
397
+ * felix: {species: 'cat'},
398
+ * cujo: {species: 'dog'},
399
+ * });
400
+ *
401
+ * const indexes = createIndexes(store);
402
+ * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
403
+ *
404
+ * console.log(indexes.getSliceIds('bySpecies'));
405
+ * // -> ['dog', 'cat']
406
+ * console.log(indexes.getSliceIds('byColor'));
407
+ * // -> []
408
+ * ```
409
+ * @category Getter
410
+ */
411
+ getSliceIds(indexId: Id): Ids;
412
+
413
+ /**
414
+ * The getSliceRowIds method gets the list of Row Ids in a given Slice, within
415
+ * a given Index.
416
+ *
417
+ * If the identified Index or Slice do not exist (or if the definition
418
+ * references a Table that does not exist) then an empty array is returned.
419
+ *
420
+ * @param indexId The Id of the Index.
421
+ * @param sliceId The Id of the Slice in the Index.
422
+ * @returns The Row Ids in the Slice, or an empty array.
423
+ * @example
424
+ * This example creates a Store, creates an Indexes object, and defines a
425
+ * simple Index. It then uses getSliceRowIds to see the Row Ids in the Slice
426
+ * (and also the Row Ids in Slices that do not exist).
427
+ *
428
+ * ```tsx
429
+ * const store = createStore().setTable('pets', {
430
+ * fido: {species: 'dog'},
431
+ * felix: {species: 'cat'},
432
+ * cujo: {species: 'dog'},
433
+ * });
434
+ *
435
+ * const indexes = createIndexes(store);
436
+ * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
437
+ *
438
+ * console.log(indexes.getSliceRowIds('bySpecies', 'dog'));
439
+ * // -> ['fido', 'cujo']
440
+ * console.log(indexes.getSliceRowIds('bySpecies', 'worm'));
441
+ * // -> []
442
+ * console.log(indexes.getSliceRowIds('byColor', 'brown'));
443
+ * // -> []
444
+ * ```
445
+ * @category Getter
446
+ */
447
+ getSliceRowIds(indexId: Id, sliceId: Id): Ids;
448
+
449
+ /**
450
+ * The addSliceIdsListener method registers a listener function with the
451
+ * Indexes object that will be called whenever the Slice Ids in an Index
452
+ * change.
453
+ *
454
+ * You can either listen to a single Index (by specifying the Index Id as the
455
+ * method's first parameter), or changes to any Index (by providing a `null`
456
+ * wildcard).
457
+ *
458
+ * The provided listener is a SliceIdsListener function, and will be called
459
+ * with a reference to the Indexes object, and the Id of the Index that
460
+ * changed.
461
+ *
462
+ * @param indexId The Id of the Index to listen to, or `null` as a wildcard.
463
+ * @param listener The function that will be called whenever the Slice Ids in
464
+ * the Index change.
465
+ * @returns A unique Id for the listener that can later be used to remove it.
466
+ * @example
467
+ * This example creates a Store, a Indexes object, and then registers a
468
+ * listener that responds to any changes to a specific Index.
469
+ *
470
+ * ```tsx
471
+ * const store = createStore().setTable('pets', {
472
+ * fido: {species: 'dog'},
473
+ * felix: {species: 'cat'},
474
+ * cujo: {species: 'dog'},
475
+ * });
476
+ *
477
+ * const indexes = createIndexes(store);
478
+ * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
479
+ *
480
+ * const listenerId = indexes.addSliceIdsListener(
481
+ * 'bySpecies',
482
+ * (indexes, indexId) => {
483
+ * console.log('Slice Ids for bySpecies index changed');
484
+ * console.log(indexes.getSliceIds('bySpecies'));
485
+ * },
486
+ * );
487
+ *
488
+ * store.setRow('pets', 'lowly', {species: 'worm'});
489
+ * // -> 'Slice Ids for bySpecies index changed'
490
+ * // -> ['dog', 'cat', 'worm']
491
+ *
492
+ * indexes.delListener(listenerId);
493
+ * ```
494
+ * @example
495
+ * This example creates a Store, a Indexes object, and then registers a
496
+ * listener that responds to any changes to any Index.
497
+ *
498
+ * ```tsx
499
+ * const store = createStore().setTable('pets', {
500
+ * fido: {species: 'dog', color: 'brown'},
501
+ * felix: {species: 'cat', color: 'black'},
502
+ * cujo: {species: 'dog', color: 'brown'},
503
+ * });
504
+ *
505
+ * const indexes = createIndexes(store)
506
+ * .setIndexDefinition('bySpecies', 'pets', 'species')
507
+ * .setIndexDefinition('byColor', 'pets', 'color');
508
+ *
509
+ * const listenerId = indexes.addSliceIdsListener(
510
+ * null,
511
+ * (indexes, indexId) => {
512
+ * console.log(`Slice Ids for ${indexId} index changed`);
513
+ * console.log(indexes.getSliceIds(indexId));
514
+ * },
515
+ * );
516
+ *
517
+ * store.setRow('pets', 'lowly', {species: 'worm', color: 'pink'});
518
+ * // -> 'Slice Ids for bySpecies index changed'
519
+ * // -> ['dog', 'cat', 'worm']
520
+ * // -> 'Slice Ids for byColor index changed'
521
+ * // -> ['brown', 'black', 'pink']
522
+ *
523
+ * indexes.delListener(listenerId);
524
+ * ```
525
+ * @category Listener
526
+ */
527
+ addSliceIdsListener(indexId: IdOrNull, listener: SliceIdsListener): Id;
528
+
529
+ /**
530
+ * The addSliceRowIdsListener method registers a listener function with the
531
+ * Indexes object that will be called whenever the Row Ids in a Slice change.
532
+ *
533
+ * You can either listen to a single Slice (by specifying the Index Id and
534
+ * Slice Id as the method's first two parameters), or changes to any Slice (by
535
+ * providing `null` wildcards).
536
+ *
537
+ * Both, either, or neither of the `indexId` and `sliceId` parameters can be
538
+ * wildcarded with `null`. You can listen to a specific Slice in a specific
539
+ * Index, any Slice in a specific Index, a specific Slice in any Index, or any
540
+ * Slice in any Index.
541
+ *
542
+ * The provided listener is a SliceRowIdsListener function, and will be called
543
+ * with a reference to the Indexes object, the Id of the Index, and the Id of
544
+ * the Slice that changed.
545
+ *
546
+ * @param indexId The Id of the Index to listen to, or `null` as a wildcard.
547
+ * @param sliceId The Id of the Slice to listen to, or `null` as a wildcard.
548
+ * @param listener The function that will be called whenever the Row Ids in
549
+ * the Slice change.
550
+ * @returns A unique Id for the listener that can later be used to remove it.
551
+ * @example
552
+ * This example creates a Store, a Indexes object, and then registers a
553
+ * listener that responds to any changes to a specific Slice.
554
+ *
555
+ * ```tsx
556
+ * const store = createStore().setTable('pets', {
557
+ * fido: {species: 'dog'},
558
+ * felix: {species: 'cat'},
559
+ * cujo: {species: 'dog'},
560
+ * });
561
+ *
562
+ * const indexes = createIndexes(store);
563
+ * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
564
+ *
565
+ * const listenerId = indexes.addSliceRowIdsListener(
566
+ * 'bySpecies',
567
+ * 'dog',
568
+ * (indexes, indexId, sliceId) => {
569
+ * console.log('Row Ids for dog slice in bySpecies index changed');
570
+ * console.log(indexes.getSliceRowIds('bySpecies', 'dog'));
571
+ * },
572
+ * );
573
+ *
574
+ * store.setRow('pets', 'toto', {species: 'dog'});
575
+ * // -> 'Row Ids for dog slice in bySpecies index changed'
576
+ * // -> ['fido', 'cujo', 'toto']
577
+ *
578
+ * indexes.delListener(listenerId);
579
+ * ```
580
+ * @example
581
+ * This example creates a Store, a Indexes object, and then registers a
582
+ * listener that responds to any changes to any Slice.
583
+ *
584
+ * ```tsx
585
+ * const store = createStore().setTable('pets', {
586
+ * fido: {species: 'dog', color: 'brown'},
587
+ * felix: {species: 'cat', color: 'black'},
588
+ * cujo: {species: 'dog', color: 'black'},
589
+ * });
590
+ *
591
+ * const indexes = createIndexes(store)
592
+ * .setIndexDefinition('bySpecies', 'pets', 'species')
593
+ * .setIndexDefinition('byColor', 'pets', 'color');
594
+ *
595
+ * const listenerId = indexes.addSliceRowIdsListener(
596
+ * null,
597
+ * null,
598
+ * (indexes, indexId, sliceId) => {
599
+ * console.log(
600
+ * `Row Ids for ${sliceId} slice in ${indexId} index changed`,
601
+ * );
602
+ * console.log(indexes.getSliceRowIds(indexId, sliceId));
603
+ * },
604
+ * );
605
+ *
606
+ * store.setRow('pets', 'toto', {species: 'dog', color: 'brown'});
607
+ * // -> 'Row Ids for dog slice in bySpecies index changed'
608
+ * // -> ['fido', 'cujo', 'toto']
609
+ * // -> 'Row Ids for brown slice in byColor index changed'
610
+ * // -> ['fido', 'toto']
611
+ *
612
+ * indexes.delListener(listenerId);
613
+ * ```
614
+ * @category Listener
615
+ */
616
+ addSliceRowIdsListener(
617
+ indexId: IdOrNull,
618
+ sliceId: IdOrNull,
619
+ listener: SliceRowIdsListener,
620
+ ): Id;
621
+
622
+ /**
623
+ * The delListener method removes a listener that was previously added to the
624
+ * Indexes object.
625
+ *
626
+ * Use the Id returned by whichever method was used to add the listener. Note
627
+ * that the Indexes object may re-use this Id for future listeners added to
628
+ * it.
629
+ *
630
+ * @param listenerId The Id of the listener to remove.
631
+ * @returns A reference to the Indexes object.
632
+ * @example
633
+ * This example creates a Store, a Indexes object, registers a listener, and
634
+ * then removes it.
635
+ *
636
+ * ```tsx
637
+ * const store = createStore().setTable('pets', {
638
+ * fido: {species: 'dog'},
639
+ * felix: {species: 'cat'},
640
+ * cujo: {species: 'dog'},
641
+ * });
642
+ *
643
+ * const indexes = createIndexes(store);
644
+ * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
645
+ *
646
+ * const listenerId = indexes.addSliceIdsListener(
647
+ * 'bySpecies',
648
+ * (indexes, indexId) => {
649
+ * console.log('Slice Ids for bySpecies index changed');
650
+ * },
651
+ * );
652
+ *
653
+ * store.setRow('pets', 'lowly', {species: 'worm'});
654
+ * // -> 'Slice Ids for bySpecies index changed'
655
+ *
656
+ * indexes.delListener(listenerId);
657
+ *
658
+ * store.setRow('pets', 'toto', {species: 'dog'});
659
+ * // -> undefined
660
+ * // The listener is not called.
661
+ * ```
662
+ * @category Listener
663
+ */
664
+ delListener(listenerId: Id): Indexes;
665
+
666
+ /**
667
+ * The destroy method should be called when this Indexes object is no longer
668
+ * used.
669
+ *
670
+ * This guarantees that all of the listeners that the object registered with
671
+ * the underlying Store are removed and it can be correctly garbage collected.
672
+ *
673
+ * @example
674
+ * This example creates a Store, adds an Indexes object with a
675
+ * definition (that registers a RowListener with the underlying Store),
676
+ * and then destroys it again, removing the listener.
677
+ *
678
+ * ```tsx
679
+ * const store = createStore().setTable('pets', {
680
+ * fido: {species: 'dog'},
681
+ * felix: {species: 'cat'},
682
+ * cujo: {species: 'dog'},
683
+ * });
684
+ *
685
+ * const indexes = createIndexes(store);
686
+ * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
687
+ * console.log(store.getListenerStats().row);
688
+ * // -> 1
689
+ *
690
+ * indexes.destroy();
691
+ *
692
+ * console.log(store.getListenerStats().row);
693
+ * // -> 0
694
+ * ```
695
+ * @category Lifecycle
696
+ */
697
+ destroy(): void;
698
+
699
+ /**
700
+ * The getListenerStats method provides a set of statistics about the
701
+ * listeners registered with the Indexes object, and is used for debugging
702
+ * purposes.
703
+ *
704
+ * The IndexesListenerStats object contains a breakdown of the different types
705
+ * of listener.
706
+ *
707
+ * The statistics are only populated in a debug build: production builds
708
+ * return an empty object. The method is intended to be used during
709
+ * development to ensure your application is not leaking listener
710
+ * registrations, for example.
711
+ *
712
+ * @returns A IndexesListenerStats object containing Indexes listener
713
+ * statistics.
714
+ * @example
715
+ * This example gets the listener statistics of an Indexes object.
716
+ *
717
+ * ```tsx
718
+ * const store = createStore();
719
+ * const indexes = createIndexes(store);
720
+ * indexes.addSliceIdsListener(null, () => {
721
+ * console.log('Slice Ids changed');
722
+ * });
723
+ * indexes.addSliceRowIdsListener(null, null, () => {
724
+ * console.log('Slice Row Ids changed');
725
+ * });
726
+ *
727
+ * console.log(indexes.getListenerStats());
728
+ * // -> {sliceIds: 1, sliceRowIds: 1}
729
+ * ```
730
+ * @category Development
731
+ */
732
+ getListenerStats(): IndexesListenerStats;
733
+ }
734
+
735
+ /**
736
+ * The createIndexes function creates an Indexes object, and is the main entry
737
+ * point into the indexes module.
738
+ *
739
+ * It is trivially simple.
740
+ *
741
+ * A given Store can only have one Indexes object associated with it. If you
742
+ * call this function twice on the same Store, your second call will return a
743
+ * reference to the Indexes object created by the first.
744
+ *
745
+ * @param store The Store for which to register Index definitions.
746
+ * @returns A reference to the new Indexes object.
747
+ * @example
748
+ * This example creates an Indexes object.
749
+ *
750
+ * ```tsx
751
+ * const store = createStore();
752
+ * const indexes = createIndexes(store);
753
+ * console.log(indexes.getIndexIds());
754
+ * // -> []
755
+ * ```
756
+ * @example
757
+ * This example creates an Indexes object, and calls the method a second time
758
+ * for the same Store to return the same object.
759
+ *
760
+ * ```tsx
761
+ * const store = createStore();
762
+ * const indexes1 = createIndexes(store);
763
+ * const indexes2 = createIndexes(store);
764
+ * console.log(indexes1 === indexes2);
765
+ * // -> true
766
+ * ```
767
+ */
768
+ export function createIndexes(store: Store): Indexes;
769
+
770
+ /**
771
+ * The defaultSorter function is provided as a convenience to sort keys
772
+ * alphanumerically, and can be provided to the `sliceIdSorter` and
773
+ * `rowIdSorter` parameters of the setIndexDefinition method, for example.
774
+ *
775
+ * @param sortKey1 The first item of the pair to compare.
776
+ * @param sortKey2 The second item of the pair to compare.
777
+ * @returns A number indicating how to sort the pair.
778
+ * @example
779
+ * This example creates an Indexes object.
780
+ *
781
+ * ```tsx
782
+ * const store = createStore();
783
+ * const indexes = createIndexes(store);
784
+ * console.log(indexes.getIndexIds());
785
+ * // -> []
786
+ * ```
787
+ * @example
788
+ * This example creates a Store, creates an Indexes object, and defines an
789
+ * Index based on the first letter of the pets' names. The Slice Ids (and Row
790
+ * Ids within them) are alphabetically sorted using the defaultSorter function.
791
+ *
792
+ * ```tsx
793
+ * const store = createStore().setTable('pets', {
794
+ * fido: {species: 'dog'},
795
+ * felix: {species: 'cat'},
796
+ * cujo: {species: 'dog'},
797
+ * });
798
+ *
799
+ * const indexes = createIndexes(store);
800
+ * indexes.setIndexDefinition(
801
+ * 'byFirst', // indexId
802
+ * 'pets', // tableId
803
+ * (_, rowId) => rowId[0], // each Row's Slice Id
804
+ * (_, rowId) => rowId, // each Row's sort key
805
+ * defaultSorter, // sort Slice Ids
806
+ * defaultSorter, // sort Row Ids by sort key
807
+ * );
808
+ *
809
+ * console.log(indexes.getSliceIds('byFirst'));
810
+ * // -> ['c', 'f']
811
+ * console.log(indexes.getSliceRowIds('byFirst', 'f'));
812
+ * // -> ['felix', 'fido']
813
+ * ```
814
+ */
815
+ export function defaultSorter(sortKey1: SortKey, sortKey2: SortKey): number;