Skip to content

Commit

Permalink
Fix deeply embedded entity relations not mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
sgarner committed Aug 21, 2020
1 parent a348308 commit d07e696
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 6 deletions.
38 changes: 36 additions & 2 deletions src/RelationMapper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ describe('RelationMapper', () => {
owner {
id
name
address {
street
country {
id
name
}
}
}
}
}
Expand All @@ -123,7 +130,13 @@ describe('RelationMapper', () => {
const resolveInfoHook = (info: GraphQLResolveInfo): void => {
const relations = new RelationMapper(connection).buildRelationListForQuery(Product, info);

expect([...relations]).toEqual(['owner', 'owner.address.country', 'store', 'store.owner']);
expect([...relations]).toEqual([
'owner',
'owner.address.country',
'store',
'store.owner',
'store.owner.address.country',
]);
};
const result = await graphql(executableSchema, query, {}, { resolveInfoHook });

Expand Down Expand Up @@ -155,6 +168,13 @@ describe('RelationMapper', () => {
owner: {
id: expect.any(Number),
name: mockData.ownerA.name,
address: {
street: mockData.ownerA.address.street,
country: {
id: mockData.countryA.id,
name: mockData.countryA.name,
},
},
},
},
},
Expand All @@ -178,6 +198,13 @@ describe('RelationMapper', () => {
fragment OwnerFragment on Owner {
id
name
address {
street
country {
id
name
}
}
}
fragment StoreFragment on Store {
Expand All @@ -199,7 +226,7 @@ describe('RelationMapper', () => {
const resolveInfoHook = (info: GraphQLResolveInfo): void => {
const relations = new RelationMapper(connection).buildRelationListForQuery(Product, info);

expect([...relations]).toEqual(['owner', 'store', 'store.owner']);
expect([...relations]).toEqual(['owner', 'owner.address.country', 'store', 'store.owner']);
};
const result = await graphql(executableSchema, query, {}, { resolveInfoHook });

Expand All @@ -217,6 +244,13 @@ describe('RelationMapper', () => {
owner: {
id: expect.any(Number),
name: mockData.ownerA.name,
address: {
street: mockData.ownerA.address.street,
country: {
id: mockData.countryA.id,
name: mockData.countryA.name,
},
},
},
store: {
id: expect.any(Number),
Expand Down
12 changes: 8 additions & 4 deletions src/RelationMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class RelationMapper {
baseNode: SelectionNode,
fragments?: { [p: string]: FragmentDefinitionNode },
basePropertyPath?: string,
currentLevel: number = 0,
): Set<string> {
const relationNames = new Set<string>();
const selectionSet = this.getSelectionSetFromNode(baseNode, fragments);
Expand All @@ -43,17 +44,18 @@ export class RelationMapper {
selectionSet.selections.forEach((selectionNode: SelectionNode) => {
const currentPropertyPath: string[] = (basePropertyPath ?? '').split('.').filter(path => path !== '');
let currentTargetEntity = entity;
let nextLevel: number = currentLevel;

const nodeName = this.getNameFromNode(selectionNode);

// when the node has a name (i.e. is not an inline fragment), we can look for relations to map
if (nodeName != null) {
// remove first element from path (the path of this field on the entity should not include the entity itself)
const currentPropertyPathExcludingFirstElement = [...currentPropertyPath];
currentPropertyPathExcludingFirstElement.shift();
// remove elements from path up to the level of the current entity
const currentPropertyPathExcludingEntity = [...currentPropertyPath];
currentPropertyPathExcludingEntity.splice(0, currentLevel);

// then add the current node name to the end of the path
const propPath = [...currentPropertyPathExcludingFirstElement, nodeName].join('.');
const propPath = [...currentPropertyPathExcludingEntity, nodeName].join('.');

// find relation or embedded entity metadata, if field corresponds to such a property on the entity
const propMetadata =
Expand All @@ -63,6 +65,7 @@ export class RelationMapper {
if (propMetadata != null) {
if (propMetadata instanceof RelationMetadata) {
currentTargetEntity = propMetadata.inverseEntityMetadata.target;
nextLevel = currentLevel + 1;
currentPropertyPath.push(propMetadata.propertyName);
relationNames.add(currentPropertyPath.join('.'));
} else if (propMetadata instanceof EmbeddedMetadata) {
Expand All @@ -82,6 +85,7 @@ export class RelationMapper {
selectionNode,
fragments,
currentPropertyPath.join('.'),
nextLevel,
);
nestedRelations.forEach(nestedRelation => relationNames.add(nestedRelation));
});
Expand Down

0 comments on commit d07e696

Please sign in to comment.