Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/execution/__tests__/executor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ describe('Execute: Handles basic execution tasks', () => {
);
expect(info.returnType).to.equal(GraphQLString);
expect(info.parentType).to.equal(schema.getQueryType());
expect(info.path).to.deep.equal([ 'result' ]);
expect(info.path).to.deep.equal({ prev: undefined, key: 'result' });
expect(info.schema).to.equal(schema);
expect(info.rootValue).to.equal(rootValue);
expect(info.operation).to.equal(ast.definitions[0]);
Expand Down
54 changes: 39 additions & 15 deletions src/execution/execute.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import type {
GraphQLField,
GraphQLFieldResolver,
GraphQLResolveInfo,
ResponsePath,
} from '../type/definition';
import { GraphQLSchema } from '../type/schema';
import {
Expand Down Expand Up @@ -168,6 +169,27 @@ export function execute(
});
}

/**
* Given a ResponsePath (found in the `path` entry in the information provided
* as the last argument to a field resolver), return an Array of the path keys.
*/
export function responsePathAsArray(
path: ResponsePath
): Array<string | number> {
const flattened = [];
let curr = path;
while (curr) {
flattened.push(curr.key);
curr = curr.prev;
}
return flattened.reverse();
}


function addPath(prev: ResponsePath, key: string | number) {
return { prev, key };
}

