Skip to content
This repository has been archived by the owner on Apr 15, 2020. It is now read-only.

Commit

Permalink
fix(stitching): map errors along schema transformation path when extr…
Browse files Browse the repository at this point in the history
…acting fields
  • Loading branch information
yaacovCR committed Aug 18, 2019
1 parent f308443 commit c132142
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 21 deletions.
36 changes: 31 additions & 5 deletions src/stitching/createMergedResolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { GraphQLObjectType, getNamedType, responsePathAsArray } from 'graphql';
import { IFieldResolver } from '../Interfaces';
import { defaultMergedResolver } from '../stitching';
import { GraphQLObjectType } from 'graphql';
import {
relocatedError,
combineErrors,
getErrorsFromParent,
annotateWithChildrenErrors,
} from './errors';
import defaultMergedResolver from './defaultMergedResolver';
import { extractOneLevelOfFields } from './extractFields';

export function wrapField(wrapper: string, fieldName: string): IFieldResolver<any, any> {
Expand Down Expand Up @@ -31,8 +37,8 @@ export function createMergedResolver({

toPath.forEach(pathSegment => {
fieldNodes = extractOneLevelOfFields(fieldNodes, pathSegment, info.fragments);
parentType = returnType as GraphQLObjectType;
returnType = (returnType as GraphQLObjectType).getFields()[pathSegment].type;
parentType = getNamedType(returnType) as GraphQLObjectType;
returnType = (parentType as GraphQLObjectType).getFields()[pathSegment].type;
path = { prev: path, key: pathSegment };
});

Expand All @@ -44,7 +50,27 @@ export function createMergedResolver({

const fromPathLength = fromPath.length;
if (fromPathLength) {
parent = fromPath.slice(0, -1).reduce((p, pathSegment) => p[pathSegment], parent);
const fromParentPathLength = fromPathLength - 1;

for (let i = 0; i < fromParentPathLength; i++) {
const responseKey = fromPath[i];
const errors = getErrorsFromParent(parent, responseKey);
const result = parent[responseKey];
if (result == null) {
if (errors.length) {
throw relocatedError(
combineErrors(errors),
fieldNodes,
responsePathAsArray(path)
);
} else {
return null;
}
}
annotateWithChildrenErrors(result, errors);
parent = result;
}

fieldName = fromPath[fromPathLength - 1];
}

Expand Down
111 changes: 95 additions & 16 deletions src/test/testAlternateMergeSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
GraphQLScalarType,
FieldNode,
printSchema,
ExecutableDefinitionNode,
Kind,
} from 'graphql';
import {
transformSchema,
Expand Down Expand Up @@ -46,9 +46,35 @@ import {
} from '../stitching';
import { SchemaExecutionConfig } from '../Interfaces';

const toFieldNode =
(raw: string) =>
((parse(`{ ${raw} }`).definitions[0] as ExecutableDefinitionNode).selectionSet.selections[0]);
function renameFieldNode(fieldNode: FieldNode, name: string): FieldNode {
return {
...fieldNode,
name: {
...fieldNode.name,
value: name,
}
};
}

function wrapFieldNode(fieldNode: FieldNode, path: Array<string>): FieldNode {
let newFieldNode = fieldNode;
path.forEach(fieldName => {
newFieldNode = {
kind: Kind.FIELD,
name: {
kind: Kind.NAME,
value: fieldName,
},
selectionSet: {
kind: Kind.SELECTION_SET,
selections: [
fieldNode,
]
}
};
});
return newFieldNode;
}

let linkSchema = `
"""
Expand Down Expand Up @@ -581,25 +607,78 @@ describe('schema transformation with extraction of nested fields', () => {
extend type Property {
locationName: String
locationName2: String
pseudoWrappedError: String
}
`,
resolvers: {
Property: {
locationName: createMergedResolver({ fromPath: ['location', 'name'] }),
//deprecated wrapField shorthand
locationName2: wrapField('location', 'name'),
pseudoWrappedError: createMergedResolver({ fromPath: ['error', 'name'] }),
},
},
fieldNodeTransformerMap: {
'Property': {
'locationName': () => toFieldNode('location { name }'),
'locationName2': () => toFieldNode('location { name }'),
'locationName':
fieldNode => wrapFieldNode(renameFieldNode(fieldNode, 'name'), ['location']),
'locationName2':
fieldNode => wrapFieldNode(renameFieldNode(fieldNode, 'name'), ['location']),
'pseudoWrappedError': fieldNode => renameFieldNode(fieldNode, 'error'),
},
},
}),
]);
});

it('should work to extract a field', async () => {
const result = await graphql(
transformedPropertySchema,
`
query($pid: ID!) {
propertyById(id: $pid) {
test1: locationName
test2: locationName2
pseudoWrappedError
}
}
`,
{},
{},
{
pid: 'p1',
},
);

expect(result).to.deep.equal({
data: {
propertyById: {
test1: 'Helsinki',
test2: 'Helsinki',
pseudoWrappedError: null,
},
},
errors: [
{
extensions: {
code: 'SOME_CUSTOM_CODE',
},
locations: [
{
column: 13,
line: 6,
},
],
message: 'Property.error error',
path: [
'propertyById',
'pseudoWrappedError',
],
},
]
});
});

it('should work to extract a field', async () => {
const result = await graphql(
transformedPropertySchema,
Expand Down Expand Up @@ -759,8 +838,8 @@ describe('schema transformation with renaming of object fields', () => {
},
fieldNodeTransformerMap: {
'Property': {
'new_error': () => toFieldNode('error'),
'new_error2': () => toFieldNode('error'),
'new_error': fieldNode => renameFieldNode(fieldNode, 'error'),
'new_error2': fieldNode => renameFieldNode(fieldNode, 'error'),
},
},
}),
Expand Down Expand Up @@ -799,12 +878,12 @@ describe('schema transformation with renaming of object fields', () => {
},
locations: [
{
column: 3,
line: 1,
column: 13,
line: 4,
},
{
column: 3,
line: 1,
column: 13,
line: 5,
},
],
message: 'Property.error error',
Expand All @@ -819,12 +898,12 @@ describe('schema transformation with renaming of object fields', () => {
},
locations: [
{
column: 3,
line: 1,
column: 13,
line: 4,
},
{
column: 3,
line: 1,
column: 13,
line: 5,
},
],
message: 'Property.error error',
Expand Down

0 comments on commit c132142

Please sign in to comment.