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
@@ -0,0 +1,3066 @@
1
+ /**
2
+ * The queries module of the TinyBase project provides the ability to create and
3
+ * track queries of the data in Store objects.
4
+ *
5
+ * The main entry point to this module is the createQueries function, which
6
+ * returns a new Queries object. From there, you can create new query
7
+ * definitions, access the results of those directly, and register listeners for
8
+ * when they change.
9
+ *
10
+ * @packageDocumentation
11
+ * @module queries
12
+ * @since v2.0.0-beta
13
+ */
14
+
15
+ import {
16
+ Cell,
17
+ CellCallback,
18
+ CellOrUndefined,
19
+ GetCell,
20
+ GetCellChange,
21
+ Row,
22
+ RowCallback,
23
+ Store,
24
+ Table,
25
+ TableCallback,
26
+ } from './store.d';
27
+ import {Id, IdOrNull, Ids, SortKey} from './common.d';
28
+
29
+ /**
30
+ * The Aggregate type describes a custom function that takes an array of Cell
31
+ * values and returns an aggregate of them.
32
+ *
33
+ * There are a number of common predefined aggregators, such as for counting,
34
+ * summing, and averaging values. This type is instead used for when you wish to
35
+ * use a more complex aggregation of your own devising.
36
+ *
37
+ * @param cells The array of Cell values to be aggregated.
38
+ * @param length The length of the array of Cell values to be aggregated.
39
+ * @returns The value of the aggregation.
40
+ * @category Aggregators
41
+ * @since v2.0.0-beta
42
+ */
43
+ export type Aggregate = (cells: Cell[], length: number) => Cell;
44
+
45
+ /**
46
+ * The AggregateAdd type describes a function that can be used to optimize a
47
+ * custom Aggregate by providing a shortcut for when a single value is added to
48
+ * the input values.
49
+ *
50
+ * Some aggregation functions do not need to recalculate the aggregation of the
51
+ * whole set when one value changes. For example, when adding a new number to a
52
+ * series, the new sum of the series is the new value added to the previous sum.
53
+ *
54
+ * If it is not possible to shortcut the aggregation based on just one value
55
+ * being added, return `undefined` and the aggregation will be completely
56
+ * recalculated.
57
+ *
58
+ * Where possible, if you are providing a custom Aggregate, seek an
59
+ * implementation of an AggregateAdd function that can reduce the complexity
60
+ * cost of growing the input data set.
61
+ *
62
+ * @param current The current value of the aggregation.
63
+ * @param add The Cell value being added to the aggregation.
64
+ * @param length The length of the array of Cell values in the aggregation.
65
+ * @returns The new value of the aggregation.
66
+ * @category Aggregators
67
+ * @since v2.0.0-beta
68
+ */
69
+ export type AggregateAdd = (
70
+ current: Cell,
71
+ add: Cell,
72
+ length: number,
73
+ ) => Cell | undefined;
74
+
75
+ /**
76
+ * The AggregateRemove type describes a function that can be used to optimize a
77
+ * custom Aggregate by providing a shortcut for when a single value is removed
78
+ * from the input values.
79
+ *
80
+ * Some aggregation functions do not need to recalculate the aggregation of the
81
+ * whole set when one value changes. For example, when removing a number from a
82
+ * series, the new sum of the series is the new value subtracted from the
83
+ * previous sum.
84
+ *
85
+ * If it is not possible to shortcut the aggregation based on just one value
86
+ * being removed, return `undefined` and the aggregation will be completely
87
+ * recalculated. One example might be if you were taking the minimum of the
88
+ * values, and the previous minimum is being removed. The whole of the rest of
89
+ * the list will need to be re-scanned to find a new minimum.
90
+ *
91
+ * Where possible, if you are providing a custom Aggregate, seek an
92
+ * implementation of an AggregateRemove function that can reduce the complexity
93
+ * cost of shrinking the input data set.
94
+ *
95
+ * @param current The current value of the aggregation.
96
+ * @param remove The Cell value being removed from the aggregation.
97
+ * @param length The length of the array of Cell values in the aggregation.
98
+ * @returns The new value of the aggregation.
99
+ * @category Aggregators
100
+ * @since v2.0.0-beta
101
+ */
102
+ export type AggregateRemove = (
103
+ current: Cell,
104
+ remove: Cell,
105
+ length: number,
106
+ ) => Cell | undefined;
107
+
108
+ /**
109
+ * The AggregateReplace type describes a function that can be used to optimize a
110
+ * custom Aggregate by providing a shortcut for when a single value in the input
111
+ * values is replaced with another.
112
+ *
113
+ * Some aggregation functions do not need to recalculate the aggregation of the
114
+ * whole set when one value changes. For example, when replacing a number in a
115
+ * series, the new sum of the series is the previous sum, plus the new value,
116
+ * minus the old value.
117
+ *
118
+ * If it is not possible to shortcut the aggregation based on just one value
119
+ * changing, return `undefined` and the aggregation will be completely
120
+ * recalculated.
121
+ *
122
+ * Where possible, if you are providing a custom Aggregate, seek an
123
+ * implementation of an AggregateReplace function that can reduce the complexity
124
+ * cost of changing the input data set in place.
125
+ *
126
+ * @param current The current value of the aggregation.
127
+ * @param add The Cell value being added to the aggregation.
128
+ * @param remove The Cell value being removed from the aggregation.
129
+ * @param length The length of the array of Cell values in the aggregation.
130
+ * @returns The new value of the aggregation.
131
+ * @category Aggregators
132
+ * @since v2.0.0-beta
133
+ */
134
+ export type AggregateReplace = (
135
+ current: Cell,
136
+ add: Cell,
137
+ remove: Cell,
138
+ length: number,
139
+ ) => Cell | undefined;
140
+
141
+ /**
142
+ * The QueryCallback type describes a function that takes a query's Id.
143
+ *
144
+ * A QueryCallback is provided when using the forEachQuery method, so that you
145
+ * can do something based on every query in the Queries object. See that method
146
+ * for specific examples.
147
+ *
148
+ * @param queryId The Id of the query that the callback can operate on.
149
+ * @category Callback
150
+ * @since v2.0.0-beta
151
+ */
152
+ export type QueryCallback = (queryId: Id) => void;
153
+
154
+ /**
155
+ * The ResultTableListener type describes a function that is used to listen to
156
+ * changes to a query's result Table.
157
+ *
158
+ * A ResultTableListener is provided when using the addResultTableListener
159
+ * method. See that method for specific examples.
160
+ *
161
+ * When called, a ResultTableListener is given a reference to the Queries
162
+ * object, the Id of the Table that changed (which is the same as the query Id),
163
+ * and a GetCellChange function that can be used to query Cell values before and
164
+ * after the change.
165
+ *
166
+ * @param queries A reference to the Queries object that changed.
167
+ * @param tableId The Id of the Table that changed, which is also the query Id.
168
+ * @param getCellChange A function that returns information about any Cell's
169
+ * changes.
170
+ * @category Listener
171
+ * @since v2.0.0-beta
172
+ */
173
+ export type ResultTableListener = (
174
+ queries: Queries,
175
+ tableId: Id,
176
+ getCellChange: GetCellChange | undefined,
177
+ ) => void;
178
+
179
+ /**
180
+ * The ResultRowIdsListener type describes a function that is used to listen to
181
+ * changes to the Row Ids in a query's result Table.
182
+ *
183
+ * A ResultRowIdsListener is provided when using the addResultRowIdsListener
184
+ * method. See that method for specific examples.
185
+ *
186
+ * When called, a ResultRowIdsListener is given a reference to the Queries
187
+ * object, and the Id of the Table whose Row Ids changed (which is the same as
188
+ * the query Id).
189
+ *
190
+ * @param queries A reference to the Queries object that changed.
191
+ * @param tableId The Id of the Table that changed, which is also the query Id.
192
+ * @category Listener
193
+ * @since v2.0.0-beta
194
+ */
195
+ export type ResultRowIdsListener = (queries: Queries, tableId: Id) => void;
196
+
197
+ /**
198
+ * The ResultRowListener type describes a function that is used to listen to
199
+ * changes to a Row in a query's result Table.
200
+ *
201
+ * A ResultRowListener is provided when using the addResultRowListener method.
202
+ * See that method for specific examples.
203
+ *
204
+ * When called, a ResultRowListener is given a reference to the Queries object,
205
+ * the Id of the Table that changed (which is the same as the query Id), the Id
206
+ * of the Row that changed, and a GetCellChange function that can be used to
207
+ * query Cell values before and after the change.
208
+ *
209
+ * @param queries A reference to the Queries object that changed.
210
+ * @param tableId The Id of the Table that changed, which is also the query Id.
211
+ * @param rowId The Id of the Row that changed.
212
+ * @param getCellChange A function that returns information about any Cell's
213
+ * changes.
214
+ * @category Listener
215
+ * @since v2.0.0-beta
216
+ */
217
+ export type ResultRowListener = (
218
+ queries: Queries,
219
+ tableId: Id,
220
+ rowId: Id,
221
+ getCellChange: GetCellChange | undefined,
222
+ ) => void;
223
+
224
+ /**
225
+ * The ResultCellIdsListener type describes a function that is used to listen to
226
+ * changes to the Cell Ids in a Row in a query's result Table.
227
+ *
228
+ * A ResultCellIdsListener is provided when using the addResultCellIdsListener
229
+ * method. See that method for specific examples.
230
+ *
231
+ * When called, a ResultCellIdsListener is given a reference to the Queries
232
+ * object, the Id of the Table that changed (which is the same as the query Id),
233
+ * and the Id of the Row whose Cell Ids changed.
234
+ *
235
+ * @param queries A reference to the Queries object that changed.
236
+ * @param tableId The Id of the Table that changed, which is also the query Id.
237
+ * @param rowId The Id of the Row that changed.
238
+ * @category Listener
239
+ * @since v2.0.0-beta
240
+ */
241
+ export type ResultCellIdsListener = (
242
+ queries: Queries,
243
+ tableId: Id,
244
+ rowId: Id,
245
+ ) => void;
246
+
247
+ /**
248
+ * The ResultCellListener type describes a function that is used to listen to
249
+ * changes to a Cell in a query's result Table.
250
+ *
251
+ * A ResultCellListener is provided when using the addResultCellListener method.
252
+ * See that method for specific examples.
253
+ *
254
+ * When called, a ResultCellListener is given a reference to the Queries object,
255
+ * the Id of the Table that changed (which is the same as the query Id), the Id
256
+ * of the Row that changed, and the Id of Cell that changed. It is also given
257
+ * the new value of the Cell, the old value of the Cell, and a GetCellChange
258
+ * function that can be used to query Cell values before and after the change.
259
+ *
260
+ * @param queries A reference to the Queries object that changed.
261
+ * @param tableId The Id of the Table that changed, which is also the query Id.
262
+ * @param rowId The Id of the Row that changed.
263
+ * @param cellId The Id of the Cell that changed.
264
+ * @param newCell The new value of the Cell that changed.
265
+ * @param oldCell The old value of the Cell that changed.
266
+ * @param getCellChange A function that returns information about any Cell's
267
+ * changes.
268
+ * @category Listener
269
+ * @since v2.0.0-beta
270
+ */
271
+ export type ResultCellListener = (
272
+ queries: Queries,
273
+ tableId: Id,
274
+ rowId: Id,
275
+ cellId: Id,
276
+ newCell: Cell,
277
+ oldCell: Cell,
278
+ getCellChange: GetCellChange | undefined,
279
+ ) => void;
280
+
281
+ /**
282
+ * The QueriesListenerStats type describes the number of listeners registered
283
+ * with the Queries object, and can be used for debugging purposes.
284
+ *
285
+ * A QueriesListenerStats object is returned from the getListenerStats method,
286
+ * and is only populated in a debug build.
287
+ *
288
+ * @category Development
289
+ * @since v2.0.0-beta
290
+ */
291
+ export type QueriesListenerStats = {
292
+ /**
293
+ * The number of ResultTableListeners registered with the Store.
294
+ */
295
+ table?: number;
296
+ /**
297
+ * The number of ResultRowIdsListeners registered with the Store.
298
+ */
299
+ rowIds?: number;
300
+ /**
301
+ * The number of ResultRowListeners registered with the Store.
302
+ */
303
+ row?: number;
304
+ /**
305
+ * The number of ResultCellIdsListeners registered with the Store.
306
+ */
307
+ cellIds?: number;
308
+ /**
309
+ * The number of ResultCellListeners registered with the Store.
310
+ */
311
+ cell?: number;
312
+ };
313
+
314
+ /**
315
+ * The GetTableCell type describes a function that takes a Id and returns the
316
+ * Cell value for a particular Row, optionally in a joined Table.
317
+ *
318
+ * A GetTableCell can be provided when setting query definitions, specifically
319
+ * in the Select and Where clauses when you want to create or filter on
320
+ * calculated values. See those methods for specific examples.
321
+ *
322
+ * @category Callback
323
+ * @since v2.0.0-beta
324
+ */
325
+ export type GetTableCell = {
326
+ /**
327
+ * When called with one parameter, this function will return the value of the
328
+ * specified Cell from the query's main Table for the Row being selected or
329
+ * filtered.
330
+ *
331
+ * @param cellId The Id of the Cell to fetch the value for.
332
+ * @returns A Cell value or `undefined`.
333
+ */
334
+ (cellId: Id): CellOrUndefined;
335
+ /**
336
+ * When called with two parameters, this function will return the value of the
337
+ * specified Cell from a Table that has been joined in the query, for the Row
338
+ * being selected or filtered.
339
+ *
340
+ * @param joinedTableId The Id of the Table to fetch the value from. If the
341
+ * underlying Table was joined 'as' a different Id, that should instead be
342
+ * used.
343
+ * @param joinedCellId The Id of the Cell to fetch the value for.
344
+ * @returns A Cell value or `undefined`.
345
+ */
346
+ (joinedTableId: Id, joinedCellId: Id): CellOrUndefined;
347
+ };
348
+
349
+ /**
350
+ * The Select type describes a function that lets you specify a Cell or
351
+ * calculated value for including into the query's result.
352
+ *
353
+ * The Select function is provided as an parameter in the `build` parameter of
354
+ * the setQueryDefinition method. A query definition must call the Select
355
+ * function at least once, otherwise it will be meaningless and return no data.
356
+ *
357
+ * @example
358
+ * This example shows a query that selects two Cells from the main query Table.
359
+ *
360
+ * ```js
361
+ * const store = createStore().setTable('pets', {
362
+ * fido: {species: 'dog', color: 'brown'},
363
+ * felix: {species: 'cat', color: 'black'},
364
+ * cujo: {species: 'dog', color: 'black'},
365
+ * });
366
+ *
367
+ * const queries = createQueries(store);
368
+ * queries.setQueryDefinition('query', 'pets', ({select}) => {
369
+ * select('species');
370
+ * select('color');
371
+ * });
372
+ *
373
+ * queries.forEachResultRow('query', (rowId) => {
374
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
375
+ * });
376
+ * // -> {fido: {species: 'dog', color: 'brown'}}
377
+ * // -> {felix: {species: 'cat', color: 'black'}}
378
+ * // -> {cujo: {species: 'dog', color: 'black'}}
379
+ * ```
380
+ * @example
381
+ * This example shows a query that selects two Cells, one from a joined Table.
382
+ *
383
+ * ```js
384
+ * const store = createStore()
385
+ * .setTable('pets', {
386
+ * fido: {species: 'dog', ownerId: '1'},
387
+ * felix: {species: 'cat', ownerId: '2'},
388
+ * cujo: {species: 'dog', ownerId: '3'},
389
+ * })
390
+ * .setTable('owners', {
391
+ * '1': {name: 'Alice'},
392
+ * '2': {name: 'Bob'},
393
+ * '3': {name: 'Carol'},
394
+ * });
395
+ *
396
+ * const queries = createQueries(store);
397
+ * queries.setQueryDefinition('query', 'pets', ({select, join}) => {
398
+ * select('species');
399
+ * select('owners', 'name');
400
+ * // from pets
401
+ * join('owners', 'ownerId');
402
+ * });
403
+ *
404
+ * queries.forEachResultRow('query', (rowId) => {
405
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
406
+ * });
407
+ * // -> {fido: {species: 'dog', name: 'Alice'}}
408
+ * // -> {felix: {species: 'cat', name: 'Bob'}}
409
+ * // -> {cujo: {species: 'dog', name: 'Carol'}}
410
+ * ```
411
+ * @example
412
+ * This example shows a query that calculates a value from two underlying Cells.
413
+ *
414
+ * ```js
415
+ * const store = createStore()
416
+ * .setTable('pets', {
417
+ * fido: {species: 'dog', ownerId: '1'},
418
+ * felix: {species: 'cat', ownerId: '2'},
419
+ * cujo: {species: 'dog', ownerId: '3'},
420
+ * })
421
+ * .setTable('owners', {
422
+ * '1': {name: 'Alice'},
423
+ * '2': {name: 'Bob'},
424
+ * '3': {name: 'Carol'},
425
+ * });
426
+ *
427
+ * const queries = createQueries(store);
428
+ * queries.setQueryDefinition('query', 'pets', ({select, join}) => {
429
+ * select(
430
+ * (getTableCell, rowId) =>
431
+ * `${getTableCell('species')} for ${getTableCell('owners', 'name')}`,
432
+ * ).as('description');
433
+ * join('owners', 'ownerId');
434
+ * });
435
+ *
436
+ * queries.forEachResultRow('query', (rowId) => {
437
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
438
+ * });
439
+ * // -> {fido: {description: 'dog for Alice'}}
440
+ * // -> {felix: {description: 'cat for Bob'}}
441
+ * // -> {cujo: {description: 'dog for Carol'}}
442
+ * ```
443
+ * @category Definition
444
+ * @since v2.0.0-beta
445
+ */
446
+ export type Select = {
447
+ /**
448
+ * Calling this function with one Id parameter will indicate that the query
449
+ * should select the value of the specified Cell from the query's main Table.
450
+ *
451
+ * @param cellId The Id of the Cell to fetch the value for.
452
+ * @returns A SelectedAs object so that the selected Cell Id can be optionally
453
+ * aliased.
454
+ */
455
+ (cellId: Id): SelectedAs;
456
+ /**
457
+ * Calling this function with two parameters will indicate that the query
458
+ * should select the value of the specified Cell from a Table that has been
459
+ * joined in the query.
460
+ *
461
+ * @param joinedTableId The Id of the Table to fetch the value from. If the
462
+ * underlying Table was joined 'as' a different Id, that should instead be
463
+ * used.
464
+ * @param joinedCellId The Id of the Cell to fetch the value for.
465
+ * @returns A SelectedAs object so that the selected Cell Id can be optionally
466
+ * aliased.
467
+ */
468
+ (joinedTableId: Id, joinedCellId: Id): SelectedAs;
469
+ /**
470
+ * Calling this function with one callback parameter will indicate that the
471
+ * query should select a calculated value, based on one or more Cell values in
472
+ * the main Table or a joined Table, or on the main Table's Row Id.
473
+ *
474
+ * @param getCell A callback that takes a GetTableCell function and the main
475
+ * Table's Row Id. These can be used to programmatically create a calculated
476
+ * value from multiple Cell values and the Row Id.
477
+ * @returns A SelectedAs object so that the selected Cell Id can be optionally
478
+ * aliased.
479
+ */
480
+ (
481
+ getCell: (getTableCell: GetTableCell, rowId: Id) => CellOrUndefined,
482
+ ): SelectedAs;
483
+ };
484
+ /**
485
+ * The SelectedAs type describes an object returned from calling a Select
486
+ * function so that the selected Cell Id can be optionally aliased.
487
+ *
488
+ * If you are using a callback in the Select cause, it is highly recommended to
489
+ * use the 'as' function, since otherwise a machine-generated column name will
490
+ * be used.
491
+ *
492
+ * Note that if two Select clauses are both aliased to the same name (or if two
493
+ * columns with the same underlying name are selected, both _without_ aliases),
494
+ * only the latter of two will be used in the query.
495
+ *
496
+ * @example
497
+ * This example shows a query that selects two Cells, one from a joined Table.
498
+ * Both are aliased with the 'as' function:
499
+ *
500
+ * ```js
501
+ * const store = createStore()
502
+ * .setTable('pets', {
503
+ * fido: {species: 'dog', ownerId: '1'},
504
+ * felix: {species: 'cat', ownerId: '2'},
505
+ * cujo: {species: 'dog', ownerId: '3'},
506
+ * })
507
+ * .setTable('owners', {
508
+ * '1': {name: 'Alice'},
509
+ * '2': {name: 'Bob'},
510
+ * '3': {name: 'Carol'},
511
+ * });
512
+ *
513
+ * const queries = createQueries(store);
514
+ * queries.setQueryDefinition('query', 'pets', ({select, join}) => {
515
+ * select('species').as('petSpecies');
516
+ * select('owners', 'name').as('ownerName');
517
+ * // from pets
518
+ * join('owners', 'ownerId');
519
+ * });
520
+ *
521
+ * queries.forEachResultRow('query', (rowId) => {
522
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
523
+ * });
524
+ * // -> {fido: {petSpecies: 'dog', ownerName: 'Alice'}}
525
+ * // -> {felix: {petSpecies: 'cat', ownerName: 'Bob'}}
526
+ * // -> {cujo: {petSpecies: 'dog', ownerName: 'Carol'}}
527
+ * ```
528
+ * @category Definition
529
+ * @since v2.0.0-beta
530
+ */
531
+ export type SelectedAs = {
532
+ /**
533
+ * A function that lets you specify an alias for the Cell Id.
534
+ */
535
+ as: (selectedCellId: Id) => void;
536
+ };
537
+
538
+ /**
539
+ * The Join type describes a function that lets you specify a Cell or calculated
540
+ * value to join the main query Table to others, by Row Id.
541
+ *
542
+ * The Join function is provided as an parameter in the `build` parameter of the
543
+ * setQueryDefinition method.
544
+ *
545
+ * You can join zero, one, or many Tables. You can join the same underlying
546
+ * Table multiple times, but in that case you will need to use the 'as' function
547
+ * to distinguish them from each other.
548
+ *
549
+ * By default, each join is made from the main query Table to the joined table,
550
+ * but it is also possible to connect via an intermediate join Table to a more
551
+ * distant join Table.
552
+ *
553
+ * Because a Join clause is used to identify which unique Row Id of the joined
554
+ * Table will be joined to each Row of the main Table, queries follow the 'left
555
+ * join' semantics you may be familiar with from SQL. This means that an
556
+ * unfiltered query will only ever return the same number of Rows as the main
557
+ * Table being queried, and indeed the resulting table (assuming it has not been
558
+ * aggregated) will even preserve the main Table's original Row Ids.
559
+ *
560
+ * @example
561
+ * This example shows a query that joins a single Table by using an Id present
562
+ * in the main query Table.
563
+ *
564
+ * ```js
565
+ * const store = createStore()
566
+ * .setTable('pets', {
567
+ * fido: {species: 'dog', ownerId: '1'},
568
+ * felix: {species: 'cat', ownerId: '2'},
569
+ * cujo: {species: 'dog', ownerId: '3'},
570
+ * })
571
+ * .setTable('owners', {
572
+ * '1': {name: 'Alice'},
573
+ * '2': {name: 'Bob'},
574
+ * '3': {name: 'Carol'},
575
+ * });
576
+ *
577
+ * const queries = createQueries(store);
578
+ * queries.setQueryDefinition('query', 'pets', ({select, join}) => {
579
+ * select('species');
580
+ * select('owners', 'name');
581
+ * // from pets
582
+ * join('owners', 'ownerId');
583
+ * });
584
+ *
585
+ * queries.forEachResultRow('query', (rowId) => {
586
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
587
+ * });
588
+ * // -> {fido: {species: 'dog', name: 'Alice'}}
589
+ * // -> {felix: {species: 'cat', name: 'Bob'}}
590
+ * // -> {cujo: {species: 'dog', name: 'Carol'}}
591
+ * ```
592
+ * @example
593
+ * This example shows a query that joins the same underlying Table twice, and
594
+ * aliases them (and the selected Cell Ids). Note the left-join semantics: Felix
595
+ * the cat was bought, but the seller was unknown. The record still exists in
596
+ * the result Table.
597
+ *
598
+ * ```js
599
+ * const store = createStore()
600
+ * .setTable('pets', {
601
+ * fido: {species: 'dog', buyerId: '1', sellerId: '2'},
602
+ * felix: {species: 'cat', buyerId: '2'},
603
+ * cujo: {species: 'dog', buyerId: '3', sellerId: '1'},
604
+ * })
605
+ * .setTable('humans', {
606
+ * '1': {name: 'Alice'},
607
+ * '2': {name: 'Bob'},
608
+ * '3': {name: 'Carol'},
609
+ * });
610
+ *
611
+ * const queries = createQueries(store);
612
+ * queries.setQueryDefinition('query', 'pets', ({select, join}) => {
613
+ * select('buyers', 'name').as('buyer');
614
+ * select('sellers', 'name').as('seller');
615
+ * // from pets
616
+ * join('humans', 'buyerId').as('buyers');
617
+ * join('humans', 'sellerId').as('sellers');
618
+ * });
619
+ *
620
+ * queries.forEachResultRow('query', (rowId) => {
621
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
622
+ * });
623
+ * // -> {fido: {buyer: 'Alice', seller: 'Bob'}}
624
+ * // -> {felix: {buyer: 'Bob'}}
625
+ * // -> {cujo: {buyer: 'Carol', seller: 'Alice'}}
626
+ * ```
627
+ * @example
628
+ * This example shows a query that calculates the Id of the joined Table based
629
+ * from multiple values in the main Table rather than a single Cell.
630
+ *
631
+ * ```js
632
+ * const store = createStore()
633
+ * .setTable('pets', {
634
+ * fido: {species: 'dog', color: 'brown'},
635
+ * felix: {species: 'cat', color: 'black'},
636
+ * cujo: {species: 'dog', color: 'black'},
637
+ * })
638
+ * .setTable('colorSpecies', {
639
+ * 'brown-dog': {price: 6},
640
+ * 'black-dog': {price: 5},
641
+ * 'brown-cat': {price: 4},
642
+ * 'black-cat': {price: 3},
643
+ * });
644
+ *
645
+ * const queries = createQueries(store);
646
+ * queries.setQueryDefinition('query', 'pets', ({select, join}) => {
647
+ * select('colorSpecies', 'price');
648
+ * // from pets
649
+ * join(
650
+ * 'colorSpecies',
651
+ * (getCell) => `${getCell('color')}-${getCell('species')}`,
652
+ * );
653
+ * });
654
+ *
655
+ * queries.forEachResultRow('query', (rowId) => {
656
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
657
+ * });
658
+ * // -> {fido: {price: 6}}
659
+ * // -> {felix: {price: 3}}
660
+ * // -> {cujo: {price: 5}}
661
+ * ```
662
+ * @example
663
+ * This example shows a query that joins two Tables, one through the
664
+ * intermediate other.
665
+ *
666
+ * ```js
667
+ * const store = createStore()
668
+ * .setTable('pets', {
669
+ * fido: {species: 'dog', ownerId: '1'},
670
+ * felix: {species: 'cat', ownerId: '2'},
671
+ * cujo: {species: 'dog', ownerId: '3'},
672
+ * })
673
+ * .setTable('owners', {
674
+ * '1': {name: 'Alice', state: 'CA'},
675
+ * '2': {name: 'Bob', state: 'CA'},
676
+ * '3': {name: 'Carol', state: 'WA'},
677
+ * })
678
+ * .setTable('states', {
679
+ * CA: {name: 'California'},
680
+ * WA: {name: 'Washington'},
681
+ * });
682
+ *
683
+ * const queries = createQueries(store);
684
+ * queries.setQueryDefinition('query', 'pets', ({select, join}) => {
685
+ * select(
686
+ * (getTableCell, rowId) =>
687
+ * `${getTableCell('species')} in ${getTableCell('states', 'name')}`,
688
+ * ).as('description');
689
+ * // from pets
690
+ * join('owners', 'ownerId');
691
+ * join('states', 'owners', 'state');
692
+ * });
693
+ *
694
+ * queries.forEachResultRow('query', (rowId) => {
695
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
696
+ * });
697
+ * // -> {fido: {description: 'dog in California'}}
698
+ * // -> {felix: {description: 'cat in California'}}
699
+ * // -> {cujo: {description: 'dog in Washington'}}
700
+ * ```
701
+ * @category Definition
702
+ * @since v2.0.0-beta
703
+ */
704
+ export type Join = {
705
+ /**
706
+ * Calling this function with two Id parameters will indicate that the join to
707
+ * a Row in an adjacent Table is made by finding its Id in a Cell of the
708
+ * query's main Table.
709
+ *
710
+ * @param joinedTableId The Id of the Table to join to.
711
+ * @param on The Id of the Cell in the main Table that contains the joined
712
+ * Table's Row Id.
713
+ * @returns A JoinedAs object so that the joined Table Id can be optionally
714
+ * aliased.
715
+ */
716
+ (joinedTableId: Id, on: Id): JoinedAs;
717
+ /**
718
+ * Calling this function with two parameters (where the second is a function)
719
+ * will indicate that the join to a Row in an adjacent Table is made by
720
+ * calculating its Id from the Cells and the Row Id of the query's main Table.
721
+ *
722
+ * @param joinedTableId The Id of the Table to join to.
723
+ * @param on A callback that takes a GetCell function and the main Table's Row
724
+ * Id. These can be used to programmatically calculate the joined Table's Row
725
+ * Id.
726
+ * @returns A JoinedAs object so that the joined Table Id can be optionally
727
+ * aliased.
728
+ */
729
+ (
730
+ joinedTableId: Id,
731
+ on: (getCell: GetCell, rowId: Id) => Id | undefined,
732
+ ): JoinedAs;
733
+ /**
734
+ * Calling this function with three Id parameters will indicate that the join
735
+ * to a Row in distant Table is made by finding its Id in a Cell of an
736
+ * intermediately joined Table.
737
+ *
738
+ * @param joinedTableId The Id of the distant Table to join to.
739
+ * @param fromIntermediateJoinedTableId The Id of an intermediate Table (which
740
+ * should have been in turn joined to the main query table via other Join
741
+ * clauses).
742
+ * @param on The Id of the Cell in the intermediate Table that contains the
743
+ * joined Table's Row Id.
744
+ * @returns A JoinedAs object so that the joined Table Id can be optionally
745
+ * aliased.
746
+ */
747
+ (joinedTableId: Id, fromIntermediateJoinedTableId: Id, on: Id): JoinedAs;
748
+ /**
749
+ * Calling this function with three parameters (where the third is a function)
750
+ * will indicate that the join to a Row in distant Table is made by
751
+ * calculating its Id from the Cells and the Row Id of an intermediately
752
+ * joined Table.
753
+ *
754
+ * @param joinedTableId The Id of the Table to join to.
755
+ * @param fromIntermediateJoinedTableId The Id of an intermediate Table (which
756
+ * should have been in turn joined to the main query table via other Join
757
+ * clauses).
758
+ * @param on A callback that takes a GetCell function and the intermediate
759
+ * Table's Row Id. These can be used to programmatically calculate the joined
760
+ * Table's Row Id.
761
+ * @returns A JoinedAs object so that the joined Table Id can be optionally
762
+ * aliased.
763
+ */
764
+ (
765
+ joinedTableId: Id,
766
+ fromIntermediateJoinedTableId: Id,
767
+ on: (
768
+ getIntermediateJoinedCell: GetCell,
769
+ intermediateJoinedTableRowId: Id,
770
+ ) => Id | undefined,
771
+ ): JoinedAs;
772
+ };
773
+ /**
774
+ * The JoinedAs type describes an object returned from calling a Join function
775
+ * so that the joined Table Id can be optionally aliased.
776
+ *
777
+ * Note that if two Join clauses are both aliased to the same name (or if you
778
+ * create two joins to the same underlying Table, both _without_ aliases), only
779
+ * the latter of two will be used in the query.
780
+ *
781
+ * @example
782
+ * This example shows a query that joins the same underlying Table twice, for
783
+ * different purposes. Both joins are aliased with the 'as' function to
784
+ * disambiguate them. Note that the selected Cells are also aliased.
785
+ *
786
+ * ```js
787
+ * const store = createStore()
788
+ * .setTable('pets', {
789
+ * fido: {species: 'dog', buyerId: '1', sellerId: '2'},
790
+ * felix: {species: 'cat', buyerId: '2'},
791
+ * cujo: {species: 'dog', buyerId: '3', sellerId: '1'},
792
+ * })
793
+ * .setTable('humans', {
794
+ * '1': {name: 'Alice'},
795
+ * '2': {name: 'Bob'},
796
+ * '3': {name: 'Carol'},
797
+ * });
798
+ *
799
+ * const queries = createQueries(store);
800
+ * queries.setQueryDefinition('query', 'pets', ({select, join}) => {
801
+ * select('buyers', 'name').as('buyer');
802
+ * select('sellers', 'name').as('seller');
803
+ * // from pets
804
+ * join('humans', 'buyerId').as('buyers');
805
+ * join('humans', 'sellerId').as('sellers');
806
+ * });
807
+ *
808
+ * queries.forEachResultRow('query', (rowId) => {
809
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
810
+ * });
811
+ * // -> {fido: {buyer: 'Alice', seller: 'Bob'}}
812
+ * // -> {felix: {buyer: 'Bob'}}
813
+ * // -> {cujo: {buyer: 'Carol', seller: 'Alice'}}
814
+ * ```
815
+ * @category Definition
816
+ * @since v2.0.0-beta
817
+ */
818
+ export type JoinedAs = {as: (joinedTableId: Id) => void};
819
+
820
+ /**
821
+ * The Where type describes a function that lets you specify conditions to
822
+ * filter results, based on the underlying Cells of the main or joined Tables.
823
+ *
824
+ * The Where function is provided as an parameter in the `build` parameter of
825
+ * the setQueryDefinition method.
826
+ *
827
+ * If you do not specify a Where clause, you should expect every non-empty Row
828
+ * of the main Table to appear in the query's results.
829
+ *
830
+ * A Where condition has to be true for a Row to be included in the results.
831
+ * Each Where class is additive, as though combined with a logical 'and'. If you
832
+ * wish to create an 'or' expression, use the single parameter version of the
833
+ * type that allows arbitrary programmatic conditions.
834
+ *
835
+ * The Where clause differs from the Having clause in that the former describes
836
+ * conditions that should be met by underlying Cell values (whether selected or
837
+ * not), and the latter describes conditions based on calculated and aggregated
838
+ * values - after Group clauses have been applied.
839
+ *
840
+ * @example
841
+ * This example shows a query that filters the results from a single Table by
842
+ * comparing an underlying Cell from it with a value.
843
+ *
844
+ * ```js
845
+ * const store = createStore().setTable('pets', {
846
+ * fido: {species: 'dog'},
847
+ * felix: {species: 'cat'},
848
+ * cujo: {species: 'dog'},
849
+ * });
850
+ *
851
+ * const queries = createQueries(store);
852
+ * queries.setQueryDefinition('query', 'pets', ({select, where}) => {
853
+ * select('species');
854
+ * where('species', 'dog');
855
+ * });
856
+ *
857
+ * queries.forEachResultRow('query', (rowId) => {
858
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
859
+ * });
860
+ * // -> {fido: {species: 'dog'}}
861
+ * // -> {cujo: {species: 'dog'}}
862
+ * ```
863
+ * @example
864
+ * This example shows a query that filters the results of a query by comparing
865
+ * an underlying Cell from a joined Table with a value. Note that the joined
866
+ * table has also been aliased, and so its alias is used in the Where clause.
867
+ *
868
+ * ```js
869
+ * const store = createStore()
870
+ * .setTable('pets', {
871
+ * fido: {species: 'dog', ownerId: '1'},
872
+ * felix: {species: 'cat', ownerId: '2'},
873
+ * cujo: {species: 'dog', ownerId: '3'},
874
+ * })
875
+ * .setTable('owners', {
876
+ * '1': {name: 'Alice', state: 'CA'},
877
+ * '2': {name: 'Bob', state: 'CA'},
878
+ * '3': {name: 'Carol', state: 'WA'},
879
+ * });
880
+ *
881
+ * const queries = createQueries(store);
882
+ * queries.setQueryDefinition('query', 'pets', ({select, join, where}) => {
883
+ * select('species');
884
+ * // from pets
885
+ * join('owners', 'ownerId').as('petOwners');
886
+ * where('petOwners', 'state', 'CA');
887
+ * });
888
+ *
889
+ * queries.forEachResultRow('query', (rowId) => {
890
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
891
+ * });
892
+ * // -> {fido: {species: 'dog'}}
893
+ * // -> {felix: {species: 'cat'}}
894
+ * ```
895
+ * @example
896
+ * This example shows a query that filters the results of a query with a
897
+ * condition that is calculated from underlying Cell values from the main and
898
+ * joined Table. Note that the joined table has also been aliased, and so its
899
+ * alias is used in the Where clause.
900
+ *
901
+ * ```js
902
+ * const store = createStore()
903
+ * .setTable('pets', {
904
+ * fido: {species: 'dog', ownerId: '1'},
905
+ * felix: {species: 'cat', ownerId: '2'},
906
+ * cujo: {species: 'dog', ownerId: '3'},
907
+ * })
908
+ * .setTable('owners', {
909
+ * '1': {name: 'Alice', state: 'CA'},
910
+ * '2': {name: 'Bob', state: 'CA'},
911
+ * '3': {name: 'Carol', state: 'WA'},
912
+ * });
913
+ *
914
+ * const queries = createQueries(store);
915
+ * queries.setQueryDefinition('query', 'pets', ({select, join, where}) => {
916
+ * select('species');
917
+ * select('petOwners', 'state');
918
+ * // from pets
919
+ * join('owners', 'ownerId').as('petOwners');
920
+ * where(
921
+ * (getTableCell) =>
922
+ * getTableCell('pets', 'species') === 'cat' ||
923
+ * getTableCell('petOwners', 'state') === 'WA',
924
+ * );
925
+ * });
926
+ *
927
+ * queries.forEachResultRow('query', (rowId) => {
928
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
929
+ * });
930
+ * // -> {felix: {species: 'cat', state: 'CA'}}
931
+ * // -> {cujo: {species: 'dog', state: 'WA'}}
932
+ * ```
933
+ * @category Definition
934
+ * @since v2.0.0-beta
935
+ */
936
+ export type Where = {
937
+ /**
938
+ * Calling this function with two parameters is used to include only those
939
+ * Rows for which a specified Cell in the query's main Table has a specified
940
+ * value.
941
+ *
942
+ * @param cellId The Id of the Cell in the query's main Table to test.
943
+ * @param equals The value that the Cell has to have for the Row to be
944
+ * included in the result.
945
+ */
946
+ (cellId: Id, equals: Cell): void;
947
+ /**
948
+ * Calling this function with three parameters is used to include only those
949
+ * Rows for which a specified Cell in a joined Table has a specified value.
950
+ *
951
+ * @param joinedTableId The Id of the joined Table to test a value in. If the
952
+ * underlying Table was joined 'as' a different Id, that should instead be
953
+ * used.
954
+ * @param joinedCellId The Id of the Cell in the joined Table to test.
955
+ * @param equals The value that the Cell has to have for the Row to be
956
+ * included in the result.
957
+ */
958
+ (joinedTableId: Id, joinedCellId: Id, equals: Cell): void;
959
+ /**
960
+ * Calling this function with one callback parameter is used to include only
961
+ * those Rows which meet a calculated boolean condition, based on values in
962
+ * the main and (optionally) joined Tables.
963
+ *
964
+ * @param condition A callback that takes a GetTableCell function and that
965
+ * should return `true` for the Row to be included in the result.
966
+ */
967
+ (condition: (getTableCell: GetTableCell) => boolean): void;
968
+ };
969
+
970
+ /**
971
+ * The Group type describes a function that lets you specify that the values of
972
+ * a Cell in multiple result Rows should be aggregated together.
973
+ *
974
+ * The Group function is provided as an parameter in the `build` parameter of
975
+ * the setQueryDefinition method. When called, it should refer to a Cell Id (or
976
+ * aliased Id) specified in one of the Select functions, and indicate how the
977
+ * values should be aggregated.
978
+ *
979
+ * This is applied after any joins or where-based filtering.
980
+ *
981
+ * If you provide a Group for every Select, the result will be a single Row with
982
+ * every Cell having been aggregated. If you provide a Group for only one, or
983
+ * some, of the Select clauses, the _others_ will be automatically used as
984
+ * dimensional values (analogous to the 'group by` semantics in SQL), within
985
+ * which the aggregations of Group Cells will be performed.
986
+ *
987
+ * You can join the same underlying Cell multiple times, but in that case you
988
+ * will need to use the 'as' function to distinguish them from each other.
989
+ *
990
+ * The second parameter can be one of five predefined aggregates - 'count',
991
+ * 'sum', 'avg', 'min', and 'max' - or a custom function that produces your own
992
+ * aggregation of an array of Cell values.
993
+ *
994
+ * The final three parameters, `aggregateAdd`, `aggregateRemove`,
995
+ * `aggregateReplace` need only be provided when you are using your own custom
996
+ * `aggregate` function. These give you the opportunity to reduce your custom
997
+ * function's algorithmic complexity by providing shortcuts that can nudge an
998
+ * aggregation result when a single value is added, removed, or replaced in the
999
+ * input values.
1000
+ *
1001
+ * @param selectedCellId The Id of the Cell to aggregate. If the underlying Cell
1002
+ * was selected 'as' a different Id, that should instead be used.
1003
+ * @param aggregate Either a string representing one of a set of common
1004
+ * aggregation techniques ('count', 'sum', 'avg', 'min', or 'max'), or a
1005
+ * function that aggregates Cell values from each Row to create the aggregate's
1006
+ * overall.
1007
+ * @param aggregateAdd A function that can be used to optimize a custom
1008
+ * Aggregate by providing a shortcut for when a single value is added to the
1009
+ * input values - for example, when a Row is added to the Table.
1010
+ * @param aggregateRemove A function that can be used to optimize a custom
1011
+ * Aggregate by providing a shortcut for when a single value is removed from the
1012
+ * input values - for example ,when a Row is removed from the Table.
1013
+ * @param aggregateReplace A function that can be used to optimize a custom
1014
+ * Aggregate by providing a shortcut for when a single value in the input values
1015
+ * is replaced with another - for example, when a Row is updated.
1016
+ * @returns A GroupedAs object so that the grouped Cell Id can be optionally
1017
+ * aliased.
1018
+ * @example
1019
+ * This example shows a query that calculates the average of all the values in a
1020
+ * single selected Cell from a joined Table.
1021
+ *
1022
+ * ```js
1023
+ * const store = createStore()
1024
+ * .setTable('pets', {
1025
+ * fido: {species: 'dog'},
1026
+ * felix: {species: 'cat'},
1027
+ * cujo: {species: 'dog'},
1028
+ * lowly: {species: 'worm'},
1029
+ * })
1030
+ * .setTable('species', {
1031
+ * dog: {price: 5},
1032
+ * cat: {price: 4},
1033
+ * worm: {price: 1},
1034
+ * });
1035
+ *
1036
+ * const queries = createQueries(store);
1037
+ * queries.setQueryDefinition('query', 'pets', ({select, join, group}) => {
1038
+ * select('species', 'price');
1039
+ * // from pets
1040
+ * join('species', 'species');
1041
+ * group('price', 'avg').as('avgPrice');
1042
+ * });
1043
+ *
1044
+ * console.log(queries.getResultTable('query'));
1045
+ * // -> {0: {avgPrice: 3.75}}
1046
+ * // 2 dogs at 5, 1 cat at 4, 1 worm at 1: a total of 15 for 4 pets
1047
+ * ```
1048
+ * @example
1049
+ * This example shows a query that calculates the average of a two Cell values,
1050
+ * aggregated by the two other dimensional 'group by' Cells.
1051
+ *
1052
+ * ```js
1053
+ * const store = createStore()
1054
+ * .setTable('pets', {
1055
+ * fido: {species: 'dog', color: 'brown', owner: 'alice'},
1056
+ * felix: {species: 'cat', color: 'black', owner: 'bob'},
1057
+ * cujo: {species: 'dog', color: 'black', owner: 'bob'},
1058
+ * lowly: {species: 'worm', color: 'brown', owner: 'alice'},
1059
+ * carnaby: {species: 'parrot', color: 'black', owner: 'bob'},
1060
+ * polly: {species: 'parrot', color: 'red', owner: 'alice'},
1061
+ * })
1062
+ * .setTable('species', {
1063
+ * dog: {price: 5, legs: 4},
1064
+ * cat: {price: 4, legs: 4},
1065
+ * parrot: {price: 3, legs: 2},
1066
+ * worm: {price: 1, legs: 0},
1067
+ * });
1068
+ *
1069
+ * const queries = createQueries(store);
1070
+ * queries.setQueryDefinition('query', 'pets', ({select, join, group}) => {
1071
+ * select('pets', 'color'); // group by
1072
+ * select('pets', 'owner'); // group by
1073
+ * select('species', 'price'); // grouped
1074
+ * select('species', 'legs'); // grouped
1075
+ * // from pets
1076
+ * join('species', 'species');
1077
+ * group('price', 'avg').as('avgPrice');
1078
+ * group('legs', 'sum').as('sumLegs');
1079
+ * });
1080
+ *
1081
+ * queries.forEachResultRow('query', (rowId) => {
1082
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
1083
+ * });
1084
+ * // -> {0: {color: 'brown', owner: 'alice', avgPrice: 3, sumLegs: 4}}
1085
+ * // -> {1: {color: 'black', owner: 'bob', avgPrice: 4, sumLegs: 10}}
1086
+ * // -> {2: {color: 'red', owner: 'alice', avgPrice: 3, sumLegs: 2}}
1087
+ * ```
1088
+ * @example
1089
+ * This example shows a query that calculates the a custom aggregate of one
1090
+ * Cell's values, grouped by another. Note how `aggregateAdd`,
1091
+ * `aggregateRemove`, and `aggregateReplace` parameters are provided to make the
1092
+ * custom aggregation more efficient as individual values are added, removed, or
1093
+ * replaced during the lifecycle of the Table.
1094
+ *
1095
+ * ```js
1096
+ * const store = createStore()
1097
+ * .setTable('pets', {
1098
+ * fido: {species: 'dog', owner: 'alice'},
1099
+ * felix: {species: 'cat', owner: 'bob'},
1100
+ * cujo: {species: 'dog', owner: 'bob'},
1101
+ * lowly: {species: 'worm', owner: 'alice'},
1102
+ * carnaby: {species: 'parrot', owner: 'bob'},
1103
+ * polly: {species: 'parrot', owner: 'alice'},
1104
+ * })
1105
+ * .setTable('species', {
1106
+ * dog: {price: 5, legs: 4},
1107
+ * cat: {price: 4, legs: 4},
1108
+ * parrot: {price: 3, legs: 2},
1109
+ * worm: {price: 1, legs: 0},
1110
+ * });
1111
+ *
1112
+ * const queries = createQueries(store);
1113
+ * queries.setQueryDefinition('query', 'pets', ({select, join, group}) => {
1114
+ * select('pets', 'owner'); // group by
1115
+ * select('species', 'price'); // grouped
1116
+ * // from pets
1117
+ * join('species', 'species');
1118
+ * group(
1119
+ * 'price',
1120
+ * (cells) => Math.min(...cells.filter((cell) => cell > 2)),
1121
+ * (current, add) => (add > 2 ? Math.min(current, add) : current),
1122
+ * (current, remove) => (remove == current ? undefined : current),
1123
+ * (current, add, remove) =>
1124
+ * remove == current
1125
+ * ? undefined
1126
+ * : add > 2
1127
+ * ? Math.min(current, add)
1128
+ * : current,
1129
+ * ).as('lowestPriceOver2');
1130
+ * });
1131
+ *
1132
+ * queries.forEachResultRow('query', (rowId) => {
1133
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
1134
+ * });
1135
+ * // -> {0: {owner: 'alice', lowestPriceOver2: 3}}
1136
+ * // -> {1: {owner: 'bob', lowestPriceOver2: 3}}
1137
+ * // Both have a parrot at 3. Alice's worm at 1 is excluded from aggregation.
1138
+ * ```
1139
+ */
1140
+ export type Group = (
1141
+ selectedCellId: Id,
1142
+ aggregate: 'count' | 'sum' | 'avg' | 'min' | 'max' | Aggregate,
1143
+ aggregateAdd?: AggregateAdd,
1144
+ aggregateRemove?: AggregateRemove,
1145
+ aggregateReplace?: AggregateReplace,
1146
+ ) => GroupedAs;
1147
+ /**
1148
+ * The GroupedAs type describes an object returned from calling a Group function
1149
+ * so that the grouped Cell Id can be optionally aliased.
1150
+ *
1151
+ * Note that if two Group clauses are both aliased to the same name (or if you
1152
+ * create two groups of the same underlying Cell, both _without_ aliases), only
1153
+ * the latter of two will be used in the query.
1154
+ *
1155
+ * @example
1156
+ * This example shows a query that groups the same underlying Cell twice, for
1157
+ * different purposes. Both groups are aliased with the 'as' function to
1158
+ * disambiguate them.
1159
+ *
1160
+ * ```js
1161
+ * const store = createStore().setTable('pets', {
1162
+ * fido: {species: 'dog', price: 5},
1163
+ * felix: {species: 'cat', price: 4},
1164
+ * cujo: {species: 'dog', price: 4},
1165
+ * tom: {species: 'cat', price: 3},
1166
+ * });
1167
+ *
1168
+ * const queries = createQueries(store);
1169
+ * queries.setQueryDefinition('query', 'pets', ({select, group}) => {
1170
+ * select('pets', 'species');
1171
+ * select('pets', 'price');
1172
+ * group('price', 'min').as('minPrice');
1173
+ * group('price', 'max').as('maxPrice');
1174
+ * });
1175
+ *
1176
+ * queries.forEachResultRow('query', (rowId) => {
1177
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
1178
+ * });
1179
+ * // -> {0: {species: 'dog', minPrice: 4, maxPrice: 5}}
1180
+ * // -> {1: {species: 'cat', minPrice: 3, maxPrice: 4}}
1181
+ * ```
1182
+ * @category Definition
1183
+ * @since v2.0.0-beta
1184
+ */
1185
+ export type GroupedAs = {as: (groupedCellId: Id) => void};
1186
+
1187
+ /**
1188
+ * The Having type describes a function that lets you specify conditions to
1189
+ * filter results, based on the grouped Cells resulting from a Group clause.
1190
+ *
1191
+ * The Having function is provided as an parameter in the `build` parameter of
1192
+ * the setQueryDefinition method.
1193
+ *
1194
+ * A Having condition has to be true for a Row to be included in the results.
1195
+ * Each Having class is additive, as though combined with a logical 'and'. If
1196
+ * you wish to create an 'or' expression, use the single parameter version of
1197
+ * the type that allows arbitrary programmatic conditions.
1198
+ *
1199
+ * The Where clause differs from the Having clause in that the former describes
1200
+ * conditions that should be met by underlying Cell values (whether selected or
1201
+ * not), and the latter describes conditions based on calculated and aggregated
1202
+ * values - after Group clauses have been applied.
1203
+ *
1204
+ * Whilst it is technically possible to use a Having clause even if the results
1205
+ * have not been grouped with a Group clause, you should expect it to be less
1206
+ * performant than using a Where clause, due to that being applied earlier in
1207
+ * the query process.
1208
+ *
1209
+ * @example
1210
+ * This example shows a query that filters the results from a grouped Table by
1211
+ * comparing a Cell from it with a value.
1212
+ *
1213
+ * ```js
1214
+ * const store = createStore().setTable('pets', {
1215
+ * fido: {species: 'dog', price: 5},
1216
+ * felix: {species: 'cat', price: 4},
1217
+ * cujo: {species: 'dog', price: 4},
1218
+ * tom: {species: 'cat', price: 3},
1219
+ * carnaby: {species: 'parrot', price: 3},
1220
+ * polly: {species: 'parrot', price: 3},
1221
+ * });
1222
+ *
1223
+ * const queries = createQueries(store);
1224
+ * queries.setQueryDefinition('query', 'pets', ({select, group, having}) => {
1225
+ * select('pets', 'species');
1226
+ * select('pets', 'price');
1227
+ * group('price', 'min').as('minPrice');
1228
+ * group('price', 'max').as('maxPrice');
1229
+ * having('minPrice', 3);
1230
+ * });
1231
+ *
1232
+ * queries.forEachResultRow('query', (rowId) => {
1233
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
1234
+ * });
1235
+ * // -> {1: {species: 'cat', minPrice: 3, maxPrice: 4}}
1236
+ * // -> {2: {species: 'parrot', minPrice: 3, maxPrice: 3}}
1237
+ * ```
1238
+ * @example
1239
+ * This example shows a query that filters the results from a grouped Table with
1240
+ * a condition that is calculated from Cell values.
1241
+ *
1242
+ * ```js
1243
+ * const store = createStore().setTable('pets', {
1244
+ * fido: {species: 'dog', price: 5},
1245
+ * felix: {species: 'cat', price: 4},
1246
+ * cujo: {species: 'dog', price: 4},
1247
+ * tom: {species: 'cat', price: 3},
1248
+ * carnaby: {species: 'parrot', price: 3},
1249
+ * polly: {species: 'parrot', price: 3},
1250
+ * });
1251
+ *
1252
+ * const queries = createQueries(store);
1253
+ * queries.setQueryDefinition('query', 'pets', ({select, group, having}) => {
1254
+ * select('pets', 'species');
1255
+ * select('pets', 'price');
1256
+ * group('price', 'min').as('minPrice');
1257
+ * group('price', 'max').as('maxPrice');
1258
+ * having(
1259
+ * (getSelectedOrGroupedCell) =>
1260
+ * getSelectedOrGroupedCell('minPrice') !=
1261
+ * getSelectedOrGroupedCell('maxPrice'),
1262
+ * );
1263
+ * });
1264
+ *
1265
+ * queries.forEachResultRow('query', (rowId) => {
1266
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
1267
+ * });
1268
+ * // -> {0: {species: 'dog', minPrice: 4, maxPrice: 5}}
1269
+ * // -> {1: {species: 'cat', minPrice: 3, maxPrice: 4}}
1270
+ * // Parrots are filtered out because they have zero range in price.
1271
+ * ```
1272
+ * @category Definition
1273
+ * @since v2.0.0-beta
1274
+ */
1275
+ export type Having = {
1276
+ /**
1277
+ * Calling this function with two parameters is used to include only those
1278
+ * Rows for which a specified Cell in the query's main Table has a specified
1279
+ * value.
1280
+ *
1281
+ * @param selectedOrGroupedCellId The Id of the Cell in the query to test.
1282
+ * @param equals The value that the Cell has to have for the Row to be
1283
+ * included in the result.
1284
+ */
1285
+ (selectedOrGroupedCellId: Id, equals: Cell): void;
1286
+ /**
1287
+ * Calling this function with one callback parameter is used to include only
1288
+ * those Rows which meet a calculated boolean condition.
1289
+ *
1290
+ * @param condition A callback that takes a GetCell function and that should
1291
+ * return `true` for the Row to be included in the result.
1292
+ */
1293
+ (condition: (getSelectedOrGroupedCell: GetCell) => boolean): void;
1294
+ };
1295
+
1296
+ /**
1297
+ * The Order type describes a function that lets you specify how you want the
1298
+ * Rows in the result Table to be ordered, based on values within.
1299
+ *
1300
+ * The Order function is provided as an parameter in the `build` parameter of
1301
+ * the setQueryDefinition method.
1302
+ *
1303
+ * An Order clause can either order alphanumerically by the value of a single
1304
+ * Cell or by a 'sort key' calculated from Cell values. The alphanumeric sorting
1305
+ * will be ascending by default, or descending if the second parameter is set to
1306
+ * `true`.
1307
+ *
1308
+ * This is applied after any grouping.
1309
+ *
1310
+ * It is possible to provide multiple Order clauses, and a later clause will be
1311
+ * used to establish the order of pairs of Rows if the earlier clauses have not
1312
+ * been able to.
1313
+ *
1314
+ * Note that the Order clause does not work by changing the Row Ids of the
1315
+ * result Table, but by changing their insert order. Therefore the Ids array
1316
+ * returned from the getResultRowIds method will be correctly ordered, even if
1317
+ * the Ids themselves might seem out of order based on their values. If you _do_
1318
+ * want to sort Rows by their Id, that is provided as a second parameter to the
1319
+ * getSortKey callback.
1320
+ *
1321
+ * Importantly, if you are using the addResultRowIdsListener method to listen to
1322
+ * changes to the order of Rows due to this clause, you will need to set the
1323
+ * optional `trackReorder` parameter to `true` to track when the set of Ids has
1324
+ * not changed, but the order has.
1325
+ *
1326
+ * trackReorder
1327
+ *
1328
+ * @example
1329
+ * This example shows a query that orders a Table by a numeric Cell, in a
1330
+ * descending fashion.
1331
+ *
1332
+ * ```js
1333
+ * const store = createStore().setTable('pets', {
1334
+ * cujo: {price: 4},
1335
+ * fido: {price: 5},
1336
+ * tom: {price: 3},
1337
+ * carnaby: {price: 3},
1338
+ * felix: {price: 4},
1339
+ * polly: {price: 3},
1340
+ * });
1341
+ *
1342
+ * const queries = createQueries(store);
1343
+ * queries.setQueryDefinition('query', 'pets', ({select, order}) => {
1344
+ * select('pets', 'price');
1345
+ * order('price', true);
1346
+ * });
1347
+ *
1348
+ * queries.forEachResultRow('query', (rowId) => {
1349
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
1350
+ * });
1351
+ * // -> {fido: {price: 5}}
1352
+ * // -> {cujo: {price: 4}}
1353
+ * // -> {felix: {price: 4}}
1354
+ * // -> {tom: {price: 3}}
1355
+ * // -> {carnaby: {price: 3}}
1356
+ * // -> {polly: {price: 3}}
1357
+ * ```
1358
+ * @example
1359
+ * This example shows a query that orders a Table by a string Cell, and then a
1360
+ * calculated sort key based on the Row Id.
1361
+ *
1362
+ * ```js
1363
+ * const store = createStore().setTable('pets', {
1364
+ * cujo: {species: 'dog'},
1365
+ * fido: {species: 'dog'},
1366
+ * tom: {species: 'cat'},
1367
+ * carnaby: {species: 'parrot'},
1368
+ * felix: {species: 'cat'},
1369
+ * polly: {species: 'parrot'},
1370
+ * });
1371
+ *
1372
+ * const queries = createQueries(store);
1373
+ * queries.setQueryDefinition('query', 'pets', ({select, order}) => {
1374
+ * select('pets', 'species');
1375
+ * order('species');
1376
+ * order((getSelectedOrGroupedCell, rowId) => rowId);
1377
+ * });
1378
+ *
1379
+ * queries.forEachResultRow('query', (rowId) => {
1380
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
1381
+ * });
1382
+ * // -> {felix: {species: 'cat'}}
1383
+ * // -> {tom: {species: 'cat'}}
1384
+ * // -> {cujo: {species: 'dog'}}
1385
+ * // -> {fido: {species: 'dog'}}
1386
+ * // -> {carnaby: {species: 'parrot'}}
1387
+ * // -> {polly: {species: 'parrot'}}
1388
+ * ```
1389
+ * @category Definition
1390
+ * @since v2.0.0-beta
1391
+ */
1392
+ export type Order = {
1393
+ /**
1394
+ * Calling this function with the first parameter as an Id is used to sort the
1395
+ * Rows by the value in that Cell.
1396
+ *
1397
+ * @param selectedOrGroupedCellId The Id of the Cell in the query to sort by.
1398
+ * @param descending Set to `true` to have the Rows sorted in descending
1399
+ * order.
1400
+ */
1401
+ (selectedOrGroupedCellId: Id, descending?: boolean): void;
1402
+ /**
1403
+ * Calling this function with the first parameter as a function is used to
1404
+ * sort the Rows by a value calculate from their Cells or Id.
1405
+ *
1406
+ * @param getSortKey A callback that takes a GetCell function and that should
1407
+ * return a 'sort key' to be used for ordering the Rows.
1408
+ * @param descending Set to `true` to have the Rows sorted in descending
1409
+ * order.
1410
+ */
1411
+ (
1412
+ getSortKey: (getSelectedOrGroupedCell: GetCell, rowId: Id) => SortKey,
1413
+ descending?: boolean,
1414
+ ): void;
1415
+ };
1416
+
1417
+ /**
1418
+ * The Limit type describes a function that lets you specify how many Rows you
1419
+ * want in the result Table, and how they should be offset.
1420
+ *
1421
+ * The Limit function is provided as an parameter in the `build` parameter of
1422
+ * the setQueryDefinition method.
1423
+ *
1424
+ * A Limit clause can either provide an 'page' offset and size limit, or just
1425
+ * the limit. The offset is zero-based, so if you specify `2`, say, the results
1426
+ * will skip the first two Rows and start with the third.
1427
+ *
1428
+ * This is applied after any grouping and sorting.
1429
+ *
1430
+ * @example
1431
+ * This example shows a query that limits a Table to four Rows from its first.
1432
+ *
1433
+ * ```js
1434
+ * const store = createStore().setTable('pets', {
1435
+ * cujo: {price: 4},
1436
+ * fido: {price: 5},
1437
+ * tom: {price: 3},
1438
+ * carnaby: {price: 3},
1439
+ * felix: {price: 4},
1440
+ * polly: {price: 3},
1441
+ * });
1442
+ *
1443
+ * const queries = createQueries(store);
1444
+ * queries.setQueryDefinition('query', 'pets', ({select, limit}) => {
1445
+ * select('pets', 'price');
1446
+ * limit(4);
1447
+ * });
1448
+ *
1449
+ * queries.forEachResultRow('query', (rowId) => {
1450
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
1451
+ * });
1452
+ * // -> {cujo: {price: 4}}
1453
+ * // -> {fido: {price: 5}}
1454
+ * // -> {tom: {price: 3}}
1455
+ * // -> {carnaby: {price: 3}}
1456
+ * ```
1457
+ * @example
1458
+ * This example shows a query that limits a Table to three Rows, offset by two.
1459
+ *
1460
+ * ```js
1461
+ * const store = createStore().setTable('pets', {
1462
+ * cujo: {price: 4},
1463
+ * fido: {price: 5},
1464
+ * tom: {price: 3},
1465
+ * carnaby: {price: 3},
1466
+ * felix: {price: 4},
1467
+ * polly: {price: 3},
1468
+ * });
1469
+ *
1470
+ * const queries = createQueries(store);
1471
+ * queries.setQueryDefinition('query', 'pets', ({select, limit}) => {
1472
+ * select('pets', 'price');
1473
+ * limit(2, 3);
1474
+ * });
1475
+ *
1476
+ * queries.forEachResultRow('query', (rowId) => {
1477
+ * console.log({[rowId]: queries.getResultRow('query', rowId)});
1478
+ * });
1479
+ * // -> {tom: {price: 3}}
1480
+ * // -> {carnaby: {price: 3}}
1481
+ * // -> {felix: {price: 4}}
1482
+ * ```
1483
+ * @category Definition
1484
+ * @since v2.0.0-beta
1485
+ */
1486
+ export type Limit = {
1487
+ /**
1488
+ * Calling this function with one numeric parameter is used to limit the Rows
1489
+ * returned, starting from the first.
1490
+ *
1491
+ * @param limit The number of Rows to return.
1492
+ */
1493
+ (limit: number): void;
1494
+ /**
1495
+ * Calling this function with two numeric parameters is used to offset the
1496
+ * start of the results, and then limit the Rows returned.
1497
+ *
1498
+ * @param offset The number of Rows to skip.
1499
+ * @param limit The number of Rows to return.
1500
+ */
1501
+ (offset: number, limit: number): void;
1502
+ };
1503
+
1504
+ /**
1505
+ * A Queries object lets you create and track queries of the data in Store
1506
+ * objects.
1507
+ *
1508
+ * This is useful for creating a reactive view of data that is stored in
1509
+ * physical tables: selecting columns, joining tables together, filtering rows,
1510
+ * aggregating data, sorting it, and so on.
1511
+ *
1512
+ * This provides a generalized query concept for Store data. If you just want to
1513
+ * create and track metrics, indexes, or relationships between rows, you may
1514
+ * prefer to use the dedicated Metrics, Indexes, and Relationships objects,
1515
+ * which have simpler APIs.
1516
+ *
1517
+ * Create a Queries object easily with the createQueries function. From there,
1518
+ * you can add new query definitions (with the setQueryDefinition method), query
1519
+ * the results (with the getResultTable method, the getResultRow method, the
1520
+ * getResultCell method, and so on), and add listeners for when they change
1521
+ * (with the addResultTableListener method, the addResultRowListener method, the
1522
+ * addResultCellListener method, and so on).
1523
+ *
1524
+ * @example
1525
+ * This example shows a very simple lifecycle of a Queries object: from
1526
+ * creation, to adding definitions, getting their contents, and then registering
1527
+ * and removing listeners for them.
1528
+ *
1529
+ * ```js
1530
+ * const store = createStore()
1531
+ * .setTable('pets', {
1532
+ * fido: {species: 'dog', color: 'brown', ownerId: '1'},
1533
+ * felix: {species: 'cat', color: 'black', ownerId: '2'},
1534
+ * cujo: {species: 'dog', color: 'black', ownerId: '3'},
1535
+ * })
1536
+ * .setTable('species', {
1537
+ * dog: {price: 5},
1538
+ * cat: {price: 4},
1539
+ * worm: {price: 1},
1540
+ * })
1541
+ * .setTable('owners', {
1542
+ * '1': {name: 'Alice'},
1543
+ * '2': {name: 'Bob'},
1544
+ * '3': {name: 'Carol'},
1545
+ * });
1546
+ *
1547
+ * const queries = createQueries(store);
1548
+ *
1549
+ * // A filtered table query:
1550
+ * queries.setQueryDefinition('blackPets', 'pets', ({select, where}) => {
1551
+ * select('species');
1552
+ * where('color', 'black');
1553
+ * });
1554
+ * console.log(queries.getResultTable('blackPets'));
1555
+ * // -> {felix: {species: 'cat'}, cujo: {species: 'dog'}}
1556
+ *
1557
+ * // A joined table query:
1558
+ * queries.setQueryDefinition('petOwners', 'pets', ({select, join}) => {
1559
+ * select('owners', 'name').as('owner');
1560
+ * join('owners', 'ownerId');
1561
+ * });
1562
+ * console.log(queries.getResultTable('petOwners'));
1563
+ * // -> {fido: {owner: 'Alice'}, felix: {owner: 'Bob'}, cujo: {owner: 'Carol'}}
1564
+ *
1565
+ * // A grouped and ordered query:
1566
+ * queries.setQueryDefinition(
1567
+ * 'colorPrice',
1568
+ * 'pets',
1569
+ * ({select, join, group, order}) => {
1570
+ * select('color');
1571
+ * select('species', 'price');
1572
+ * join('species', 'species');
1573
+ * group('price', 'avg');
1574
+ * order('price');
1575
+ * },
1576
+ * );
1577
+ * console.log(queries.getResultTable('colorPrice'));
1578
+ * // -> {"1": {color: 'black', price: 4.5}, "0": {color: 'brown', price: 5}}
1579
+ * console.log(queries.getResultRowIds('colorPrice'));
1580
+ * // -> ["1", "0"]
1581
+ *
1582
+ * const listenerId = queries.addResultTableListener('colorPrice', () => {
1583
+ * console.log('Average prices per color changed');
1584
+ * console.log(queries.getResultTable('colorPrice'));
1585
+ * console.log(queries.getResultRowIds('colorPrice'));
1586
+ * });
1587
+ *
1588
+ * store.setRow('pets', 'lowly', {species: 'worm', color: 'brown'});
1589
+ * // -> 'Average prices per color changed'
1590
+ * // -> {"0": {color: 'brown', price: 3}, "1": {color: 'black', price: 4.5}}
1591
+ * // -> ["0", "1"]
1592
+ *
1593
+ * queries.delListener(listenerId);
1594
+ * queries.destroy();
1595
+ * ```
1596
+ * @see Queries guides
1597
+ * @category Queries
1598
+ * @since v2.0.0-beta
1599
+ */
1600
+ export interface Queries {
1601
+ /**
1602
+ * The setQueryDefinition method lets you set the definition of a query.
1603
+ *
1604
+ * Every query definition is identified by a unique Id, and if you re-use an
1605
+ * existing Id with this method, the previous definition is overwritten.
1606
+ *
1607
+ * A query provides a tabular result formed from each Row within a main Table.
1608
+ * The definition must specify this 'main' Table (by its Id) to be aggregated.
1609
+ * Other Tables can be joined to that using Join clauses.
1610
+ *
1611
+ * The third `build` parameter is a callback that you provide to define the
1612
+ * query. That callback is provided with a `builders` object that contains the
1613
+ * named 'keywords' for the query, like `select`, `join`, and so on. You can
1614
+ * see how that is used in the simple example below. The following seven
1615
+ * clause types are supported:
1616
+ *
1617
+ * - The Select type describes a function that lets you specify a Cell or
1618
+ * calculated value for including into the query's result.
1619
+ * - The Join type describes a function that lets you specify a Cell or
1620
+ * calculated value to join the main query Table to others, by Row Id.
1621
+ * - The Where type describes a function that lets you specify conditions to
1622
+ * filter results, based on the underlying Cells of the main or joined
1623
+ * Tables.
1624
+ * - The Group type describes a function that lets you specify that the values
1625
+ * of a Cell in multiple result Rows should be aggregated together.
1626
+ * - The Having type describes a function that lets you specify conditions to
1627
+ * filter results, based on the grouped Cells resulting from a Group clause.
1628
+ * - The Order type describes a function that lets you specify how you want
1629
+ * the Rows in the result Table to be ordered, based on values within.
1630
+ * - The Limit type describes a function that lets you specify how many Rows
1631
+ * you want in the result Table, and how they should be offset.
1632
+ *
1633
+ * Full documentation and examples are provided in the sections for each of
1634
+ * those clause types.
1635
+ *
1636
+ * @param queryId The Id of the query to define.
1637
+ * @param tableId The Id of the main Table the query will be based on.
1638
+ * @param build A callback which can take a `builders` object and which uses
1639
+ the clause functions it contains to define the query.
1640
+ * @returns A reference to the Queries object.
1641
+ * @example
1642
+ * This example creates a Store, creates a Queries object, and defines a
1643
+ * simple query to select just one column from the Table, for each Row where
1644
+ * the `species` Cell matches as certain value.
1645
+ *
1646
+ * ```js
1647
+ * const store = createStore().setTable('pets', {
1648
+ * fido: {species: 'dog', color: 'brown'},
1649
+ * felix: {species: 'cat', color: 'black'},
1650
+ * cujo: {species: 'dog', color: 'black'},
1651
+ * });
1652
+ *
1653
+ * const queries = createQueries(store);
1654
+ * queries.setQueryDefinition('dogColors', 'pets', ({select, where}) => {
1655
+ * select('color');
1656
+ * where('species', 'dog');
1657
+ * });
1658
+ *
1659
+ * console.log(queries.getResultTable('dogColors'));
1660
+ * // -> {fido: {color: 'brown'}, cujo: {color: 'black'}}
1661
+ * ```
1662
+ * @category Configuration
1663
+ * @since v2.0.0-beta
1664
+ */
1665
+ setQueryDefinition(
1666
+ queryId: Id,
1667
+ tableId: Id,
1668
+ build: (builders: {
1669
+ select: Select;
1670
+ join: Join;
1671
+ where: Where;
1672
+ group: Group;
1673
+ having: Having;
1674
+ order: Order;
1675
+ limit: Limit;
1676
+ }) => void,
1677
+ ): Queries;
1678
+
1679
+ /**
1680
+ * The delQueryDefinition method removes an existing query definition.
1681
+ *
1682
+ * @param queryId The Id of the query to remove.
1683
+ * @returns A reference to the Queries object.
1684
+ * @example
1685
+ * This example creates a Store, creates a Queries object, defines a simple
1686
+ * query, and then removes it.
1687
+ *
1688
+ * ```js
1689
+ * const store = createStore().setTable('pets', {
1690
+ * fido: {species: 'dog', color: 'brown'},
1691
+ * felix: {species: 'cat', color: 'black'},
1692
+ * cujo: {species: 'dog', color: 'black'},
1693
+ * });
1694
+ *
1695
+ * const queries = createQueries(store);
1696
+ * queries.setQueryDefinition('dogColors', 'pets', ({select, where}) => {
1697
+ * select('color');
1698
+ * where('species', 'dog');
1699
+ * });
1700
+ * console.log(queries.getQueryIds());
1701
+ * // -> ['dogColors']
1702
+ *
1703
+ * queries.delQueryDefinition('dogColors');
1704
+ * console.log(queries.getQueryIds());
1705
+ * // -> []
1706
+ * ```
1707
+ * @category Configuration
1708
+ * @since v2.0.0-beta
1709
+ */
1710
+ delQueryDefinition(queryId: Id): Queries;
1711
+
1712
+ /**
1713
+ * The getStore method returns a reference to the underlying Store that is
1714
+ * backing this Queries object.
1715
+ *
1716
+ * @returns A reference to the Store.
1717
+ * @example
1718
+ * This example creates a Queries object against a newly-created Store and
1719
+ * then gets its reference in order to update its data.
1720
+ *
1721
+ * ```js
1722
+ * const queries = createQueries(createStore());
1723
+ * queries.setQueryDefinition('dogColors', 'pets', ({select, where}) => {
1724
+ * select('color');
1725
+ * where('species', 'dog');
1726
+ * });
1727
+ * queries
1728
+ * .getStore()
1729
+ * .setRow('pets', 'fido', {species: 'dog', color: 'brown'});
1730
+ * console.log(queries.getResultTable('dogColors'));
1731
+ * // -> {fido: {color: 'brown'}}
1732
+ * ```
1733
+ * @category Getter
1734
+ * @since v2.0.0-beta
1735
+ */
1736
+ getStore(): Store;
1737
+
1738
+ /**
1739
+ * The getQueryIds method returns an array of the query Ids registered with
1740
+ * this Queries object.
1741
+ *
1742
+ * @returns An array of Ids.
1743
+ * @example
1744
+ * This example creates a Queries object with two definitions, and then gets
1745
+ * the Ids of the definitions.
1746
+ *
1747
+ * ```js
1748
+ * const queries = createQueries(createStore())
1749
+ * .setQueryDefinition('dogColors', 'pets', ({select, where}) => {
1750
+ * select('color');
1751
+ * where('species', 'dog');
1752
+ * })
1753
+ * .setQueryDefinition('catColors', 'pets', ({select, where}) => {
1754
+ * select('color');
1755
+ * where('species', 'cat');
1756
+ * });
1757
+ *
1758
+ * console.log(queries.getQueryIds());
1759
+ * // -> ['dogColors', 'catColors']
1760
+ * ```
1761
+ * @category Getter
1762
+ * @since v2.0.0-beta
1763
+ */
1764
+ getQueryIds(): Ids;
1765
+
1766
+ /**
1767
+ * The forEachQuery method takes a function that it will then call for each
1768
+ * Query in the Queries object.
1769
+ *
1770
+ * This method is useful for iterating over all the queries in a functional
1771
+ * style. The `queryCallback` parameter is a QueryCallback function that will
1772
+ * be called with the Id of each query.
1773
+ *
1774
+ * @param queryCallback The function that should be called for every query.
1775
+ * @example
1776
+ * This example iterates over each query in a Queries object.
1777
+ *
1778
+ * ```js
1779
+ * const queries = createQueries(createStore())
1780
+ * .setQueryDefinition('dogColors', 'pets', ({select, where}) => {
1781
+ * select('color');
1782
+ * where('species', 'dog');
1783
+ * })
1784
+ * .setQueryDefinition('catColors', 'pets', ({select, where}) => {
1785
+ * select('color');
1786
+ * where('species', 'cat');
1787
+ * });
1788
+ *
1789
+ * queries.forEachQuery((queryId) => {
1790
+ * console.log(queryId);
1791
+ * });
1792
+ * // -> 'dogColors'
1793
+ * // -> 'catColors'
1794
+ * ```
1795
+ * @category Iterator
1796
+ * @since v2.0.0-beta
1797
+ */
1798
+ forEachQuery(queryCallback: QueryCallback): void;
1799
+
1800
+ /**
1801
+ * The hasQuery method returns a boolean indicating whether a given query
1802
+ * exists in the Queries object.
1803
+ *
1804
+ * @param queryId The Id of a possible query in the Queries object.
1805
+ * @returns Whether a query with that Id exists.
1806
+ * @example
1807
+ * This example shows two simple query existence checks.
1808
+ *
1809
+ * ```js
1810
+ * const queries = createQueries(createStore()).setQueryDefinition(
1811
+ * 'dogColors',
1812
+ * 'pets',
1813
+ * ({select, where}) => {
1814
+ * select('color');
1815
+ * where('species', 'dog');
1816
+ * },
1817
+ * );
1818
+ *
1819
+ * console.log(queries.hasQuery('dogColors'));
1820
+ * // -> true
1821
+ * console.log(queries.hasQuery('catColors'));
1822
+ * // -> false
1823
+ * ```
1824
+ * @category Getter
1825
+ * @since v2.0.0-beta
1826
+ */
1827
+ hasQuery(queryId: Id): boolean;
1828
+
1829
+ /**
1830
+ * The getTableId method returns the Id of the underlying Table that is
1831
+ * backing a query.
1832
+ *
1833
+ * If the query Id is invalid, the method returns `undefined`.
1834
+ *
1835
+ * @param queryId The Id of a query.
1836
+ * @returns The Id of the Table backing the query, or `undefined`.
1837
+ * @example
1838
+ * This example creates a Queries object, a single query definition, and then
1839
+ * calls this method on it (as well as a non-existent definition) to get the
1840
+ * underlying Table Id.
1841
+ *
1842
+ * ```js
1843
+ * const queries = createQueries(createStore()).setQueryDefinition(
1844
+ * 'dogColors',
1845
+ * 'pets',
1846
+ * ({select, where}) => {
1847
+ * select('color');
1848
+ * where('species', 'dog');
1849
+ * },
1850
+ * );
1851
+ *
1852
+ * console.log(queries.getTableId('dogColors'));
1853
+ * // -> 'pets'
1854
+ * console.log(queries.getTableId('catColors'));
1855
+ * // -> undefined
1856
+ * ```
1857
+ * @category Getter
1858
+ * @since v2.0.0-beta
1859
+ */
1860
+ getTableId(queryId: Id): Id | undefined;
1861
+
1862
+ /**
1863
+ * The getResultTable method returns an object containing the entire data of
1864
+ * the result Table of the given query.
1865
+ *
1866
+ * This has the same behavior as a Store's getTable method. For example, if
1867
+ * the query Id is invalid, the method returns an empty object. Similarly, it
1868
+ * returns a copy of, rather than a reference to the underlying data, so
1869
+ * changes made to the returned object are not made to the query results
1870
+ * themselves.
1871
+ *
1872
+ * @param queryId The Id of a query.
1873
+ * @returns An object containing the entire data of the result Table of the
1874
+ * query.
1875
+ * @returns The result of the query, structured as a Table.
1876
+ * @example
1877
+ * This example creates a Queries object, a single query definition, and then
1878
+ * calls this method on it (as well as a non-existent definition) to get the
1879
+ * result Table.
1880
+ *
1881
+ * ```js
1882
+ * const store = createStore().setTable('pets', {
1883
+ * fido: {species: 'dog', color: 'brown'},
1884
+ * felix: {species: 'cat', color: 'black'},
1885
+ * cujo: {species: 'dog', color: 'black'},
1886
+ * });
1887
+ *
1888
+ * const queries = createQueries(store).setQueryDefinition(
1889
+ * 'dogColors',
1890
+ * 'pets',
1891
+ * ({select, where}) => {
1892
+ * select('color');
1893
+ * where('species', 'dog');
1894
+ * },
1895
+ * );
1896
+ *
1897
+ * console.log(queries.getResultTable('dogColors'));
1898
+ * // -> {fido: {color: 'brown'}, cujo: {color: 'black'}}
1899
+ *
1900
+ * console.log(queries.getResultTable('catColors'));
1901
+ * // -> {}
1902
+ * ```
1903
+ * @category Result
1904
+ * @since v2.0.0-beta
1905
+ */
1906
+ getResultTable(queryId: Id): Table;
1907
+
1908
+ /**
1909
+ * The getResultRowIds method returns the Ids of every Row in the result Table
1910
+ * of the given query.
1911
+ *
1912
+ * This has the same behavior as a Store's getRowIds method. For example, if
1913
+ * the query Id is invalid, the method returns an empty array. Similarly, it
1914
+ * returns a copy of, rather than a reference to the list of Ids, so changes
1915
+ * made to the list object are not made to the query results themselves.
1916
+ *
1917
+ * An Order clause in the query explicitly affects the order of entries in
1918
+ * this array.
1919
+ *
1920
+ * @param queryId The Id of a query.
1921
+ * @returns An array of the Ids of every Row in the result of the query.
1922
+ * @example
1923
+ * This example creates a Queries object, a single query definition, and then
1924
+ * calls this method on it (as well as a non-existent definition) to get the
1925
+ * result Row Ids.
1926
+ *
1927
+ * ```js
1928
+ * const store = createStore().setTable('pets', {
1929
+ * fido: {species: 'dog', color: 'brown'},
1930
+ * felix: {species: 'cat', color: 'black'},
1931
+ * cujo: {species: 'dog', color: 'black'},
1932
+ * });
1933
+ *
1934
+ * const queries = createQueries(store).setQueryDefinition(
1935
+ * 'dogColors',
1936
+ * 'pets',
1937
+ * ({select, where}) => {
1938
+ * select('color');
1939
+ * where('species', 'dog');
1940
+ * },
1941
+ * );
1942
+ *
1943
+ * console.log(queries.getResultRowIds('dogColors'));
1944
+ * // -> ['fido', 'cujo']
1945
+ *
1946
+ * console.log(queries.getResultRowIds('catColors'));
1947
+ * // -> []
1948
+ * ```
1949
+ * @category Result
1950
+ * @since v2.0.0-beta
1951
+ */
1952
+ getResultRowIds(queryId: Id): Ids;
1953
+
1954
+ /**
1955
+ * The getResultRow method returns an object containing the entire data of a
1956
+ * single Row in the result Table of the given query.
1957
+ *
1958
+ * This has the same behavior as a Store's getRow method. For example, if the
1959
+ * query or Row Id is invalid, the method returns an empty object. Similarly,
1960
+ * it returns a copy of, rather than a reference to the underlying data, so
1961
+ * changes made to the returned object are not made to the query results
1962
+ * themselves.
1963
+ *
1964
+ * @param queryId The Id of a query.
1965
+ * @param rowId The Id of the Row in the result Table.
1966
+ * @returns An object containing the entire data of the Row in the result
1967
+ * Table of the query.
1968
+ * @example
1969
+ * This example creates a Queries object, a single query definition, and then
1970
+ * calls this method on it (as well as a non-existent Row Id) to get the
1971
+ * result Row.
1972
+ *
1973
+ * ```js
1974
+ * const store = createStore().setTable('pets', {
1975
+ * fido: {species: 'dog', color: 'brown'},
1976
+ * felix: {species: 'cat', color: 'black'},
1977
+ * cujo: {species: 'dog', color: 'black'},
1978
+ * });
1979
+ *
1980
+ * const queries = createQueries(store).setQueryDefinition(
1981
+ * 'dogColors',
1982
+ * 'pets',
1983
+ * ({select, where}) => {
1984
+ * select('color');
1985
+ * where('species', 'dog');
1986
+ * },
1987
+ * );
1988
+ *
1989
+ * console.log(queries.getResultRow('dogColors', 'fido'));
1990
+ * // -> {color: 'brown'}
1991
+ *
1992
+ * console.log(queries.getResultRow('dogColors', 'felix'));
1993
+ * // -> {}
1994
+ * ```
1995
+ * @category Result
1996
+ * @since v2.0.0-beta
1997
+ */
1998
+ getResultRow(queryId: Id, rowId: Id): Row;
1999
+
2000
+ /**
2001
+ * The getResultCellIds method returns the Ids of every Cell in a given Row,
2002
+ * in the result Table of the given query.
2003
+ *
2004
+ * This has the same behavior as a Store's getCellIds method. For example, if
2005
+ * the query Id or Row Id is invalid, the method returns an empty array.
2006
+ * Similarly, it returns a copy of, rather than a reference to the list of
2007
+ * Ids, so changes made to the list object are not made to the query results
2008
+ * themselves.
2009
+ *
2010
+ * @param queryId The Id of a query.
2011
+ * @param rowId The Id of the Row in the result Table.
2012
+ * @returns An array of the Ids of every Cell in the Row in the result of the
2013
+ * query.
2014
+ * @example
2015
+ * This example creates a Queries object, a single query definition, and then
2016
+ * calls this method on it (as well as a non-existent Row Id) to get the
2017
+ * result Cell Ids.
2018
+ *
2019
+ * ```js
2020
+ * const store = createStore().setTable('pets', {
2021
+ * fido: {species: 'dog', color: 'brown'},
2022
+ * felix: {species: 'cat', color: 'black'},
2023
+ * cujo: {species: 'dog', color: 'black'},
2024
+ * });
2025
+ *
2026
+ * const queries = createQueries(store).setQueryDefinition(
2027
+ * 'dogColors',
2028
+ * 'pets',
2029
+ * ({select, where}) => {
2030
+ * select('color');
2031
+ * where('species', 'dog');
2032
+ * },
2033
+ * );
2034
+ *
2035
+ * console.log(queries.getResultCellIds('dogColors', 'fido'));
2036
+ * // -> ['color']
2037
+ *
2038
+ * console.log(queries.getResultCellIds('dogColors', 'felix'));
2039
+ * // -> []
2040
+ * ```
2041
+ * @category Result
2042
+ * @since v2.0.0-beta
2043
+ */
2044
+ getResultCellIds(queryId: Id, rowId: Id): Ids;
2045
+
2046
+ /**
2047
+ * The getResultCell method returns the value of a single Cell in a given Row,
2048
+ * in the result Table of the given query.
2049
+ *
2050
+ * This has the same behavior as a Store's getCell method. For example, if the
2051
+ * query, or Row, or Cell Id is invalid, the method returns `undefined`.
2052
+ *
2053
+ * @param queryId The Id of a query.
2054
+ * @param rowId The Id of the Row in the result Table.
2055
+ * @param cellId The Id of the Cell in the Row.
2056
+ * @returns The value of the Cell, or `undefined`.
2057
+ * @example
2058
+ * This example creates a Queries object, a single query definition, and then
2059
+ * calls this method on it (as well as a non-existent Cell Id) to get the
2060
+ * result Cell.
2061
+ *
2062
+ * ```js
2063
+ * const store = createStore().setTable('pets', {
2064
+ * fido: {species: 'dog', color: 'brown'},
2065
+ * felix: {species: 'cat', color: 'black'},
2066
+ * cujo: {species: 'dog', color: 'black'},
2067
+ * });
2068
+ *
2069
+ * const queries = createQueries(store).setQueryDefinition(
2070
+ * 'dogColors',
2071
+ * 'pets',
2072
+ * ({select, where}) => {
2073
+ * select('color');
2074
+ * where('species', 'dog');
2075
+ * },
2076
+ * );
2077
+ *
2078
+ * console.log(queries.getResultCell('dogColors', 'fido', 'color'));
2079
+ * // -> 'brown'
2080
+ *
2081
+ * console.log(queries.getResultCell('dogColors', 'fido', 'species'));
2082
+ * // -> undefined
2083
+ * ```
2084
+ * @category Result
2085
+ * @since v2.0.0-beta
2086
+ */
2087
+ getResultCell(queryId: Id, rowId: Id, cellId: Id): CellOrUndefined;
2088
+
2089
+ /**
2090
+ * The hasResultTable method returns a boolean indicating whether a given
2091
+ * result Table exists.
2092
+ *
2093
+ * @param queryId The Id of a possible query.
2094
+ * @returns Whether a result Table for that query Id exists.
2095
+ * @example
2096
+ * This example shows two simple result Table existence checks.
2097
+ *
2098
+ * ```js
2099
+ * const store = createStore().setTable('pets', {
2100
+ * fido: {species: 'dog', color: 'brown'},
2101
+ * felix: {species: 'cat', color: 'black'},
2102
+ * cujo: {species: 'dog', color: 'black'},
2103
+ * });
2104
+ *
2105
+ * const queries = createQueries(store).setQueryDefinition(
2106
+ * 'dogColors',
2107
+ * 'pets',
2108
+ * ({select, where}) => {
2109
+ * select('color');
2110
+ * where('species', 'dog');
2111
+ * },
2112
+ * );
2113
+ *
2114
+ * console.log(queries.hasResultTable('dogColors'));
2115
+ * // -> true
2116
+ * console.log(queries.hasResultTable('catColors'));
2117
+ * // -> false
2118
+ * ```
2119
+ * @category Result
2120
+ * @since v2.0.0-beta
2121
+ */
2122
+ hasResultTable(queryId: Id): boolean;
2123
+
2124
+ /**
2125
+ * The hasResultRow method returns a boolean indicating whether a given
2126
+ * result Row exists.
2127
+ *
2128
+ * @param queryId The Id of a possible query.
2129
+ * @param rowId The Id of a possible Row.
2130
+ * @returns Whether a result Row for that Id exists.
2131
+ * @example
2132
+ * This example shows two simple result Row existence checks.
2133
+ *
2134
+ * ```js
2135
+ * const store = createStore().setTable('pets', {
2136
+ * fido: {species: 'dog', color: 'brown'},
2137
+ * felix: {species: 'cat', color: 'black'},
2138
+ * cujo: {species: 'dog', color: 'black'},
2139
+ * });
2140
+ *
2141
+ * const queries = createQueries(store).setQueryDefinition(
2142
+ * 'dogColors',
2143
+ * 'pets',
2144
+ * ({select, where}) => {
2145
+ * select('color');
2146
+ * where('species', 'dog');
2147
+ * },
2148
+ * );
2149
+ *
2150
+ * console.log(queries.hasResultRow('dogColors', 'fido'));
2151
+ * // -> true
2152
+ * console.log(queries.hasResultRow('dogColors', 'felix'));
2153
+ * // -> false
2154
+ * ```
2155
+ * @category Result
2156
+ * @since v2.0.0-beta
2157
+ */
2158
+ hasResultRow(queryId: Id, rowId: Id): boolean;
2159
+
2160
+ /**
2161
+ * The hasResultCell method returns a boolean indicating whether a given
2162
+ * result Cell exists.
2163
+ *
2164
+ * @param queryId The Id of a possible query.
2165
+ * @param rowId The Id of a possible Row.
2166
+ * @param cellId The Id of a possible Cell.
2167
+ * @returns Whether a result Cell for that Id exists.
2168
+ * @example
2169
+ * This example shows two simple result Row existence checks.
2170
+ *
2171
+ * ```js
2172
+ * const store = createStore().setTable('pets', {
2173
+ * fido: {species: 'dog', color: 'brown'},
2174
+ * felix: {species: 'cat', color: 'black'},
2175
+ * cujo: {species: 'dog', color: 'black'},
2176
+ * });
2177
+ *
2178
+ * const queries = createQueries(store).setQueryDefinition(
2179
+ * 'dogColors',
2180
+ * 'pets',
2181
+ * ({select, where}) => {
2182
+ * select('color');
2183
+ * where('species', 'dog');
2184
+ * },
2185
+ * );
2186
+ *
2187
+ * console.log(queries.hasResultCell('dogColors', 'fido', 'color'));
2188
+ * // -> true
2189
+ * console.log(queries.hasResultCell('dogColors', 'fido', 'species'));
2190
+ * // -> false
2191
+ * ```
2192
+ * @category Result
2193
+ * @since v2.0.0-beta
2194
+ */
2195
+ hasResultCell(queryId: Id, rowId: Id, cellId: Id): boolean;
2196
+
2197
+ /**
2198
+ * The forEachResultTable method takes a function that it will then call for
2199
+ * each result Table in the Queries object.
2200
+ *
2201
+ * This method is useful for iterating over all the result Tables of the
2202
+ * queries in a functional style. The `tableCallback` parameter is a
2203
+ * TableCallback function that will be called with the Id of each result
2204
+ * Table, and with a function that can then be used to iterate over each Row
2205
+ * of the result Table, should you wish.
2206
+ *
2207
+ * @param tableCallback The function that should be called for every query's
2208
+ * result Table.
2209
+ * @example
2210
+ * This example iterates over each query's result Table in a Queries object.
2211
+ *
2212
+ * ```js
2213
+ * const store = createStore().setTable('pets', {
2214
+ * fido: {species: 'dog', color: 'brown'},
2215
+ * felix: {species: 'cat', color: 'black'},
2216
+ * cujo: {species: 'dog', color: 'black'},
2217
+ * });
2218
+ *
2219
+ * const queries = createQueries(store)
2220
+ * .setQueryDefinition('dogColors', 'pets', ({select, where}) => {
2221
+ * select('color');
2222
+ * where('species', 'dog');
2223
+ * })
2224
+ * .setQueryDefinition('catColors', 'pets', ({select, where}) => {
2225
+ * select('color');
2226
+ * where('species', 'cat');
2227
+ * });
2228
+ *
2229
+ * queries.forEachResultTable((queryId, forEachRow) => {
2230
+ * console.log(queryId);
2231
+ * forEachRow((rowId) => console.log(`- ${rowId}`));
2232
+ * });
2233
+ * // -> 'dogColors'
2234
+ * // -> '- fido'
2235
+ * // -> '- cujo'
2236
+ * // -> 'catColors'
2237
+ * // -> '- felix'
2238
+ * ```
2239
+ * @category Iterator
2240
+ * @since v2.0.0-beta
2241
+ */
2242
+ forEachResultTable(tableCallback: TableCallback): void;
2243
+
2244
+ /**
2245
+ * The forEachResultRow method takes a function that it will then call for
2246
+ * each Row in the result Table of a query.
2247
+ *
2248
+ * This method is useful for iterating over each Row of the result Table of
2249
+ * the query in a functional style. The `rowCallback` parameter is a
2250
+ * RowCallback function that will be called with the Id of each result Row,
2251
+ * and with a function that can then be used to iterate over each Cell of the
2252
+ * result Row, should you wish.
2253
+ *
2254
+ * @param queryId The Id of a query.
2255
+ * @param rowCallback The function that should be called for every Row of the
2256
+ * query's result Table.
2257
+ * @example
2258
+ * This example iterates over each Row in a query's result Table.
2259
+ *
2260
+ * ```js
2261
+ * const store = createStore().setTable('pets', {
2262
+ * fido: {species: 'dog', color: 'brown'},
2263
+ * felix: {species: 'cat', color: 'black'},
2264
+ * cujo: {species: 'dog', color: 'black'},
2265
+ * });
2266
+ *
2267
+ * const queries = createQueries(store).setQueryDefinition(
2268
+ * 'dogColors',
2269
+ * 'pets',
2270
+ * ({select, where}) => {
2271
+ * select('color');
2272
+ * where('species', 'dog');
2273
+ * },
2274
+ * );
2275
+ *
2276
+ * queries.forEachResultRow('dogColors', (rowId, forEachCell) => {
2277
+ * console.log(rowId);
2278
+ * forEachCell((cellId) => console.log(`- ${cellId}`));
2279
+ * });
2280
+ * // -> 'fido'
2281
+ * // -> '- color'
2282
+ * // -> 'cujo'
2283
+ * // -> '- color'
2284
+ * ```
2285
+ * @category Iterator
2286
+ * @since v2.0.0-beta
2287
+ */
2288
+ forEachResultRow(queryId: Id, rowCallback: RowCallback): void;
2289
+
2290
+ /**
2291
+ * The forEachResultCell method takes a function that it will then call for
2292
+ * each Cell in the result Row of a query.
2293
+ *
2294
+ * This method is useful for iterating over each Cell of the result Row of the
2295
+ * query in a functional style. The `cellCallback` parameter is a CellCallback
2296
+ * function that will be called with the Id and value of each result Cell.
2297
+ *
2298
+ * @param queryId The Id of a query.
2299
+ * @param rowId The Id of a Row in the query's result Table.
2300
+ * @param cellCallback The function that should be called for every Cell of
2301
+ * the query's result Row.
2302
+ * @example
2303
+ * This example iterates over each Cell in a query's result Row.
2304
+ *
2305
+ * ```js
2306
+ * const store = createStore().setTable('pets', {
2307
+ * fido: {species: 'dog', color: 'brown'},
2308
+ * felix: {species: 'cat', color: 'black'},
2309
+ * cujo: {species: 'dog', color: 'black'},
2310
+ * });
2311
+ *
2312
+ * const queries = createQueries(store).setQueryDefinition(
2313
+ * 'dogColors',
2314
+ * 'pets',
2315
+ * ({select, where}) => {
2316
+ * select('species');
2317
+ * select('color');
2318
+ * where('species', 'dog');
2319
+ * },
2320
+ * );
2321
+ *
2322
+ * queries.forEachResultCell('dogColors', 'fido', (cellId, cell) => {
2323
+ * console.log(`${cellId}: ${cell}`);
2324
+ * });
2325
+ * // -> 'species: dog'
2326
+ * // -> 'color: brown'
2327
+ * ```
2328
+ * @category Iterator
2329
+ * @since v2.0.0-beta
2330
+ */
2331
+ forEachResultCell(queryId: Id, rowId: Id, cellCallback: CellCallback): void;
2332
+
2333
+ /**
2334
+ * The addResultTableListener method registers a listener function with the
2335
+ * Queries object that will be called whenever data in a result Table changes.
2336
+ *
2337
+ * The provided listener is a ResultTableListener function, and will be called
2338
+ * with a reference to the Queries object, the Id of the Table that changed
2339
+ * (which is also the query Id), and a GetCellChange function in case you need
2340
+ * to inspect any changes that occurred.
2341
+ *
2342
+ * You can either listen to a single result Table (by specifying a query Id as
2343
+ * the method's first parameter) or changes to any result Table (by providing
2344
+ * a `null` wildcard).
2345
+ *
2346
+ * @param queryId The Id of the query to listen to, or `null` as a wildcard.
2347
+ * @param listener The function that will be called whenever data in the
2348
+ * matching result Table changes.
2349
+ * @returns A unique Id for the listener that can later be used to remove it.
2350
+ * @example
2351
+ * This example registers a listener that responds to any changes to a
2352
+ * specific result Table.
2353
+ *
2354
+ * ```js
2355
+ * const store = createStore().setTable('pets', {
2356
+ * fido: {species: 'dog', color: 'brown'},
2357
+ * felix: {species: 'cat', color: 'black'},
2358
+ * cujo: {species: 'dog', color: 'black'},
2359
+ * });
2360
+ *
2361
+ * const queries = createQueries(store).setQueryDefinition(
2362
+ * 'dogColors',
2363
+ * 'pets',
2364
+ * ({select, where}) => {
2365
+ * select('color');
2366
+ * where('species', 'dog');
2367
+ * },
2368
+ * );
2369
+ *
2370
+ * const listenerId = queries.addResultTableListener(
2371
+ * 'dogColors',
2372
+ * (queries, tableId, getCellChange) => {
2373
+ * console.log('dogColors result table changed');
2374
+ * console.log(getCellChange('dogColors', 'fido', 'color'));
2375
+ * },
2376
+ * );
2377
+ *
2378
+ * store.setCell('pets', 'fido', 'color', 'walnut');
2379
+ * // -> 'dogColors result table changed'
2380
+ * // -> [true, 'brown', 'walnut']
2381
+ *
2382
+ * store.delListener(listenerId);
2383
+ * ```
2384
+ * @example
2385
+ * This example registers a listener that responds to any changes to any
2386
+ * result Table.
2387
+ *
2388
+ * ```js
2389
+ * const store = createStore().setTable('pets', {
2390
+ * fido: {species: 'dog', color: 'brown'},
2391
+ * felix: {species: 'cat', color: 'black'},
2392
+ * cujo: {species: 'dog', color: 'black'},
2393
+ * });
2394
+ *
2395
+ * const queries = createQueries(store)
2396
+ * .setQueryDefinition('dogColors', 'pets', ({select, where}) => {
2397
+ * select('color');
2398
+ * where('species', 'dog');
2399
+ * })
2400
+ * .setQueryDefinition('catColors', 'pets', ({select, where}) => {
2401
+ * select('color');
2402
+ * where('species', 'cat');
2403
+ * });
2404
+ *
2405
+ * const listenerId = queries.addResultTableListener(
2406
+ * null,
2407
+ * (queries, tableId) => {
2408
+ * console.log(`${tableId} result table changed`);
2409
+ * },
2410
+ * );
2411
+ *
2412
+ * store.setCell('pets', 'fido', 'color', 'walnut');
2413
+ * // -> 'dogColors result table changed'
2414
+ * store.setCell('pets', 'felix', 'color', 'tortoiseshell');
2415
+ * // -> 'catColors result table changed'
2416
+ *
2417
+ * store.delListener(listenerId);
2418
+ * ```
2419
+ * @category Listener
2420
+ */
2421
+ addResultTableListener(queryId: IdOrNull, listener: ResultTableListener): Id;
2422
+
2423
+ /**
2424
+ * The addResultRowIdsListener method registers a listener function with the
2425
+ * Queries object that will be called whenever the Row Ids in a result Table
2426
+ * change.
2427
+ *
2428
+ * The provided listener is a ResultRowIdsListener function, and will be
2429
+ * called with a reference to the Queries object and the Id of the Table that
2430
+ * changed (which is also the query Id).
2431
+ *
2432
+ * By default, such a listener is only called when a Row is added to, or
2433
+ * removed from, the result Table. To listen to all changes in the result
2434
+ * Table, use the addResultTableListener method.
2435
+ *
2436
+ * You can either listen to a single result Table (by specifying a query Id as
2437
+ * the method's first parameter) or changes to any result Table (by providing
2438
+ * a `null` wildcard).
2439
+ *
2440
+ * Use the optional `trackReorder` parameter to additionally track when the
2441
+ * set of Ids has not changed, but the order has - for example when the Order
2442
+ * clause of the query causes the Row Ids to be re-sorted. This behavior is
2443
+ * disabled by default due to the potential performance cost of detecting such
2444
+ * changes.
2445
+ *
2446
+ * @param queryId The Id of the query to listen to, or `null` as a wildcard.
2447
+ * @param listener The function that will be called whenever the Row Ids in
2448
+ * the result Table change.
2449
+ * @param trackReorder An optional boolean that indicates that the listener
2450
+ * should be called if the set of Ids remains the same but their order
2451
+ * changes.
2452
+ * @returns A unique Id for the listener that can later be used to remove it.
2453
+ * @example
2454
+ * This example registers a listener that responds to any change to the Row
2455
+ * Ids of a specific result Table, but not their order.
2456
+ *
2457
+ * ```js
2458
+ * const store = createStore().setTable('pets', {
2459
+ * fido: {species: 'dog', color: 'brown'},
2460
+ * felix: {species: 'cat', color: 'black'},
2461
+ * cujo: {species: 'dog', color: 'black'},
2462
+ * });
2463
+ *
2464
+ * const queries = createQueries(store).setQueryDefinition(
2465
+ * 'dogColors',
2466
+ * 'pets',
2467
+ * ({select, where, order}) => {
2468
+ * select('color');
2469
+ * where('species', 'dog');
2470
+ * order('color');
2471
+ * },
2472
+ * );
2473
+ *
2474
+ * const listenerId = queries.addResultRowIdsListener(
2475
+ * 'dogColors',
2476
+ * (store, tableId) => {
2477
+ * console.log(`Row Ids for dogColors result table changed`);
2478
+ * console.log(queries.getResultRowIds('dogColors'));
2479
+ * },
2480
+ * );
2481
+ *
2482
+ * store.setRow('pets', 'rex', {species: 'dog', color: 'tan'});
2483
+ * // -> 'Row Ids for dogColors result table changed'
2484
+ * // -> ['cujo', 'fido', 'rex']
2485
+ *
2486
+ * store.setCell('pets', 'fido', 'color', 'walnut');
2487
+ * // -> undefined
2488
+ * // trackReorder not set for listener
2489
+ *
2490
+ * store.delListener(listenerId);
2491
+ * ```
2492
+ * @example
2493
+ * This example registers a listener that responds to a change of order in the
2494
+ * rows of a specific result Table, even though the set of Ids themselves has
2495
+ * not changed.
2496
+ *
2497
+ * ```js
2498
+ * const store = createStore().setTable('pets', {
2499
+ * fido: {species: 'dog', color: 'brown'},
2500
+ * felix: {species: 'cat', color: 'black'},
2501
+ * cujo: {species: 'dog', color: 'black'},
2502
+ * });
2503
+ *
2504
+ * const queries = createQueries(store).setQueryDefinition(
2505
+ * 'dogColors',
2506
+ * 'pets',
2507
+ * ({select, where, order}) => {
2508
+ * select('color');
2509
+ * where('species', 'dog');
2510
+ * order('color');
2511
+ * },
2512
+ * );
2513
+ *
2514
+ * const listenerId = queries.addResultRowIdsListener(
2515
+ * 'dogColors',
2516
+ * (store, tableId) => {
2517
+ * console.log(`Row Ids for dogColors result table changed`);
2518
+ * console.log(queries.getResultRowIds('dogColors'));
2519
+ * },
2520
+ * true, // track reorder
2521
+ * );
2522
+ *
2523
+ * store.setRow('pets', 'rex', {species: 'dog', color: 'tan'});
2524
+ * // -> 'Row Ids for dogColors result table changed'
2525
+ * // -> ['cujo', 'fido', 'rex']
2526
+ *
2527
+ * store.setCell('pets', 'fido', 'color', 'walnut');
2528
+ * // -> 'Row Ids for dogColors result table changed'
2529
+ * // -> ['cujo', 'rex', 'fido']
2530
+ *
2531
+ * store.delListener(listenerId);
2532
+ * ```
2533
+ * @example
2534
+ * This example registers a listener that responds to any change to the Row
2535
+ * Ids of any result Table.
2536
+ *
2537
+ * ```js
2538
+ * const store = createStore().setTable('pets', {
2539
+ * fido: {species: 'dog', color: 'brown'},
2540
+ * felix: {species: 'cat', color: 'black'},
2541
+ * cujo: {species: 'dog', color: 'black'},
2542
+ * });
2543
+ *
2544
+ * const queries = createQueries(store)
2545
+ * .setQueryDefinition('dogColors', 'pets', ({select, where}) => {
2546
+ * select('color');
2547
+ * where('species', 'dog');
2548
+ * })
2549
+ * .setQueryDefinition('catColors', 'pets', ({select, where}) => {
2550
+ * select('color');
2551
+ * where('species', 'cat');
2552
+ * });
2553
+ *
2554
+ * const listenerId = queries.addResultRowIdsListener(
2555
+ * null,
2556
+ * (queries, tableId) => {
2557
+ * console.log(`Row Ids for ${tableId} result table changed`);
2558
+ * },
2559
+ * );
2560
+ *
2561
+ * store.setRow('pets', 'rex', {species: 'dog', color: 'tan'});
2562
+ * // -> 'Row Ids for dogColors result table changed'
2563
+ * store.setRow('pets', 'tom', {species: 'cat', color: 'gray'});
2564
+ * // -> 'Row Ids for catColors result table changed'
2565
+ *
2566
+ * store.delListener(listenerId);
2567
+ * ```
2568
+ * @category Listener
2569
+ */
2570
+ addResultRowIdsListener(
2571
+ queryId: IdOrNull,
2572
+ listener: ResultRowIdsListener,
2573
+ trackReorder?: boolean,
2574
+ ): Id;
2575
+
2576
+ /**
2577
+ * The addResultRowListener method registers a listener function with the
2578
+ * Queries object that will be called whenever data in a result Row changes.
2579
+ *
2580
+ * The provided listener is a ResultRowListener function, and will be called
2581
+ * with a reference to the Queries object, the Id of the Table that changed
2582
+ * (which is also the query Id), and a GetCellChange function in case you need
2583
+ * to inspect any changes that occurred.
2584
+ *
2585
+ * You can either listen to a single result Row (by specifying a query Id and
2586
+ * Row Id as the method's first two parameters) or changes to any result Row
2587
+ * (by providing `null` wildcards).
2588
+ *
2589
+ * Both, either, or neither of the `queryId` and `rowId` parameters can be
2590
+ * wildcarded with `null`. You can listen to a specific result Row in a
2591
+ * specific query, any result Row in a specific query, a specific result Row
2592
+ * in any query, or any result Row in any query.
2593
+ *
2594
+ * @param queryId The Id of the query to listen to, or `null` as a wildcard.
2595
+ * @param rowId The Id of the result Row to listen to, or `null` as a
2596
+ * wildcard.
2597
+ * @param listener The function that will be called whenever data in the
2598
+ * matching result Row changes.
2599
+ * @returns A unique Id for the listener that can later be used to remove it.
2600
+ * @example
2601
+ * This example registers a listener that responds to any changes to a
2602
+ * specific result Row.
2603
+ *
2604
+ * ```js
2605
+ * const store = createStore().setTable('pets', {
2606
+ * fido: {species: 'dog', color: 'brown'},
2607
+ * felix: {species: 'cat', color: 'black'},
2608
+ * cujo: {species: 'dog', color: 'black'},
2609
+ * });
2610
+ *
2611
+ * const queries = createQueries(store).setQueryDefinition(
2612
+ * 'dogColors',
2613
+ * 'pets',
2614
+ * ({select, where}) => {
2615
+ * select('color');
2616
+ * where('species', 'dog');
2617
+ * },
2618
+ * );
2619
+ *
2620
+ * const listenerId = queries.addResultRowListener(
2621
+ * 'dogColors',
2622
+ * 'fido',
2623
+ * (queries, tableId, rowId, getCellChange) => {
2624
+ * console.log('fido row in dogColors result table changed');
2625
+ * console.log(getCellChange('dogColors', 'fido', 'color'));
2626
+ * },
2627
+ * );
2628
+ *
2629
+ * store.setCell('pets', 'fido', 'color', 'walnut');
2630
+ * // -> 'fido row in dogColors result table changed'
2631
+ * // -> [true, 'brown', 'walnut']
2632
+ *
2633
+ * store.delListener(listenerId);
2634
+ * ```
2635
+ * @example
2636
+ * This example registers a listener that responds to any changes to any
2637
+ * result Row.
2638
+ *
2639
+ * ```js
2640
+ * const store = createStore().setTable('pets', {
2641
+ * fido: {species: 'dog', color: 'brown'},
2642
+ * felix: {species: 'cat', color: 'black'},
2643
+ * cujo: {species: 'dog', color: 'black'},
2644
+ * });
2645
+ *
2646
+ * const queries = createQueries(store)
2647
+ * .setQueryDefinition('dogColors', 'pets', ({select, where}) => {
2648
+ * select('color');
2649
+ * where('species', 'dog');
2650
+ * })
2651
+ * .setQueryDefinition('catColors', 'pets', ({select, where}) => {
2652
+ * select('color');
2653
+ * where('species', 'cat');
2654
+ * });
2655
+ *
2656
+ * const listenerId = queries.addResultRowListener(
2657
+ * null,
2658
+ * null,
2659
+ * (queries, tableId, rowId) => {
2660
+ * console.log(`${rowId} row in ${tableId} result table changed`);
2661
+ * },
2662
+ * );
2663
+ *
2664
+ * store.setCell('pets', 'fido', 'color', 'walnut');
2665
+ * // -> 'fido row in dogColors result table changed'
2666
+ * store.setCell('pets', 'felix', 'color', 'tortoiseshell');
2667
+ * // -> 'felix row in catColors result table changed'
2668
+ *
2669
+ * store.delListener(listenerId);
2670
+ * ```
2671
+ * @category Listener
2672
+ */
2673
+ addResultRowListener(
2674
+ queryId: IdOrNull,
2675
+ rowId: IdOrNull,
2676
+ listener: ResultRowListener,
2677
+ ): Id;
2678
+
2679
+ /**
2680
+ * The addResultCellIdsListener method registers a listener function with the
2681
+ * Queries object that will be called whenever the Cell Ids in a result Row
2682
+ * change.
2683
+ *
2684
+ * The provided listener is a ResultCellIdsListener function, and will be
2685
+ * called with a reference to the Queries object, the Id of the Table (which
2686
+ * is also the query Id), and the Id of the result Row that changed.
2687
+ *
2688
+ * By default, such a listener is only called when a Cell is added to, or
2689
+ * removed from, the result Row. To listen to all changes in the result Row,
2690
+ * use the addResultRowListener method.
2691
+ *
2692
+ * You can either listen to a single result Row (by specifying the query Id
2693
+ * and Row Id as the method's first two parameters) or changes to any Row (by
2694
+ * providing `null`).
2695
+ *
2696
+ * Both, either, or neither of the `queryId` and `rowId` parameters can be
2697
+ * wildcarded with `null`. You can listen to a specific result Row in a
2698
+ * specific query, any result Row in a specific query, a specific result Row
2699
+ * in any query, or any result Row in any query.
2700
+ *
2701
+ * Use the optional `trackReorder` parameter to additionally track when the
2702
+ * set of Ids has not changed, but the order has - for example when a Cell
2703
+ * from the middle of the Row is removed and then added back within the same
2704
+ * transaction. This behavior is disabled by default due to the potential
2705
+ * performance cost of detecting such changes.
2706
+ *
2707
+ * @param queryId The Id of the query to listen to, or `null` as a wildcard.
2708
+ * @param rowId The Id of the result Row to listen to, or `null` as a
2709
+ * wildcard.
2710
+ * @param listener The function that will be called whenever the Cell Ids in
2711
+ * the result Row change.
2712
+ * @param trackReorder An optional boolean that indicates that the listener
2713
+ * should be called if the set of Ids remains the same but their order
2714
+ * changes.
2715
+ * @returns A unique Id for the listener that can later be used to remove it.
2716
+ * @example
2717
+ * This example registers a listener that responds to any change to the Cell
2718
+ * Ids of a specific result Row.
2719
+ *
2720
+ * ```js
2721
+ * const store = createStore().setTable('pets', {
2722
+ * fido: {species: 'dog', color: 'brown'},
2723
+ * felix: {species: 'cat', color: 'black'},
2724
+ * cujo: {species: 'dog', color: 'black'},
2725
+ * });
2726
+ *
2727
+ * const queries = createQueries(store).setQueryDefinition(
2728
+ * 'dogColors',
2729
+ * 'pets',
2730
+ * ({select, where}) => {
2731
+ * select('color');
2732
+ * select('price');
2733
+ * where('species', 'dog');
2734
+ * },
2735
+ * );
2736
+ *
2737
+ * const listenerId = queries.addResultCellIdsListener(
2738
+ * 'dogColors',
2739
+ * 'fido',
2740
+ * (store, tableId, rowId) => {
2741
+ * console.log(`Cell Ids for fido row in dogColors result table changed`);
2742
+ * console.log(queries.getResultCellIds('dogColors', 'fido'));
2743
+ * },
2744
+ * );
2745
+ *
2746
+ * store.setCell('pets', 'fido', 'price', 5);
2747
+ * // -> 'Cell Ids for fido row in dogColors result table changed'
2748
+ * // -> ['color', 'price']
2749
+ *
2750
+ * store.delListener(listenerId);
2751
+ * ```
2752
+ * @example
2753
+ * This example registers a listener that responds to any change to the Cell
2754
+ * Ids of any result Row.
2755
+ *
2756
+ * ```js
2757
+ * const store = createStore().setTable('pets', {
2758
+ * fido: {species: 'dog', color: 'brown'},
2759
+ * felix: {species: 'cat', color: 'black'},
2760
+ * cujo: {species: 'dog', color: 'black'},
2761
+ * });
2762
+ *
2763
+ * const queries = createQueries(store)
2764
+ * .setQueryDefinition('dogColors', 'pets', ({select, where}) => {
2765
+ * select('color');
2766
+ * select('price');
2767
+ * where('species', 'dog');
2768
+ * })
2769
+ * .setQueryDefinition('catColors', 'pets', ({select, where}) => {
2770
+ * select('color');
2771
+ * select('purrs');
2772
+ * where('species', 'cat');
2773
+ * });
2774
+ *
2775
+ * const listenerId = queries.addResultCellIdsListener(
2776
+ * null,
2777
+ * null,
2778
+ * (queries, tableId, rowId) => {
2779
+ * console.log(
2780
+ * `Cell Ids for ${rowId} row in ${tableId} result table changed`,
2781
+ * );
2782
+ * },
2783
+ * );
2784
+ *
2785
+ * store.setCell('pets', 'fido', 'price', 5);
2786
+ * // -> 'Cell Ids for fido row in dogColors result table changed'
2787
+ * store.setCell('pets', 'felix', 'purrs', true);
2788
+ * // -> 'Cell Ids for felix row in catColors result table changed'
2789
+ *
2790
+ * store.delListener(listenerId);
2791
+ * ```
2792
+ * @category Listener
2793
+ */
2794
+ addResultCellIdsListener(
2795
+ queryId: IdOrNull,
2796
+ rowId: IdOrNull,
2797
+ listener: ResultCellIdsListener,
2798
+ trackReorder?: boolean,
2799
+ ): Id;
2800
+
2801
+ /**
2802
+ * The addResultCellListener method registers a listener function with the
2803
+ * Queries object that will be called whenever data in a result Cell changes.
2804
+ *
2805
+ * The provided listener is a ResultCellListener function, and will be called
2806
+ * with a reference to the Queries object, the Id of the Table that changed
2807
+ * (which is also the query Id), the Id of the Row that changed, the Id of the
2808
+ * Cell that changed, the new Cell value, the old Cell value, and a
2809
+ * GetCellChange function in case you need to inspect any changes that
2810
+ * occurred.
2811
+ *
2812
+ * You can either listen to a single result Row (by specifying a query Id, Row
2813
+ * Id, and Cell Id as the method's first three parameters) or changes to any
2814
+ * result Cell (by providing `null` wildcards).
2815
+ *
2816
+ * All, some, or none of the `queryId`, `rowId`, and `cellId` parameters can
2817
+ * be wildcarded with `null`. You can listen to a specific Cell in a specific
2818
+ * result Row in a specific query, any Cell in any result Row in any query,
2819
+ * for example - or every other combination of wildcards.
2820
+ *
2821
+ * @param queryId The Id of the query to listen to, or `null` as a wildcard.
2822
+ * @param rowId The Id of the result Row to listen to, or `null` as a
2823
+ * wildcard.
2824
+ * @param cellId The Id of the result Cell to listen to, or `null` as a
2825
+ * wildcard.
2826
+ * @param listener The function that will be called whenever data in the
2827
+ * matching result Cell changes.
2828
+ * @returns A unique Id for the listener that can later be used to remove it.
2829
+ * @example
2830
+ * This example registers a listener that responds to any changes to a
2831
+ * specific result Cell.
2832
+ *
2833
+ * ```js
2834
+ * const store = createStore().setTable('pets', {
2835
+ * fido: {species: 'dog', color: 'brown'},
2836
+ * felix: {species: 'cat', color: 'black'},
2837
+ * cujo: {species: 'dog', color: 'black'},
2838
+ * });
2839
+ *
2840
+ * const queries = createQueries(store).setQueryDefinition(
2841
+ * 'dogColors',
2842
+ * 'pets',
2843
+ * ({select, where}) => {
2844
+ * select('color');
2845
+ * where('species', 'dog');
2846
+ * },
2847
+ * );
2848
+ *
2849
+ * const listenerId = queries.addResultCellListener(
2850
+ * 'dogColors',
2851
+ * 'fido',
2852
+ * 'color',
2853
+ * (queries, tableId, rowId, cellId, newCell, oldCell, getCellChange) => {
2854
+ * console.log(
2855
+ * 'color cell in fido row in dogColors result table changed',
2856
+ * );
2857
+ * console.log([oldCell, newCell]);
2858
+ * console.log(getCellChange('dogColors', 'fido', 'color'));
2859
+ * },
2860
+ * );
2861
+ *
2862
+ * store.setCell('pets', 'fido', 'color', 'walnut');
2863
+ * // -> 'color cell in fido row in dogColors result table changed'
2864
+ * // -> ['brown', 'walnut']
2865
+ * // -> [true, 'brown', 'walnut']
2866
+ *
2867
+ * store.delListener(listenerId);
2868
+ * ```
2869
+ * @example
2870
+ * This example registers a listener that responds to any changes to any
2871
+ * result Cell.
2872
+ *
2873
+ * ```js
2874
+ * const store = createStore().setTable('pets', {
2875
+ * fido: {species: 'dog', color: 'brown', price: 5},
2876
+ * felix: {species: 'cat', color: 'black', price: 4},
2877
+ * cujo: {species: 'dog', color: 'black', price: 5},
2878
+ * });
2879
+ *
2880
+ * const queries = createQueries(store)
2881
+ * .setQueryDefinition('dogColors', 'pets', ({select, where}) => {
2882
+ * select('color');
2883
+ * where('species', 'dog');
2884
+ * })
2885
+ * .setQueryDefinition('catColors', 'pets', ({select, where}) => {
2886
+ * select('color');
2887
+ * select('price');
2888
+ * where('species', 'cat');
2889
+ * });
2890
+ *
2891
+ * const listenerId = queries.addResultCellListener(
2892
+ * null,
2893
+ * null,
2894
+ * null,
2895
+ * (queries, tableId, rowId, cellId) => {
2896
+ * console.log(
2897
+ * `${cellId} cell in ${rowId} row in ${tableId} result table changed`,
2898
+ * );
2899
+ * },
2900
+ * );
2901
+ *
2902
+ * store.setCell('pets', 'fido', 'color', 'walnut');
2903
+ * // -> 'color cell in fido row in dogColors result table changed'
2904
+ * store.setCell('pets', 'felix', 'price', 3);
2905
+ * // -> 'price cell in felix row in catColors result table changed'
2906
+ *
2907
+ * store.delListener(listenerId);
2908
+ * ```
2909
+ * @category Listener
2910
+ */
2911
+ addResultCellListener(
2912
+ queryId: IdOrNull,
2913
+ rowId: IdOrNull,
2914
+ cellId: IdOrNull,
2915
+ listener: ResultCellListener,
2916
+ ): Id;
2917
+
2918
+ /**
2919
+ * The delListener method removes a listener that was previously added to the
2920
+ * Queries object.
2921
+ *
2922
+ * Use the Id returned by the addMetricListener method. Note that the Queries
2923
+ * object may re-use this Id for future listeners added to it.
2924
+ *
2925
+ * @param listenerId The Id of the listener to remove.
2926
+ * @returns A reference to the Queries object.
2927
+ * @example
2928
+ * This example creates a Store, a Queries object, registers a listener, and
2929
+ * then removes it.
2930
+ *
2931
+ * ```js
2932
+ * const store = createStore().setTable('pets', {
2933
+ * fido: {species: 'dog'},
2934
+ * felix: {species: 'cat'},
2935
+ * cujo: {species: 'dog'},
2936
+ * });
2937
+ *
2938
+ * const queries = createQueries(store).setQueryDefinition(
2939
+ * 'species',
2940
+ * 'pets',
2941
+ * ({select}) => {
2942
+ * select('species');
2943
+ * },
2944
+ * );
2945
+ *
2946
+ * const listenerId = queries.addResultTableListener('species', (queries) =>
2947
+ * console.log('species result changed'),
2948
+ * );
2949
+ *
2950
+ * store.setCell('pets', 'ed', 'species', 'horse');
2951
+ * // -> 'species result changed'
2952
+ *
2953
+ * queries.delListener(listenerId);
2954
+ *
2955
+ * store.setCell('pets', 'molly', 'species', 'cow');
2956
+ * // -> undefined
2957
+ * // The listener is not called.
2958
+ * ```
2959
+ * @category Listener
2960
+ * @since v2.0.0-beta
2961
+ */
2962
+ delListener(listenerId: Id): Queries;
2963
+
2964
+ /**
2965
+ * The destroy method should be called when this Queries object is no longer
2966
+ * used.
2967
+ *
2968
+ * This guarantees that all of the listeners that the object registered with
2969
+ * the underlying Store are removed and it can be correctly garbage collected.
2970
+ *
2971
+ * @example
2972
+ * This example creates a Store, adds a Queries object with a definition (that
2973
+ * registers a RowListener with the underlying Store), and then destroys it
2974
+ * again, removing the listener.
2975
+ *
2976
+ * ```js
2977
+ * const store = createStore().setTable('pets', {
2978
+ * fido: {species: 'dog'},
2979
+ * felix: {species: 'cat'},
2980
+ * cujo: {species: 'dog'},
2981
+ * });
2982
+ *
2983
+ * const queries = createQueries(store);
2984
+ * queries.setQueryDefinition('species', 'species', ({select}) => {
2985
+ * select('species');
2986
+ * });
2987
+ * console.log(store.getListenerStats().row);
2988
+ * // -> 1
2989
+ *
2990
+ * queries.destroy();
2991
+ *
2992
+ * console.log(store.getListenerStats().row);
2993
+ * // -> 0
2994
+ * ```
2995
+ * @category Lifecycle
2996
+ * @since v2.0.0-beta
2997
+ */
2998
+ destroy(): void;
2999
+
3000
+ /**
3001
+ * The getListenerStats method provides a set of statistics about the
3002
+ * listeners registered with the Queries object, and is used for debugging
3003
+ * purposes.
3004
+ *
3005
+ * The statistics are only populated in a debug build: production builds
3006
+ * return an empty object. The method is intended to be used during
3007
+ * development to ensure your application is not leaking listener
3008
+ * registrations, for example.
3009
+ *
3010
+ * @returns A QueriesListenerStats object containing Queries listener
3011
+ * statistics.
3012
+ * @example
3013
+ * This example gets the listener statistics of a Queries object.
3014
+ *
3015
+ * ```js
3016
+ * const store = createStore();
3017
+ * const queries = createQueries(store);
3018
+ * queries.addResultTableListener(null, () => console.log('Result changed'));
3019
+ *
3020
+ * console.log(queries.getListenerStats().table);
3021
+ * // -> 1
3022
+ * console.log(queries.getListenerStats().row);
3023
+ * // -> 0
3024
+ * ```
3025
+ * @category Development
3026
+ * @since v2.0.0-beta
3027
+ */
3028
+ getListenerStats(): QueriesListenerStats;
3029
+ }
3030
+
3031
+ /**
3032
+ * The createQueries function creates a Queries object, and is the main entry
3033
+ * point into the queries module.
3034
+ *
3035
+ * It is trivially simple.
3036
+ *
3037
+ * A given Store can only have one Queries object associated with it. If you
3038
+ * call this function twice on the same Store, your second call will return a
3039
+ * reference to the Queries object created by the first.
3040
+ *
3041
+ * @param store The Store for which to register query definitions.
3042
+ * @returns A reference to the new Queries object.
3043
+ * @example
3044
+ * This example creates a Queries object.
3045
+ *
3046
+ * ```js
3047
+ * const store = createStore();
3048
+ * const queries = createQueries(store);
3049
+ * console.log(queries.getQueryIds());
3050
+ * // -> []
3051
+ * ```
3052
+ * @example
3053
+ * This example creates a Queries object, and calls the method a second time
3054
+ * for the same Store to return the same object.
3055
+ *
3056
+ * ```js
3057
+ * const store = createStore();
3058
+ * const queries1 = createQueries(store);
3059
+ * const queries2 = createQueries(store);
3060
+ * console.log(queries1 === queries2);
3061
+ * // -> true
3062
+ * ```
3063
+ * @category Creation
3064
+ * @since v2.0.0-beta
3065
+ */
3066
+ export function createQueries(store: Store): Queries;