/**
* Constructs a ExecutionContext object from the arguments passed to
* execute, which we will pass throughout the other execution methods.
Expand Down Expand Up @@ -249,7 +271,7 @@ function executeOperation(
Object.create(null)
);

const path = [];
const path = undefined;

if (operation.operation === 'mutation') {
return executeFieldsSerially(exeContext, type, rootValue, path, fields);
Expand Down Expand Up @@ -301,13 +323,13 @@ function executeFieldsSerially(
exeContext: ExecutionContext,
parentType: GraphQLObjectType,
sourceValue: mixed,
path: Array<string | number>,
path: ResponsePath,
fields: {[key: string]: Array<FieldNode>}
): Promise<{[key: string]: mixed}> {
return Object.keys(fields).reduce(
(prevPromise, responseName) => prevPromise.then(results => {
const fieldNodes = fields[responseName];
const fieldPath = path.concat([ responseName ]);
const fieldPath = addPath(path, responseName);
const result = resolveField(
exeContext,
parentType,
Expand Down Expand Up @@ -339,15 +361,15 @@ function executeFields(
exeContext: ExecutionContext,
parentType: GraphQLObjectType,
sourceValue: mixed,
path: Array<string | number>,
path: ResponsePath,
fields: {[key: string]: Array<FieldNode>}
): {[key: string]: mixed} {
let containsPromise = false;

const finalResults = Object.keys(fields).reduce(
(results, responseName) => {
const fieldNodes = fields[responseName];
const fieldPath = path.concat([ responseName ]);
const fieldPath = addPath(path, responseName);
const result = resolveField(
exeContext,
parentType,
Expand Down Expand Up @@ -547,7 +569,7 @@ function resolveField(
parentType: GraphQLObjectType,
source: mixed,
fieldNodes: Array<FieldNode>,
path: Array<string | number>
path: ResponsePath
): mixed {
const fieldNode = fieldNodes[0];
const fieldName = fieldNode.name.value;
Expand Down Expand Up @@ -638,7 +660,7 @@ function completeValueCatchingError(
returnType: GraphQLType,
fieldNodes: Array<FieldNode>,
info: GraphQLResolveInfo,
path: Array<string | number>,
path: ResponsePath,
result: mixed
): mixed {
// If the field type is non-nullable, then it is resolved without any
Expand Down Expand Up @@ -691,7 +713,7 @@ function completeValueWithLocatedError(
returnType: GraphQLType,
fieldNodes: Array<FieldNode>,
info: GraphQLResolveInfo,
path: Array<string | number>,
path: ResponsePath,
result: mixed
): mixed {
try {
Expand All @@ -706,12 +728,14 @@ function completeValueWithLocatedError(
if (isThenable(completed)) {
return ((completed: any): Promise<*>).then(
undefined,
error => Promise.reject(locatedError(error, fieldNodes, path))
error => Promise.reject(
locatedError(error, fieldNodes, responsePathAsArray(path))
)
);
}
return completed;
} catch (error) {
throw locatedError(error, fieldNodes, path);
throw locatedError(error, fieldNodes, responsePathAsArray(path));
}
}

Expand Down Expand Up @@ -741,7 +765,7 @@ function completeValue(
returnType: GraphQLType,
fieldNodes: Array<FieldNode>,
info: GraphQLResolveInfo,
path: Array<string | number>,
path: ResponsePath,
result: mixed
): mixed {
// If result is a Promise, apply-lift over completeValue.
Expand Down Expand Up @@ -848,7 +872,7 @@ function completeListValue(
returnType: GraphQLList<*>,
fieldNodes: Array<FieldNode>,
info: GraphQLResolveInfo,
path: Array<string | number>,
path: ResponsePath,
result: mixed
): mixed {
invariant(
Expand All @@ -865,7 +889,7 @@ function completeListValue(
forEach((result: any), (item, index) => {
// No need to modify the info object containing the path,
// since from here on it is not ever accessed by resolver functions.
const fieldPath = path.concat([ index ]);
const fieldPath = addPath(path, index);
const completedItem = completeValueCatchingError(
exeContext,
itemType,
Expand Down Expand Up @@ -912,7 +936,7 @@ function completeAbstractValue(
returnType: GraphQLAbstractType,
fieldNodes: Array<FieldNode>,
info: GraphQLResolveInfo,
path: Array<string | number>,
path: ResponsePath,
result: mixed
): mixed {
let runtimeType = returnType.resolveType ?
Expand Down Expand Up @@ -959,7 +983,7 @@ function completeObjectValue(
returnType: GraphQLObjectType,
fieldNodes: Array<FieldNode>,
info: GraphQLResolveInfo,
path: Array<string | number>,
path: ResponsePath,
result: mixed
): mixed {
// If there is an isTypeOf predicate function, call it with the
Expand Down
2 changes: 1 addition & 1 deletion src/execution/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/

export { execute, defaultFieldResolver } from './execute';
export { execute, defaultFieldResolver, responsePathAsArray } from './execute';

export type { ExecutionResult } from './execute';
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export type {
GraphQLIsTypeOfFn,
GraphQLObjectTypeConfig,
GraphQLResolveInfo,
ResponsePath,
GraphQLScalarTypeConfig,
GraphQLTypeResolver,
GraphQLUnionTypeConfig,
Expand Down Expand Up @@ -224,6 +225,7 @@ export type {
export {
execute,
defaultFieldResolver,
responsePathAsArray,
} from './execution';

export type {
Expand Down
4 changes: 3 additions & 1 deletion src/type/definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -491,14 +491,16 @@ export type GraphQLResolveInfo = {
fieldNodes: Array<FieldNode>;
returnType: GraphQLOutputType;
parentType: GraphQLCompositeType;
path: Array<string | number>;
path: ResponsePath;
schema: GraphQLSchema;
fragments: { [fragmentName: string]: FragmentDefinitionNode };
rootValue: mixed;
operation: OperationDefinitionNode;
variableValues: { [variableName: string]: mixed };
};

export type ResponsePath = { prev: ResponsePath, key: string | number } | void;

export type GraphQLFieldConfig<TSource> = {
type: GraphQLOutputType;
args?: GraphQLFieldConfigArgumentMap;
Expand Down
1 change: 1 addition & 0 deletions src/type/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export type {
GraphQLIsTypeOfFn,
GraphQLObjectTypeConfig,
GraphQLResolveInfo,
ResponsePath,
GraphQLScalarTypeConfig,
GraphQLTypeResolver,
GraphQLUnionTypeConfig,
Expand Down