Skip to content

Commit 9151a25

Browse files
committed
[relationships] Add forEachRelationship method
1 parent 774d32c commit 9151a25

File tree

4 files changed

+95
-3
lines changed

4 files changed

+95
-3
lines changed

src/relationships.d.ts

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* @module relationships
1212
*/
1313

14-
import {GetCell, Store} from './store.d';
14+
import {GetCell, RowCallback, Store} from './store.d';
1515
import {Id, IdOrNull, Ids} from './common.d';
1616

1717
/**
@@ -39,6 +39,25 @@ export type Relationship = {
3939
linkedRowIds: {[firstRowId: Id]: Ids};
4040
};
4141

42+
/**
43+
* The RelationshipCallback type describes a function that takes an
44+
* Relationship's Id and a callback to loop over each local Row within it.
45+
*
46+
* A RelationshipCallback is provided when using the forEachRelationship method,
47+
* so that you can do something based on every Relationship in the Relationships
48+
* object. See that method for specific examples.
49+
*
50+
* @param relationshipId The Id of the Relationship that the callback can
51+
* operate on.
52+
* @param forEachRow A function that will let you iterate over the local Row
53+
* objects in this Relationship.
54+
* @category Callback
55+
*/
56+
export type RelationshipCallback = (
57+
relationshipId: Id,
58+
forEachRow: (rowCallback: RowCallback) => void,
59+
) => void;
60+
4261
/**
4362
* The RemoteRowIdListener type describes a function that is used to listen to
4463
* changes to the remote Row Id end of a Relationship.
@@ -405,6 +424,49 @@ export interface Relationships {
405424
*/
406425
getRelationshipIds(): Ids;
407426

427+
/**
428+
* The forEachRelationship method takes a function that it will then call for
429+
* each Relationship in a specified Relationships object.
430+
*
431+
* This method is useful for iterating over the structure of the Relationships
432+
* object in a functional style. The `relationshipCallback` parameter is a
433+
* RelationshipCallback function that will be called with the Id of each
434+
* Relationship, and with a function that can then be used to iterate over
435+
* each local Row involved in the Relationship.
436+
*
437+
* @param relationshipCallback The function that should be called for every
438+
* Relationship.
439+
* @example
440+
* This example iterates over each Relationship in a Relationships object, and
441+
* lists each Row Id within them.
442+
*
443+
* ```js
444+
* const store = createStore().setTable('pets', {
445+
* fido: {species: 'dog', next: 'felix'},
446+
* felix: {species: 'cat', next: 'cujo'},
447+
* cujo: {species: 'dog'},
448+
* });
449+
* const relationships = createRelationships(store)
450+
* .setRelationshipDefinition('petSpecies', 'pets', 'species', 'species')
451+
* .setRelationshipDefinition('petSequence', 'pets', 'pets', 'next');
452+
*
453+
* relationships.forEachRelationship((relationshipId, forEachRow) => {
454+
* console.log(relationshipId);
455+
* forEachRow((rowId) => console.log(`- ${rowId}`));
456+
* });
457+
* // -> 'petSpecies'
458+
* // -> '- fido'
459+
* // -> '- felix'
460+
* // -> '- cujo'
461+
* // -> 'petSequence'
462+
* // -> '- fido'
463+
* // -> '- felix'
464+
* // -> '- cujo'
465+
* ```
466+
* @category Iterator
467+
*/
468+
forEachRelationship(relationshipCallback: RelationshipCallback): void;
469+
408470
/**
409471
* The hasRelationship method returns a boolean indicating whether a given
410472
* Relationship exists in the Relationships object.

src/relationships.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {IdSet, IdSet3, setAdd, setNew} from './common/set';
66
import {
77
LinkedRowIdsListener,
88
LocalRowIdsListener,
9+
RelationshipCallback,
910
Relationships,
1011
RelationshipsListenerStats,
1112
RemoteRowIdListener,
@@ -39,7 +40,7 @@ export const createRelationships: typeof createRelationshipsDecl =
3940
const [
4041
getStore,
4142
getRelationshipIds,
42-
_forEachRelationship,
43+
forEachRelationshipImpl,
4344
hasRelationship,
4445
getLocalTableId,
4546
getRelationship,
@@ -173,6 +174,13 @@ export const createRelationships: typeof createRelationshipsDecl =
173174
return relationships;
174175
};
175176

177+
const forEachRelationship = (relationshipCallback: RelationshipCallback) =>
178+
forEachRelationshipImpl((relationshipId) =>
179+
relationshipCallback(relationshipId, (rowCallback) =>
180+
store.forEachRow(getLocalTableId(relationshipId), rowCallback),
181+
),
182+
);
183+
176184
const delRelationshipDefinition = (relationshipId: Id): Relationships => {
177185
mapSet(remoteTableIds, relationshipId);
178186
delDefinition(relationshipId);
@@ -250,6 +258,7 @@ export const createRelationships: typeof createRelationshipsDecl =
250258

251259
getStore,
252260
getRelationshipIds,
261+
forEachRelationship,
253262
hasRelationship,
254263
getLocalTableId,
255264
getRemoteTableId,

test/unit/common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ export const getRelationshipsObject = (
313313
): IdMap<[IdMap<Id>, IdMap<Ids>]> => {
314314
const store = relationships.getStore();
315315
const relationshipsObject: IdMap<[IdMap<Id>, IdMap<Ids>]> = {};
316-
relationships.getRelationshipIds().forEach((relationshipId) => {
316+
relationships.forEachRelationship((relationshipId) => {
317317
relationshipsObject[relationshipId] = [{}, {}];
318318
store
319319
.getRowIds(relationships.getLocalTableId(relationshipId))

test/unit/relationships.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,27 @@ describe('Miscellaneous', () => {
748748
expectNoChanges(listener);
749749
});
750750

751+
test('forEachRelationship', () => {
752+
relationships
753+
.setRelationshipDefinition('r1', 't1', 'T1', 'c1')
754+
.setRelationshipDefinition('r2', 't1', 'T1', 'c2');
755+
setCells();
756+
const eachRelationship: any = {};
757+
relationships.forEachRelationship((relationshipsId, forEachRow) => {
758+
const eachRow: any = {};
759+
forEachRow((rowId, forEachCell) => {
760+
const eachCell: any = {};
761+
forEachCell((cellId, cell) => (eachCell[cellId] = cell));
762+
eachRow[rowId] = eachCell;
763+
});
764+
eachRelationship[relationshipsId] = eachRow;
765+
});
766+
expect(eachRelationship).toEqual({
767+
r1: {r1: {c1: 'R3', c2: 'R1'}, r2: {c1: 'R2', c2: 'R2'}},
768+
r2: {r1: {c1: 'R3', c2: 'R1'}, r2: {c1: 'R2', c2: 'R2'}},
769+
});
770+
});
771+
751772
test('are things present', () => {
752773
expect(relationships.hasRelationship('r1')).toEqual(false);
753774
relationships.setRelationshipDefinition('r1', 't1', 'T1', 'c1');

0 commit comments

Comments
 (0)