tinybase 0.0.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/lib/checkpoints.d.ts +861 -0
  3. package/lib/checkpoints.js +1 -0
  4. package/lib/checkpoints.js.gz +0 -0
  5. package/lib/common.d.ts +59 -0
  6. package/lib/debug/checkpoints.d.ts +861 -0
  7. package/lib/debug/checkpoints.js +326 -0
  8. package/lib/debug/common.d.ts +59 -0
  9. package/lib/debug/indexes.d.ts +815 -0
  10. package/lib/debug/indexes.js +390 -0
  11. package/lib/debug/metrics.d.ts +728 -0
  12. package/lib/debug/metrics.js +391 -0
  13. package/lib/debug/persisters.d.ts +521 -0
  14. package/lib/debug/persisters.js +191 -0
  15. package/lib/debug/react.d.ts +7077 -0
  16. package/lib/debug/react.js +1037 -0
  17. package/lib/debug/relationships.d.ts +1091 -0
  18. package/lib/debug/relationships.js +418 -0
  19. package/lib/debug/store.d.ts +2424 -0
  20. package/lib/debug/store.js +725 -0
  21. package/lib/debug/tinybase.d.ts +14 -0
  22. package/lib/debug/tinybase.js +2727 -0
  23. package/lib/indexes.d.ts +815 -0
  24. package/lib/indexes.js +1 -0
  25. package/lib/indexes.js.gz +0 -0
  26. package/lib/metrics.d.ts +728 -0
  27. package/lib/metrics.js +1 -0
  28. package/lib/metrics.js.gz +0 -0
  29. package/lib/persisters.d.ts +521 -0
  30. package/lib/persisters.js +1 -0
  31. package/lib/persisters.js.gz +0 -0
  32. package/lib/react.d.ts +7077 -0
  33. package/lib/react.js +1 -0
  34. package/lib/react.js.gz +0 -0
  35. package/lib/relationships.d.ts +1091 -0
  36. package/lib/relationships.js +1 -0
  37. package/lib/relationships.js.gz +0 -0
  38. package/lib/store.d.ts +2424 -0
  39. package/lib/store.js +1 -0
  40. package/lib/store.js.gz +0 -0
  41. package/lib/tinybase.d.ts +14 -0
  42. package/lib/tinybase.js +1 -0
  43. package/lib/tinybase.js.gz +0 -0
  44. package/lib/umd/checkpoints.js +1 -0
  45. package/lib/umd/checkpoints.js.gz +0 -0
  46. package/lib/umd/indexes.js +1 -0
  47. package/lib/umd/indexes.js.gz +0 -0
  48. package/lib/umd/metrics.js +1 -0
  49. package/lib/umd/metrics.js.gz +0 -0
  50. package/lib/umd/persisters.js +1 -0
  51. package/lib/umd/persisters.js.gz +0 -0
  52. package/lib/umd/react.js +1 -0
  53. package/lib/umd/react.js.gz +0 -0
  54. package/lib/umd/relationships.js +1 -0
  55. package/lib/umd/relationships.js.gz +0 -0
  56. package/lib/umd/store.js +1 -0
  57. package/lib/umd/store.js.gz +0 -0
  58. package/lib/umd/tinybase.js +1 -0
  59. package/lib/umd/tinybase.js.gz +0 -0
  60. package/package.json +93 -2
  61. package/readme.md +195 -0
