Skip to content

Commit

Permalink
allow fully sync abstract type resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
dherault committed Dec 23, 2016
1 parent 164cd31 commit 7d4cd4b
Showing 1 changed file with 105 additions and 64 deletions.
169 changes: 105 additions & 64 deletions src/execution/execute.js
Original file line number Diff line number Diff line change
Expand Up @@ -940,53 +940,126 @@ function completeAbstractValue(
path: ResponsePath,
result: mixed
): mixed {
const runtimeTypePromise = returnType.resolveType ?
Promise.resolve(returnType.resolveType(
const runtimeType = returnType.resolveType ?
returnType.resolveType(
result,
exeContext.contextValue,
info
)) :
) :
resolveFirstValidType(
result,
exeContext.contextValue,
info,
info.schema.getPossibleTypes(returnType)
);

return runtimeTypePromise.then(type => {
let runtimeType = type;
if (isThenable(runtimeType)) {
return ((runtimeType: any): Promise<*>).then(resolvedRuntimeType => (
validateRuntimeTypeAndCompleteObjectValue(
exeContext,
returnType,
fieldNodes,
info,
path,
resolvedRuntimeType,
result
)
));
}

// If resolveType returns a string, we assume it's a GraphQLObjectType name.
if (typeof runtimeType === 'string') {
runtimeType = exeContext.schema.getType(runtimeType);
}
return validateRuntimeTypeAndCompleteObjectValue(
exeContext,
returnType,
fieldNodes,
info,
path,
runtimeType,
result
);
}

if (!(runtimeType instanceof GraphQLObjectType)) {
throw new GraphQLError(
`Abstract type ${returnType.name} must resolve to an Object type at ` +
`runtime for field ${info.parentType.name}.${info.fieldName} with ` +
`value "${String(result)}", received "${String(runtimeType)}".`,
fieldNodes
);
}
function validateRuntimeTypeAndCompleteObjectValue(
exeContext: ExecutionContext,
returnType: GraphQLAbstractType,
fieldNodes: Array<FieldNode>,
info: GraphQLResolveInfo,
path: ResponsePath,
returnedRuntimeType: mixed,
result: mixed
): mixed {
let runtimeType = returnedRuntimeType;

if (!exeContext.schema.isPossibleType(returnType, runtimeType)) {
throw new GraphQLError(
`Runtime Object type "${runtimeType.name}" is not a possible type ` +
`for "${returnType.name}".`,
fieldNodes
);
}
// If resolveType returns a string, we assume it's a GraphQLObjectType name.
if (typeof runtimeType === 'string') {
runtimeType = exeContext.schema.getType(runtimeType);
}

return completeObjectValue(
exeContext,
runtimeType,
fieldNodes,
info,
path,
result
if (!(runtimeType instanceof GraphQLObjectType)) {
throw new GraphQLError(
`Abstract type ${returnType.name} must resolve to an Object type at ` +
`runtime for field ${info.parentType.name}.${info.fieldName} with ` +
`value "${String(result)}", received "${String(runtimeType)}".`,
fieldNodes
);
});
}

if (!exeContext.schema.isPossibleType(returnType, runtimeType)) {
throw new GraphQLError(
`Runtime Object type "${runtimeType.name}" is not a possible type ` +
`for "${returnType.name}".`,
fieldNodes
);
}

return completeObjectValue(
exeContext,
runtimeType,
fieldNodes,
info,
path,
result
);
}

/**
* If a resolveType function is not given, then a default resolve behavior is
* used which tests each possible type for the abstract type by calling
* isTypeOf for the object being coerced, returning the first type that matches.
*/
function resolveFirstValidType(
value: mixed,
context: mixed,
info: GraphQLResolveInfo,
possibleTypes: Array<GraphQLObjectType>,
i: number = 0,
): ?GraphQLObjectType | ?string | ?Promise<?GraphQLObjectType | ?string> {
if (i >= possibleTypes.length) {
return null;
}

const type = possibleTypes[i];

if (!type.isTypeOf) {
return resolveFirstValidType(value, context, info, possibleTypes, i + 1);
}

const isCorrectType = type.isTypeOf(value, context, info);

if (isThenable(isCorrectType)) {
return ((isCorrectType: any): Promise<*>).then(result => {
if (result) {
return type;
}

return resolveFirstValidType(value, context, info, possibleTypes, i + 1);
});
}

if (isCorrectType) {
return type;
}

return resolveFirstValidType(value, context, info, possibleTypes, i + 1);
}

/**
Expand Down Expand Up @@ -1036,38 +1109,6 @@ function completeObjectValue(
});
}

/**
* If a resolveType function is not given, then a default resolve behavior is
* used which tests each possible type for the abstract type by calling
* isTypeOf for the object being coerced, returning the first type that matches.
*/
function resolveFirstValidType(
value: mixed,
context: mixed,
info: GraphQLResolveInfo,
possibleTypes: Array<GraphQLObjectType>,
i: number = 0,
): Promise<?GraphQLObjectType | ?string> {
if (i >= possibleTypes.length) {
return Promise.resolve(null);
}

const type = possibleTypes[i];

if (!type.isTypeOf) {
return resolveFirstValidType(value, context, info, possibleTypes, i + 1);
}

return Promise.resolve(type.isTypeOf(value, context, info))
.then(result => {
if (result) {
return type;
}

return resolveFirstValidType(value, context, info, possibleTypes, i + 1);
});
}

/**
* If a resolve function is not given, then a default resolve behavior is used
* which takes the property of the source object of the same name as the field
Expand Down

0 comments on commit 7d4cd4b

Please sign in to comment.