@@ -0,0 +1,1091 @@
1
+ /**
2
+ * The relationships module of the TinyBase project provides the ability to
3
+ * create and track relationships between the data in Store objects.
4
+ *
5
+ * The main entry point to this module is the createRelationships function,
6
+ * which returns a new Relationships object. From there, you can create new
7
+ * relationship definitions, access the associations within those relationships
8
+ * directly, and register listeners for when they change.
9
+ *
10
+ * @packageDocumentation
11
+ * @module relationships
12
+ */
13
+
14
+ import {GetCell, Store} from './store.d';
15
+ import {Id, IdOrNull, Ids} from './common.d';
16
+
17
+ /**
18
+ * The Relationship type represents the concept of a map that connects one Row
19
+ * object to another, often in another Table.
20
+ *
21
+ * The Relationship has a one-to-many nature. One local Row Id is linked to one
22
+ * remote Row Id (in the remote Table), as described by the
23
+ * setRelationshipDefinition method - and one remote Row Id may map back to
24
+ * multiple local Row Ids (in the local Table).
25
+ *
26
+ * A Relationship where the local Table is the same as the remote Table can be
27
+ * used to model a 'linked list', where Row A references Row B, Row B references
28
+ * Row C, and so on.
29
+ *
30
+ * Note that the Relationship type is not actually used in the API, and you
31
+ * instead enumerate and access its structure with the getRemoteRowId method,
32
+ * the getLocalRowIds method, and the getLinkedRowIds method.
33
+ *
34
+ * @category Concept
35
+ */
36
+ export type Relationship = {
37
+ remoteRowId: {[localRowId: Id]: Id};
38
+ localRowIds: {[remoteRowId: Id]: Ids};
39
+ linkedRowIds: {[firstRowId: Id]: Ids};
40
+ };
41
+
42
+ /**
43
+ * The RemoteRowIdListener type describes a function that is used to listen to
44
+ * changes to the remote Row Id end of a Relationship.
45
+ *
46
+ * A RemoteRowIdListener is provided when using the addRemoteRowIdListener
47
+ * method. See that method for specific examples.
48
+ *
49
+ * When called, a RemoteRowIdListener is given a reference to the Relationships
50
+ * object, the Id of the Relationship that changed, and the Id of the local Row
51
+ * whose remote Row Id changed.
52
+ *
53
+ * @category Listener
54
+ */
55
+ export type RemoteRowIdListener = (
56
+ relationships: Relationships,
57
+ relationshipId: Id,
58
+ localRowId: Id,
59
+ ) => void;
60
+
61
+ /**
62
+ * The LocalRowIdsListener type describes a function that is used to listen to
63
+ * changes to the local Row Id ends of a Relationship.
64
+ *
65
+ * A LocalRowIdsListener is provided when using the addLocalRowIdsListener
66
+ * method. See that method for specific examples.
67
+ *
68
+ * When called, a LocalRowIdsListener is given a reference to the Relationships
69
+ * object, the Id of the Relationship that changed, and the Id of the remote Row
70
+ * whose local Row Id changed.
71
+ *
72
+ * @category Listener
73
+ */
74
+ export type LocalRowIdsListener = (
75
+ relationships: Relationships,
76
+ relationshipId: Id,
77
+ remoteRowId: Id,
78
+ ) => void;
79
+
80
+ /**
81
+ * The LinkedRowIdsListener type describes a function that is used to listen to
82
+ * changes to the local Row Id ends of a Relationship.
83
+ *
84
+ * A LinkedRowIdsListener is provided when using the addLinkedRowIdsListener
85
+ * method. See that method for specific examples.
86
+ *
87
+ * When called, a LinkedRowIdsListener is given a reference to the Relationships
88
+ * object, the Id of the Relationship that changed, and the Id of the first Row
89
+ * of the the linked list whose members changed.
90
+ *
91
+ * @category Listener
92
+ */
93
+ export type LinkedRowIdsListener = (
94
+ relationships: Relationships,
95
+ relationshipId: Id,
96
+ firstRowId: Id,
97
+ ) => void;
98
+
99
+ /**
100
+ * The RelationshipsListenerStats type describes the number of listeners
101
+ * registered with the Relationships object, and can be used for debugging
102
+ * purposes.
103
+ *
104
+ * A RelationshipsListenerStats object is returned from the getListenerStats
105
+ * method, and is only populated in a debug build.
106
+ *
107
+ * @category Development
108
+ */
109
+ export type RelationshipsListenerStats = {
110
+ remoteRowId?: number;
111
+ localRowIds?: number;
112
+ linkedRowIds?: number;
113
+ };
114
+
115
+ /**
116
+ * A Relationships object lets you associate a Row in a one Table with the Id of
117
+ * a Row in another Table.
118
+ *
119
+ * This is useful for creating parent-child relationships between the data in
120
+ * different Table objects, but it can also be used to model a linked list of
121
+ * Row objects in the same Table.
122
+ *
123
+ * Create a Relationships object easily with the createRelationships function.
124
+ * From there, you can add new Relationship definitions (with the
125
+ * setRelationshipDefinition method), query their contents (with the
126
+ * getRemoteRowId method, the getLocalRowIds method, and the getLinkedRowIds
127
+ * method), and add listeners for when they change (with the
128
+ * addRemoteRowIdListener method, the addLocalRowIdsListener method, and the
129
+ * addLinkedRowIdsListener method).
130
+ *
131
+ * This module defaults to creating relationships between Row objects by using
132
+ * one of their Cell values. However, far more complex relationships can be
133
+ * configured with a custom function.
134
+ *
135
+ * @example
136
+ * This example shows a very simple lifecycle of a Relationships object: from
137
+ * creation, to adding definitions (both local/remote table and linked list),
138
+ * getting their contents, and then registering and removing listeners for them.
139
+ *
140
+ * ```tsx
141
+ * const store = createStore()
142
+ * .setTable('pets', {
143
+ * fido: {species: 'dog', next: 'felix'},
144
+ * felix: {species: 'cat', next: 'cujo'},
145
+ * cujo: {species: 'dog'},
146
+ * })
147
+ * .setTable('species', {
148
+ * dog: {price: 5},
149
+ * cat: {price: 4},
150
+ * });
151
+ *
152
+ * const relationships = createRelationships(store);
153
+ * // A local/remote table relationship:
154
+ * relationships.setRelationshipDefinition(
155
+ * 'petSpecies', // relationshipId
156
+ * 'pets', // localTableId to link from
157
+ * 'species', // remoteTableId to link to
158
+ * 'species', // cellId containing remote key
159
+ * );
160
+ * // A linked list relationship:
161
+ * relationships.setRelationshipDefinition(
162
+ * 'petSequence', // relationshipId
163
+ * 'pets', // localTableId to link from
164
+ * 'pets', // the same remoteTableId to link within
165
+ * 'next', // cellId containing link key
166
+ * );
167
+ *
168
+ * console.log(relationships.getRemoteRowId('petSpecies', 'fido'));
169
+ * // -> 'dog'
170
+ * console.log(relationships.getLocalRowIds('petSpecies', 'dog'));
171
+ * // -> ['fido', 'cujo']
172
+ * console.log(relationships.getLinkedRowIds('petSequence', 'fido'));
173
+ * // -> ['fido', 'felix', 'cujo']
174
+ *
175
+ * const listenerId1 = relationships.addLocalRowIdsListener(
176
+ * 'petSpecies',
177
+ * 'dog',
178
+ * () => {
179
+ * console.log('petSpecies relationship (to dog) changed');
180
+ * console.log(relationships.getLocalRowIds('petSpecies', 'dog'));
181
+ * },
182
+ * );
183
+ * const listenerId2 = relationships.addLinkedRowIdsListener(
184
+ * 'petSequence',
185
+ * 'fido',
186
+ * () => {
187
+ * console.log('petSequence linked list (from fido) changed');
188
+ * console.log(relationships.getLinkedRowIds('petSequence', 'fido'));
189
+ * },
190
+ * );
191
+ *
192
+ * store.setRow('pets', 'toto', {species: 'dog'});
193
+ * // -> 'petSpecies relationship (to dog) changed'
194
+ * // -> ['fido', 'cujo', 'toto']
195
+ *
196
+ * store.setCell('pets', 'cujo', 'next', 'toto');
197
+ * // -> 'petSequence linked list (from fido) changed'
198
+ * // -> ['fido', 'felix', 'cujo', 'toto']
199
+ *
200
+ * relationships.delListener(listenerId1);
201
+ * relationships.delListener(listenerId2);
202
+ * relationships.destroy();
203
+ * ```
204
+ */
205
+ export interface Relationships {
206
+ /**
207
+ * The setRelationshipDefinition method lets you set the definition of a
208
+ * Relationship.
209
+ *
210
+ * Every Relationship definition is identified by a unique Id, and if you
211
+ * re-use an existing Id with this method, the previous definition is
212
+ * overwritten.
213
+ *
214
+ * An Relationship is based on connections between Row objects, often in two
215
+ * different Table objects. Therefore the definition requires the
216
+ * `localTableId` parameter to specify the 'local' Table to create the
217
+ * Relationship from, and the `remoteTableId` parameter to specify the
218
+ * 'remote' Table to create Relationship to.
219
+ *
220
+ * A linked list Relationship is one that has the same Table specified as both
221
+ * local Table Id and remote Table Id, allowing you to create a sequence of
222
+ * Row objects within that one Table.
223
+ *
224
+ * A local Row is related to a remote Row by specifying which of its (local)
225
+ * Cell values contains the (remote) Row Id, using the `getRemoteRowId`
226
+ * parameter. Alternatively, a custom function can be provided that produces
227
+ * your own remote Row Id from the local Row as a whole.
228
+ *
229
+ * @param relationshipId The Id of the Relationship to define.
230
+ * @param localTableId The Id of the local Table for the Relationship.
231
+ * @param remoteTableId The Id of the remote Table for the Relationship (or
232
+ * the same as the `localTableId` in the case of a linked list).
233
+ * @param getRemoteRowId Either the Id of the Cell containing, or a function
234
+ * that produces, the Id that is used to indicate which Row in the remote
235
+ * Table a local Row is related to.
236
+ * @returns A reference to the Relationships object.
237
+ * @example
238
+ * This example creates a Store, creates a Relationships object, and defines
239
+ * a simple Relationship based on the values in the `species` Cell of the
240
+ * `pets` Table that relates a Row to another in the `species` Table.
241
+ *
242
+ * ```tsx
243
+ * const store = createStore()
244
+ * .setTable('pets', {
245
+ * fido: {species: 'dog'},
246
+ * felix: {species: 'cat'},
247
+ * cujo: {species: 'dog'},
248
+ * })
249
+ * .setTable('species', {
250
+ * dog: {price: 5},
251
+ * cat: {price: 4},
252
+ * });
253
+ *
254
+ * const relationships = createRelationships(store);
255
+ * relationships.setRelationshipDefinition(
256
+ * 'petSpecies', // relationshipId
257
+ * 'pets', // localTableId to link from
258
+ * 'species', // remoteTableId to link to
259
+ * 'species', // cellId containing remote key
260
+ * );
261
+ *
262
+ * console.log(relationships.getRemoteRowId('petSpecies', 'fido'));
263
+ * // -> 'dog'
264
+ * console.log(relationships.getLocalRowIds('petSpecies', 'dog'));
265
+ * // -> ['fido', 'cujo']
266
+ * ```
267
+ * @example
268
+ * This example creates a Store, creates a Relationships object, and defines
269
+ * a linked list Relationship based on the values in the `next` Cell of the
270
+ * `pets` Table that relates a Row to another in the same Table.
271
+ *
272
+ * ```tsx
273
+ * const store = createStore().setTable('pets', {
274
+ * fido: {species: 'dog', next: 'felix'},
275
+ * felix: {species: 'cat', next: 'cujo'},
276
+ * cujo: {species: 'dog'},
277
+ * });
278
+ *
279
+ * const relationships = createRelationships(store);
280
+ * relationships.setRelationshipDefinition(
281
+ * 'petSequence', // relationshipId
282
+ * 'pets', // localTableId to link from
283
+ * 'pets', // the same remoteTableId to link within
284
+ * 'next', // cellId containing link key
285
+ * );
286
+ *
287
+ * console.log(relationships.getLinkedRowIds('petSequence', 'fido'));
288
+ * // -> ['fido', 'felix', 'cujo']
289
+ * ```
290
+ * @category Configuration
291
+ */
292
+ setRelationshipDefinition(
293
+ relationshipId: Id,
294
+ localTableId: Id,
295
+ remoteTableId: Id,
296
+ getRemoteRowId: Id | ((getCell: GetCell, localRowId: Id) => Id),
297
+ ): Relationships;
298
+
299
+ /**
300
+ * The delRelationshipDefinition method removes an existing Relationship
301
+ * definition.
302
+ *
303
+ * @param relationshipId The Id of the Relationship to remove.
304
+ * @returns A reference to the Relationships object.
305
+ * @example
306
+ * This example creates a Store, creates a Relationships object, defines a
307
+ * simple Relationship, and then removes it.
308
+ *
309
+ * ```tsx
310
+ * const store = createStore()
311
+ * .setTable('pets', {
312
+ * fido: {species: 'dog'},
313
+ * felix: {species: 'cat'},
314
+ * cujo: {species: 'dog'},
315
+ * })
316
+ * .setTable('species', {
317
+ * dog: {price: 5},
318
+ * cat: {price: 4},
319
+ * });
320
+ *
321
+ * const relationships = createRelationships(store);
322
+ * relationships.setRelationshipDefinition(
323
+ * 'petSpecies',
324
+ * 'pets',
325
+ * 'species',
326
+ * 'species',
327
+ * );
328
+ * console.log(relationships.getRelationshipIds());
329
+ * // -> ['petSpecies']
330
+ *
331
+ * relationships.delRelationshipDefinition('petSpecies');
332
+ * console.log(relationships.getRelationshipIds());
333
+ * // -> []
334
+ * ```
335
+ * @category Configuration
336
+ */
337
+ delRelationshipDefinition(relationshipId: Id): Relationships;
338
+
339
+ /**
340
+ * The getStore method returns a reference to the underlying Store that is
341
+ * backing this Relationships object.
342
+ *
343
+ * @returns A reference to the Store.
344
+ * @example
345
+ * This example creates a Relationships object against a newly-created Store
346
+ * and then gets its reference in order to update its data.
347
+ *
348
+ * ```tsx
349
+ * const relationships = createRelationships(createStore());
350
+ * relationships.setRelationshipDefinition(
351
+ * 'petSpecies',
352
+ * 'pets',
353
+ * 'species',
354
+ * 'species',
355
+ * );
356
+ * relationships.getStore().setCell('pets', 'fido', 'species', 'dog');
357
+ * console.log(relationships.getRemoteRowId('petSpecies', 'fido'));
358
+ * // -> 'dog'
359
+ * ```
360
+ * @category Getter
361
+ */
362
+ getStore(): Store;
363
+
364
+ /**
365
+ * The getRelationshipIds method returns an array of the Relationship Ids
366
+ * registered with this Relationships object.
367
+ *
368
+ * @returns An array of Ids.
369
+ * @example
370
+ * This example creates a Relationships object with two definitions, and then
371
+ * gets the Ids of the definitions.
372
+ *
373
+ * ```tsx
374
+ * const relationships = createRelationships(createStore())
375
+ * .setRelationshipDefinition('petSpecies', 'pets', 'species', 'species')
376
+ * .setRelationshipDefinition('petSequence', 'pets', 'pets', 'next');
377
+ * console.log(relationships.getRelationshipIds());
378
+ * // -> ['petSpecies', 'petSequence']
379
+ * ```
380
+ * @category Getter
381
+ */
382
+ getRelationshipIds(): Ids;
383
+
384
+ /**
385
+ * The getLocalTableId method returns the Id of the underlying local Table
386
+ * that is used in the Relationship.
387
+ *
388
+ * If the Relationship Id is invalid, the method returns `undefined`.
389
+ *
390
+ * @param relationshipId The Id of a Relationship.
391
+ * @returns The Id of the local Table backing the Relationship, or
392
+ * `undefined`.
393
+ * @example
394
+ * This example creates a Relationship object, a single Relationship
395
+ * definition, and then queries it (and a non-existent definition) to get the
396
+ * underlying local Table Id.
397
+ *
398
+ * ```tsx
399
+ * const relationships = createRelationships(createStore());
400
+ * relationships.setRelationshipDefinition(
401
+ * 'petSpecies',
402
+ * 'pets',
403
+ * 'species',
404
+ * 'species',
405
+ * );
406
+ *
407
+ * console.log(relationships.getLocalTableId('petSpecies'));
408
+ * // -> 'pets'
409
+ * console.log(relationships.getLocalTableId('petColor'));
410
+ * // -> undefined
411
+ * ```
412
+ * @category Getter
413
+ */
414
+ getLocalTableId(relationshipId: Id): Id;
415
+
416
+ /**
417
+ * The getRemoteTableId method returns the Id of the underlying remote Table
418
+ * that is used in the Relationship.
419
+ *
420
+ * If the Relationship Id is invalid, the method returns `undefined`.
421
+ *
422
+ * @param relationshipId The Id of a Relationship.
423
+ * @returns The Id of the remote Table backing the Relationship, or
424
+ * `undefined`.
425
+ * @example
426
+ * This example creates a Relationship object, a single Relationship
427
+ * definition, and then queries it (and a non-existent definition) to get the
428
+ * underlying remote Table Id.
429
+ *
430
+ * ```tsx
431
+ * const relationships = createRelationships(createStore());
432
+ * relationships.setRelationshipDefinition(
433
+ * 'petSpecies',
434
+ * 'pets',
435
+ * 'species',
436
+ * 'species',
437
+ * );
438
+ *
439
+ * console.log(relationships.getRemoteTableId('petSpecies'));
440
+ * // -> 'species'
441
+ * console.log(relationships.getRemoteTableId('petColor'));
442
+ * // -> undefined
443
+ * ```
444
+ * @category Getter
445
+ */
446
+ getRemoteTableId(relationshipId: Id): Id;
447
+
448
+ /**
449
+ * The getRemoteRowId method gets the remote Row Id for a given local Row in a
450
+ * Relationship.
451
+ *
452
+ * If the identified Relationship or Row does not exist (or if the definition
453
+ * references a Table that does not exist) then `undefined` is returned.
454
+ *
455
+ * @param relationshipId The Id of the Relationship.
456
+ * @param localRowId The Id of the local Row in the Relationship.
457
+ * @returns The remote Row Id in the Relationship, or `undefined`.
458
+ * @example
459
+ * This example creates a Store, creates a Relationships object, and defines
460
+ * a simple Relationship. It then uses getRemoteRowId to see the remote Row Id
461
+ * in the Relationship (and also the remote Row Ids for a local Row that does
462
+ * not exist, and for a Relationship that has not been defined).
463
+ *
464
+ * ```tsx
465
+ * const store = createStore()
466
+ * .setTable('pets', {
467
+ * fido: {species: 'dog'},
468
+ * felix: {species: 'cat'},
469
+ * cujo: {species: 'dog'},
470
+ * })
471
+ * .setTable('species', {
472
+ * dog: {price: 5},
473
+ * cat: {price: 4},
474
+ * });
475
+ *
476
+ * const relationships = createRelationships(store);
477
+ * relationships.setRelationshipDefinition(
478
+ * 'petSpecies',
479
+ * 'pets',
480
+ * 'species',
481
+ * 'species',
482
+ * );
483
+ *
484
+ * console.log(relationships.getRemoteRowId('petSpecies', 'fido'));
485
+ * // -> 'dog'
486
+ * console.log(relationships.getRemoteRowId('petSpecies', 'toto'));
487
+ * // -> undefined
488
+ * console.log(relationships.getRemoteRowId('petColor', 'fido'));
489
+ * // -> undefined
490
+ * ```
491
+ * @category Getter
492
+ */
493
+ getRemoteRowId(relationshipId: Id, localRowId: Id): Id | undefined;
494
+
495
+ /**
496
+ * The getLocalRowIds method gets the local Row Ids for a given remote Row in
497
+ * a Relationship.
498
+ *
499
+ * If the identified Relationship or Row does not exist (or if the definition
500
+ * references a Table that does not exist) then an empty array is returned.
501
+ *
502
+ * @param relationshipId The Id of the Relationship.
503
+ * @param remoteRowId The Id of the remote Row in the Relationship.
504
+ * @returns The local Row Ids in the Relationship, or an empty array.
505
+ * @example
506
+ * This example creates a Store, creates a Relationships object, and defines
507
+ * a simple Relationship. It then uses getLocalRowIds to see the local Row Ids
508
+ * in the Relationship (and also the local Row Ids for a remote Row that does
509
+ * not exist, and for a Relationship that has not been defined).
510
+ *
511
+ * ```tsx
512
+ * const store = createStore()
513
+ * .setTable('pets', {
514
+ * fido: {species: 'dog'},
515
+ * felix: {species: 'cat'},
516
+ * cujo: {species: 'dog'},
517
+ * })
518
+ * .setTable('species', {
519
+ * dog: {price: 5},
520
+ * cat: {price: 4},
521
+ * });
522
+ *
523
+ * const relationships = createRelationships(store);
524
+ * relationships.setRelationshipDefinition(
525
+ * 'petSpecies',
526
+ * 'pets',
527
+ * 'species',
528
+ * 'species',
529
+ * );
530
+ *
531
+ * console.log(relationships.getLocalRowIds('petSpecies', 'dog'));
532
+ * // -> ['fido', 'cujo']
533
+ * console.log(relationships.getLocalRowIds('petSpecies', 'worm'));
534
+ * // -> []
535
+ * console.log(relationships.getLocalRowIds('petColor', 'brown'));
536
+ * // -> []
537
+ * ```
538
+ * @category Getter
539
+ */
540
+ getLocalRowIds(relationshipId: Id, remoteRowId: Id): Ids;
541
+
542
+ /**
543
+ * The getLinkedRowIds method gets the linked Row Ids for a given Row in a
544
+ * linked list Relationship.
545
+ *
546
+ * A linked list Relationship is one that has the same Table specified as both
547
+ * local Table Id and remote Table Id, allowing you to create a sequence of
548
+ * Row objects within that one Table.
549
+ *
550
+ * If the identified Relationship or Row does not exist (or if the definition
551
+ * references a Table that does not exist) then an array containing just the
552
+ * first Row Id is returned.
553
+ *
554
+ * @param relationshipId The Id of the Relationship.
555
+ * @param firstRowId The Id of the first Row in the linked list Relationship.
556
+ * @returns The linked Row Ids in the Relationship.
557
+ * @example
558
+ * This example creates a Store, creates a Relationships object, and defines
559
+ * a simple linked list Relationship. It then uses getLinkedRowIds to see the
560
+ * linked Row Ids in the Relationship (and also the linked Row Ids for a Row
561
+ * that does not exist, and for a Relationship that has not been defined).
562
+ *
563
+ * ```tsx
564
+ * const store = createStore().setTable('pets', {
565
+ * fido: {species: 'dog', next: 'felix'},
566
+ * felix: {species: 'cat', next: 'cujo'},
567
+ * cujo: {species: 'dog'},
568
+ * });
569
+ *
570
+ * const relationships = createRelationships(store);
571
+ * relationships.setRelationshipDefinition(
572
+ * 'petSequence',
573
+ * 'pets',
574
+ * 'pets',
575
+ * 'next',
576
+ * );
577
+ *
578
+ * console.log(relationships.getLinkedRowIds('petSequence', 'fido'));
579
+ * // -> ['fido', 'felix', 'cujo']
580
+ * console.log(relationships.getLinkedRowIds('petSequence', 'felix'));
581
+ * // -> ['felix', 'cujo']
582
+ * console.log(relationships.getLinkedRowIds('petSequence', 'toto'));
583
+ * // -> ['toto']
584
+ * console.log(relationships.getLinkedRowIds('petFriendships', 'fido'));
585
+ * // -> ['fido']
586
+ * ```
587
+ * @category Getter
588
+ */
589
+ getLinkedRowIds(relationshipId: Id, firstRowId: Id): Ids;
590
+
591
+ /**
592
+ * The addRemoteRowIdListener method registers a listener function with the
593
+ * Relationships object that will be called whenever a remote Row Id in a
594
+ * Relationship changes.
595
+ *
596
+ * You can either listen to a single local Row (by specifying the Relationship
597
+ * Id and local Row Id as the method's first two parameters), or changes to
598
+ * any local Row (by providing a `null` wildcards).
599
+ *
600
+ * Both, either, or neither of the `relationshipId` and `localRowId`
601
+ * parameters can be wildcarded with `null`. You can listen to a specific
602
+ * local Row in a specific Relationship, any local Row in a specific
603
+ * Relationship, a specific local Row in any Relationship, or any local Row in
604
+ * any Relationship.
605
+ *
606
+ * The provided listener is a RemoteRowIdListener function, and will be called
607
+ * with a reference to the Relationships object, the Id of the Relationship,
608
+ * and the Id of the local Row that had its remote Row change.
609
+ *
610
+ * @param relationshipId The Id of the Relationship to listen to, or `null` as
611
+ * a wildcard.
612
+ * @param localRowId The Id of the local Row to listen to, or `null` as a
613
+ * wildcard.
614
+ * @param listener The function that will be called whenever the remote Row Id
615
+ * changes.
616
+ * @returns A unique Id for the listener that can later be used to remove it.
617
+ * @example
618
+ * This example creates a Store, a Relationships object, and then registers a
619
+ * listener that responds to any changes to a specific local Row's remote Row.
620
+ *
621
+ * ```tsx
622
+ * const store = createStore()
623
+ * .setTable('pets', {
624
+ * fido: {species: 'dog'},
625
+ * felix: {species: 'cat'},
626
+ * cujo: {species: 'dog'},
627
+ * })
628
+ * .setTable('species', {
629
+ * wolf: {price: 10},
630
+ * dog: {price: 5},
631
+ * cat: {price: 4},
632
+ * });
633
+ *
634
+ * const relationships = createRelationships(store);
635
+ * relationships.setRelationshipDefinition(
636
+ * 'petSpecies',
637
+ * 'pets',
638
+ * 'species',
639
+ * 'species',
640
+ * );
641
+ *
642
+ * const listenerId = relationships.addRemoteRowIdListener(
643
+ * 'petSpecies',
644
+ * 'cujo',
645
+ * (relationships, relationshipId, localRowId) => {
646
+ * console.log('petSpecies relationship (from cujo) changed');
647
+ * console.log(relationships.getRemoteRowId('petSpecies', 'cujo'));
648
+ * },
649
+ * );
650
+ *
651
+ * store.setCell('pets', 'cujo', 'species', 'wolf');
652
+ * // -> 'petSpecies relationship (from cujo) changed'
653
+ * // -> 'wolf'
654
+ *
655
+ * relationships.delListener(listenerId);
656
+ * ```
657
+ * @example
658
+ * This example creates a Store, a Relationships object, and then registers a
659
+ * listener that responds to any changes to any local Row's remote Row. It
660
+ * also illustrates how you can use the getStore method and the getRemoteRowId
661
+ * method to resolve the remote Row as a whole.
662
+ *
663
+ * ```tsx
664
+ * const store = createStore()
665
+ * .setTable('pets', {
666
+ * fido: {species: 'dog', color: 'brown'},
667
+ * felix: {species: 'cat', color: 'black'},
668
+ * cujo: {species: 'dog', color: 'brown'},
669
+ * })
670
+ * .setTable('species', {
671
+ * wolf: {price: 10},
672
+ * dog: {price: 5},
673
+ * cat: {price: 4},
674
+ * })
675
+ * .setTable('color', {
676
+ * brown: {discount: 0.1},
677
+ * black: {discount: 0},
678
+ * grey: {discount: 0.2},
679
+ * });
680
+ *
681
+ * const relationships = createRelationships(store)
682
+ * .setRelationshipDefinition('petSpecies', 'pets', 'species', 'species')
683
+ * .setRelationshipDefinition('petColor', 'pets', 'color', 'color');
684
+ *
685
+ * const listenerId = relationships.addRemoteRowIdListener(
686
+ * null,
687
+ * null,
688
+ * (relationships, relationshipId, localRowId) => {
689
+ * console.log(
690
+ * `${relationshipId} relationship (from ${localRowId}) changed`,
691
+ * );
692
+ * console.log(relationships.getRemoteRowId(relationshipId, localRowId));
693
+ * console.log(
694
+ * relationships
695
+ * .getStore()
696
+ * .getRow(
697
+ * relationships.getRemoteTableId(relationshipId),
698
+ * relationships.getRemoteRowId(relationshipId, localRowId),
699
+ * ),
700
+ * );
701
+ * },
702
+ * );
703
+ *
704
+ * store.setRow('pets', 'cujo', {species: 'wolf', color: 'grey'});
705
+ * // -> 'petSpecies relationship (from cujo) changed'
706
+ * // -> 'wolf'
707
+ * // -> {price: 10}
708
+ * // -> 'petColor relationship (from cujo) changed'
709
+ * // -> 'grey'
710
+ * // -> {discount: 0.2}
711
+ *
712
+ * relationships.delListener(listenerId);
713
+ * ```
714
+ * @category Listener
715
+ */
716
+ addRemoteRowIdListener(
717
+ relationshipId: IdOrNull,
718
+ localRowId: IdOrNull,
719
+ listener: RemoteRowIdListener,
720
+ ): Id;
721
+
722
+ /**
723
+ * The addLocalRowIdsListener method registers a listener function with the
724
+ * Relationships object that will be called whenever the local Row Ids in
725
+ * a Relationship change.
726
+ *
727
+ * You can either listen to a single local Row (by specifying the Relationship
728
+ * Id and local Row Id as the method's first two parameters), or changes to
729
+ * any local Row (by providing a `null` wildcards).
730
+ *
731
+ * Both, either, or neither of the `relationshipId` and `remoteRowId`
732
+ * parameters can be wildcarded with `null`. You can listen to a specific
733
+ * remote Row in a specific Relationship, any remote Row in a specific
734
+ * Relationship, a specific remote Row in any Relationship, or any remote Row
735
+ * in any Relationship.
736
+ *
737
+ * The provided listener is a LocalRowIdsListener function, and will be called
738
+ * with a reference to the Relationships object, the Id of the Relationship,
739
+ * and the Id of the remote Row that had its local Row objects change.
740
+ *
741
+ * @param relationshipId The Id of the Relationship to listen to, or `null` as
742
+ * a wildcard.
743
+ * @param remoteRowId The Id of the remote Row to listen to, or `null` as a
744
+ * wildcard.
745
+ * @param listener The function that will be called whenever the local Row Ids
746
+ * change.
747
+ * @returns A unique Id for the listener that can later be used to remove it.
748
+ * @example
749
+ * This example creates a Store, a Relationships object, and then registers a
750
+ * listener that responds to any changes to a specific remote Row's local Row
751
+ * objects.
752
+ *
753
+ * ```tsx
754
+ * const store = createStore()
755
+ * .setTable('pets', {
756
+ * fido: {species: 'dog'},
757
+ * felix: {species: 'cat'},
758
+ * cujo: {species: 'dog'},
759
+ * })
760
+ * .setTable('species', {
761
+ * wolf: {price: 10},
762
+ * dog: {price: 5},
763
+ * cat: {price: 4},
764
+ * });
765
+ *
766
+ * const relationships = createRelationships(store);
767
+ * relationships.setRelationshipDefinition(
768
+ * 'petSpecies',
769
+ * 'pets',
770
+ * 'species',
771
+ * 'species',
772
+ * );
773
+ *
774
+ * const listenerId = relationships.addLocalRowIdsListener(
775
+ * 'petSpecies',
776
+ * 'dog',
777
+ * (relationships, relationshipId, remoteRowId) => {
778
+ * console.log('petSpecies relationship (to dog) changed');
779
+ * console.log(relationships.getLocalRowIds('petSpecies', 'dog'));
780
+ * },
781
+ * );
782
+ *
783
+ * store.setRow('pets', 'toto', {species: 'dog'});
784
+ * // -> 'petSpecies relationship (to dog) changed'
785
+ * // -> ['fido', 'cujo', 'toto']
786
+ *
787
+ * relationships.delListener(listenerId);
788
+ * ```
789
+ * @example
790
+ * This example creates a Store, a Relationships object, and then registers a
791
+ * listener that responds to any changes to any remote Row's local Row
792
+ * objects.
793
+ *
794
+ * ```tsx
795
+ * const store = createStore()
796
+ * .setTable('pets', {
797
+ * fido: {species: 'dog', color: 'brown'},
798
+ * felix: {species: 'cat', color: 'black'},
799
+ * cujo: {species: 'dog', color: 'brown'},
800
+ * toto: {species: 'dog', color: 'grey'},
801
+ * })
802
+ * .setTable('species', {
803
+ * wolf: {price: 10},
804
+ * dog: {price: 5},
805
+ * cat: {price: 4},
806
+ * })
807
+ * .setTable('color', {
808
+ * brown: {discount: 0.1},
809
+ * black: {discount: 0},
810
+ * grey: {discount: 0.2},
811
+ * });
812
+ *
813
+ * const relationships = createRelationships(store)
814
+ * .setRelationshipDefinition('petSpecies', 'pets', 'species', 'species')
815
+ * .setRelationshipDefinition('petColor', 'pets', 'color', 'color');
816
+ *
817
+ * const listenerId = relationships.addLocalRowIdsListener(
818
+ * null,
819
+ * null,
820
+ * (relationships, relationshipId, remoteRowId) => {
821
+ * console.log(
822
+ * `${relationshipId} relationship (to ${remoteRowId}) changed`,
823
+ * );
824
+ * console.log(relationships.getLocalRowIds(relationshipId, remoteRowId));
825
+ * },
826
+ * );
827
+ *
828
+ * store.setRow('pets', 'cujo', {species: 'wolf', color: 'grey'});
829
+ * // -> 'petSpecies relationship (to dog) changed'
830
+ * // -> ['fido', 'toto']
831
+ * // -> 'petSpecies relationship (to wolf) changed'
832
+ * // -> ['cujo']
833
+ * // -> 'petColor relationship (to brown) changed'
834
+ * // -> ['fido']
835
+ * // -> 'petColor relationship (to grey) changed'
836
+ * // -> ['toto', 'cujo']
837
+ *
838
+ * relationships.delListener(listenerId);
839
+ * ```
840
+ * @category Listener
841
+ */
842
+ addLocalRowIdsListener(
843
+ relationshipId: IdOrNull,
844
+ remoteRowId: IdOrNull,
845
+ listener: LocalRowIdsListener,
846
+ ): Id;
847
+
848
+ /**
849
+ * The addLinkedRowIdsListener method registers a listener function with the
850
+ * Relationships object that will be called whenever the linked Row Ids in a
851
+ * linked list Relationship change.
852
+ *
853
+ * A linked list Relationship is one that has the same Table specified as both
854
+ * local Table Id and remote Table Id, allowing you to create a sequence of
855
+ * Row objects within that one Table.
856
+ *
857
+ * You listen to changes to a linked list starting from a single first Row by
858
+ * specifying the Relationship Id and local Row Id as the method's first two
859
+ * parameters.
860
+ *
861
+ * Unlike other listener registration methods, you cannot provide `null`
862
+ * wildcards for the first two parameters of the addLinkedRowIdsListener
863
+ * method. This prevents the prohibitive expense of tracking all the possible
864
+ * linked lists (and partial linked lists within them) in a Store.
865
+ *
866
+ * The provided listener is a LinkedRowIdsListener function, and will be
867
+ * called with a reference to the Relationships object, the Id of the
868
+ * Relationship, and the Id of the first Row that had its linked list change.
869
+ *
870
+ * @param relationshipId The Id of the Relationship to listen to.
871
+ * @param firstRowId The Id of the first Row of the linked list to listen to.
872
+ * @param listener The function that will be called whenever the linked Row
873
+ * Ids change.
874
+ * @returns A unique Id for the listener that can later be used to remove it.
875
+ * @example
876
+ * This example creates a Store, a Relationships object, and then registers a
877
+ * listener that responds to any changes to a specific first Row's linked Row
878
+ * objects.
879
+ *
880
+ * ```tsx
881
+ * const store = createStore().setTable('pets', {
882
+ * fido: {species: 'dog', next: 'felix'},
883
+ * felix: {species: 'cat', next: 'cujo'},
884
+ * cujo: {species: 'dog'},
885
+ * });
886
+ *
887
+ * const relationships = createRelationships(store);
888
+ * relationships.setRelationshipDefinition(
889
+ * 'petSequence',
890
+ * 'pets',
891
+ * 'pets',
892
+ * 'next',
893
+ * );
894
+ *
895
+ * const listenerId = relationships.addLinkedRowIdsListener(
896
+ * 'petSequence',
897
+ * 'fido',
898
+ * (relationships, relationshipId, firstRowId) => {
899
+ * console.log('petSequence linked list (from fido) changed');
900
+ * console.log(relationships.getLinkedRowIds('petSequence', 'fido'));
901
+ * },
902
+ * );
903
+ *
904
+ * store.setRow('pets', 'toto', {species: 'dog'});
905
+ * store.setCell('pets', 'cujo', 'next', 'toto');
906
+ * // -> 'petSequence linked list (from fido) changed'
907
+ * // -> ['fido', 'felix', 'cujo', 'toto']
908
+ *
909
+ * relationships.delListener(listenerId);
910
+ * ```
911
+ * @category Listener
912
+ */
913
+ addLinkedRowIdsListener(
914
+ relationshipId: Id,
915
+ firstRowId: Id,
916
+ listener: LinkedRowIdsListener,
917
+ ): Id;
918
+
919
+ /**
920
+ * The delListener method removes a listener that was previously added to the
921
+ * Relationships object.
922
+ *
923
+ * Use the Id returned by whichever method was used to add the listener. Note
924
+ * that the Relationships object may re-use this Id for future listeners added
925
+ * to it.
926
+ *
927
+ * @param listenerId The Id of the listener to remove.
928
+ * @returns A reference to the Relationships object.
929
+ * @example
930
+ * This example creates a Store, a Relationships object, registers a listener,
931
+ * and then removes it.
932
+ *
933
+ * ```tsx
934
+ * const store = createStore()
935
+ * .setTable('pets', {
936
+ * fido: {species: 'dog'},
937
+ * felix: {species: 'cat'},
938
+ * cujo: {species: 'dog'},
939
+ * })
940
+ * .setTable('species', {
941
+ * wolf: {price: 10},
942
+ * dog: {price: 5},
943
+ * cat: {price: 4},
944
+ * });
945
+ *
946
+ * const relationships = createRelationships(store);
947
+ * relationships.setRelationshipDefinition(
948
+ * 'petSpecies',
949
+ * 'pets',
950
+ * 'species',
951
+ * 'species',
952
+ * );
953
+ *
954
+ * const listenerId = relationships.addLocalRowIdsListener(
955
+ * 'petSpecies',
956
+ * 'dog',
957
+ * (relationships, relationshipId, remoteRowId) => {
958
+ * console.log('petSpecies relationship (to dog) changed');
959
+ * },
960
+ * );
961
+ *
962
+ * store.setRow('pets', 'toto', {species: 'dog'});
963
+ * // -> 'petSpecies relationship (to dog) changed'
964
+ *
965
+ * relationships.delListener(listenerId);
966
+ *
967
+ * store.setRow('pets', 'toto', {species: 'dog'});
968
+ * // -> undefined
969
+ * // The listener is not called.
970
+ * ```
971
+ * @category Listener
972
+ */
973
+ delListener(listenerId: Id): Relationships;
974
+
975
+ /**
976
+ * The destroy method should be called when this Relationships object is no
977
+ * longer used.
978
+ *
979
+ * This guarantees that all of the listeners that the object registered with
980
+ * the underlying Store are removed and it can be correctly garbage collected.
981
+ *
982
+ * @example
983
+ * This example creates a Store, adds an Relationships object with a
984
+ * definition (that registers a RowListener with the underlying Store),
985
+ * and then destroys it again, removing the listener.
986
+ *
987
+ * ```tsx
988
+ * const store = createStore()
989
+ * .setTable('pets', {
990
+ * fido: {species: 'dog'},
991
+ * felix: {species: 'cat'},
992
+ * cujo: {species: 'dog'},
993
+ * })
994
+ * .setTable('species', {
995
+ * wolf: {price: 10},
996
+ * dog: {price: 5},
997
+ * cat: {price: 4},
998
+ * });
999
+ *
1000
+ * const relationships = createRelationships(store);
1001
+ * relationships.setRelationshipDefinition(
1002
+ * 'petSpecies',
1003
+ * 'pets',
1004
+ * 'species',
1005
+ * 'species',
1006
+ * );
1007
+ * console.log(store.getListenerStats().row);
1008
+ * // -> 1
1009
+ *
1010
+ * relationships.destroy();
1011
+ *
1012
+ * console.log(store.getListenerStats().row);
1013
+ * // -> 0
1014
+ * ```
1015
+ * @category Lifecycle
1016
+ */
1017
+ destroy(): void;
1018
+
1019
+ /**
1020
+ * The getListenerStats method provides a set of statistics about the
1021
+ * listeners registered with the Relationships object, and is used for
1022
+ * debugging purposes.
1023
+ *
1024
+ * The RelationshipsListenerStats object contains a breakdown of the different
1025
+ * types of listener.
1026
+ *
1027
+ * The statistics are only populated in a debug build: production builds
1028
+ * return an empty object. The method is intended to be used during
1029
+ * development to ensure your application is not leaking listener
1030
+ * registrations, for example.
1031
+ *
1032
+ * @returns A RelationshipsListenerStats object containing Relationships
1033
+ * listener statistics.
1034
+ * @example
1035
+ * This example gets the listener statistics of a Relationships object.
1036
+ *
1037
+ * ```tsx
1038
+ * const store = createStore();
1039
+ * const relationships = createRelationships(store);
1040
+ * relationships.addRemoteRowIdListener(null, null, () => {
1041
+ * console.log('Remote Row Id changed');
1042
+ * });
1043
+ * relationships.addLocalRowIdsListener(null, null, () => {
1044
+ * console.log('Local Row Id changed');
1045
+ * });
1046
+ *
1047
+ * const listenerStats = relationships.getListenerStats();
1048
+ * console.log(listenerStats.remoteRowId);
1049
+ * // -> 1
1050
+ * console.log(listenerStats.localRowIds);
1051
+ * // -> 1
1052
+ * ```
1053
+ * @category Development
1054
+ */
1055
+ getListenerStats(): RelationshipsListenerStats;
1056
+ }
1057
+
1058
+ /**
1059
+ * The createRelationships function creates an Relationships object, and is the
1060
+ * main entry point into the relationships module.
1061
+ *
1062
+ * It is trivially simple.
1063
+ *
1064
+ * A given Store can only have one Relationships object associated with it. If
1065
+ * you call this function twice on the same Store, your second call will return
1066
+ * a reference to the Relationships object created by the first.
1067
+ *
1068
+ * @param store The Store for which to register Relationships.
1069
+ * @returns A reference to the new Relationships object.
1070
+ * @example
1071
+ * This example creates an Relationships object.
1072
+ *
1073
+ * ```tsx
1074
+ * const store = createStore();
1075
+ * const relationships = createRelationships(store);
1076
+ * console.log(relationships.getRelationshipIds());
1077
+ * // -> []
1078
+ * ```
1079
+ * @example
1080
+ * This example creates a Relationships object, and calls the method a second
1081
+ * time for the same Store to return the same object.
1082
+ *
1083
+ * ```tsx
1084
+ * const store = createStore();
1085
+ * const relationships1 = createRelationships(store);
1086
+ * const relationships2 = createRelationships(store);
1087
+ * console.log(relationships1 === relationships2);
1088
+ * // -> true
1089
+ * ```
1090
+ */
1091
+ export function createRelationships(store: Store): Relationships;