Skip to content

Commit fd308ce

Browse files
committed
Allow providing custom default type resolver
1 parent 898cf20 commit fd308ce

File tree

5 files changed

+78
-4
lines changed

5 files changed

+78
-4
lines changed

src/execution/__tests__/executor-test.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { execute } from '../execute';
1515
import { Kind, parse } from '../../language';
1616
import {
1717
GraphQLSchema,
18+
GraphQLInterfaceType,
1819
GraphQLObjectType,
1920
GraphQLList,
2021
GraphQLBoolean,
@@ -1029,4 +1030,47 @@ describe('Execute: Handles basic execution tasks', () => {
10291030
const result = execute({ schema, document, fieldResolver });
10301031
expect(result).to.deep.equal({ data: { foo: 'foo' } });
10311032
});
1033+
1034+
it('uses a custom type resolver', () => {
1035+
const document = parse('{ foo { bar } }');
1036+
1037+
const fooInterface = new GraphQLInterfaceType({
1038+
name: 'FooInterface',
1039+
fields: {
1040+
bar: { type: GraphQLString },
1041+
},
1042+
});
1043+
1044+
const fooObject = new GraphQLObjectType({
1045+
name: 'FooObject',
1046+
interfaces: [fooInterface],
1047+
fields: {
1048+
bar: { type: GraphQLString },
1049+
},
1050+
});
1051+
1052+
const schema = new GraphQLSchema({
1053+
query: new GraphQLObjectType({
1054+
name: 'Query',
1055+
fields: {
1056+
foo: { type: fooInterface },
1057+
},
1058+
}),
1059+
types: [fooObject],
1060+
});
1061+
1062+
let possibleTypes;
1063+
function typeResolver(source, context, info, abstractType) {
1064+
// Resolver should be able to figure out all possible types on its own
1065+
possibleTypes = info.schema.getPossibleTypes(abstractType);
1066+
1067+
return 'FooObject';
1068+
}
1069+
1070+
const rootValue = { foo: { bar: 'bar' } };
1071+
const result = execute({ schema, document, rootValue, typeResolver });
1072+
1073+
expect(result).to.deep.equal({ data: { foo: { bar: 'bar' } } });
1074+
expect(possibleTypes).to.deep.equal([fooObject]);
1075+
});
10321076
});

src/execution/execute.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export type ExecutionContext = {|
103103
operation: OperationDefinitionNode,
104104
variableValues: { [variable: string]: mixed },
105105
fieldResolver: GraphQLFieldResolver<any, any>,
106+
typeResolver: GraphQLTypeResolver<any, any>,
106107
errors: Array<GraphQLError>,
107108
|};
108109

@@ -125,6 +126,7 @@ export type ExecutionArgs = {|
125126
variableValues?: ?{ [variable: string]: mixed },
126127
operationName?: ?string,
127128
fieldResolver?: ?GraphQLFieldResolver<any, any>,
129+
typeResolver?: ?GraphQLTypeResolver<any, any>,
128130
|};
129131

130132
/**
@@ -152,6 +154,7 @@ declare function execute(
152154
variableValues?: ?{ [variable: string]: mixed },
153155
operationName?: ?string,
154156
fieldResolver?: ?GraphQLFieldResolver<any, any>,
157+
typeResolver?: ?GraphQLTypeResolver<any, any>,
155158
): MaybePromise<ExecutionResult>;
156159
export function execute(
157160
argsOrSchema,
@@ -161,6 +164,7 @@ export function execute(
161164
variableValues,
162165
operationName,
163166
fieldResolver,
167+
typeResolver,
164168
) {
165169
/* eslint-enable no-redeclare */
166170
// Extract arguments from object args if provided.
@@ -173,6 +177,7 @@ export function execute(
173177
argsOrSchema.variableValues,
174178
argsOrSchema.operationName,
175179
argsOrSchema.fieldResolver,
180+
argsOrSchema.typeResolver,
176181
)
177182
: executeImpl(
178183
argsOrSchema,
@@ -182,6 +187,7 @@ export function execute(
182187
variableValues,
183188
operationName,
184189
fieldResolver,
190+
typeResolver,
185191
);
186192
}
187193

@@ -193,6 +199,7 @@ function executeImpl(
193199
variableValues,
194200
operationName,
195201
fieldResolver,
202+
typeResolver,
196203
) {
197204
// If arguments are missing or incorrect, throw an error.
198205
assertValidExecutionArguments(schema, document, variableValues);
@@ -207,6 +214,7 @@ function executeImpl(
207214
variableValues,
208215
operationName,
209216
fieldResolver,
217+
typeResolver,
210218
);
211219

212220
// Return early errors if execution context failed.
@@ -302,6 +310,7 @@ export function buildExecutionContext(
302310
rawVariableValues: ?ObjMap<mixed>,
303311
operationName: ?string,
304312
fieldResolver: ?GraphQLFieldResolver<any, any>,
313+
typeResolver?: ?GraphQLTypeResolver<any, any>,
305314
): $ReadOnlyArray<GraphQLError> | ExecutionContext {
306315
const errors: Array<GraphQLError> = [];
307316
let operation: OperationDefinitionNode | void;
@@ -372,6 +381,7 @@ export function buildExecutionContext(
372381
operation,
373382
variableValues,
374383
fieldResolver: fieldResolver || defaultFieldResolver,
384+
typeResolver: typeResolver || defaultTypeResolver,
375385
errors,
376386
};
377387
}
@@ -992,7 +1002,7 @@ function completeAbstractValue(
9921002
path: ResponsePath,
9931003
result: mixed,
9941004
): MaybePromise<ObjMap<mixed>> {
995-
const resolveTypeFn = returnType.resolveType || defaultResolveType;
1005+
const resolveTypeFn = returnType.resolveType || exeContext.typeResolver;
9961006
const contextValue = exeContext.contextValue;
9971007
const runtimeType = resolveTypeFn(result, contextValue, info, returnType);
9981008

@@ -1175,7 +1185,7 @@ function _collectSubfields(
11751185
* Otherwise, test each possible type for the abstract type by calling
11761186
* isTypeOf for the object being coerced, returning the first type that matches.
11771187
*/
1178-
const defaultResolveType: GraphQLTypeResolver<any, *> = function(
1188+
export const defaultTypeResolver: GraphQLTypeResolver<any, *> = function(
11791189
value,
11801190
contextValue,
11811191
info,

src/execution/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77
* @flow strict
88
*/
99

10-
export { execute, defaultFieldResolver, responsePathAsArray } from './execute';
10+
export {
11+
execute,
12+
defaultFieldResolver,
13+
defaultTypeResolver,
14+
responsePathAsArray,
15+
} from './execute';
1116
export { getDirectiveValues } from './values';
1217

1318
export type { ExecutionArgs, ExecutionResult } from './execute';

src/graphql.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import { validate } from './validation/validate';
1313
import { execute } from './execution/execute';
1414
import type { ObjMap } from './jsutils/ObjMap';
1515
import type { Source } from './language/source';
16-
import type { GraphQLFieldResolver } from './type/definition';
16+
import type {
17+
GraphQLFieldResolver,
18+
GraphQLTypeResolver,
19+
} from './type/definition';
1720
import type { GraphQLSchema } from './type/schema';
1821
import type { ExecutionResult } from './execution/execute';
1922
import type { MaybePromise } from './jsutils/MaybePromise';
@@ -61,6 +64,7 @@ export type GraphQLArgs = {|
6164
variableValues?: ?ObjMap<mixed>,
6265
operationName?: ?string,
6366
fieldResolver?: ?GraphQLFieldResolver<any, any>,
67+
typeResolver?: ?GraphQLTypeResolver<any, any>,
6468
|};
6569
declare function graphql(GraphQLArgs, ..._: []): Promise<ExecutionResult>;
6670
/* eslint-disable no-redeclare */
@@ -72,6 +76,7 @@ declare function graphql(
7276
variableValues?: ?ObjMap<mixed>,
7377
operationName?: ?string,
7478
fieldResolver?: ?GraphQLFieldResolver<any, any>,
79+
typeResolver?: ?GraphQLTypeResolver<any, any>,
7580
): Promise<ExecutionResult>;
7681
export function graphql(
7782
argsOrSchema,
@@ -81,6 +86,7 @@ export function graphql(
8186
variableValues,
8287
operationName,
8388
fieldResolver,
89+
typeResolver,
8490
) {
8591
/* eslint-enable no-redeclare */
8692
// Always return a Promise for a consistent API.
@@ -96,6 +102,7 @@ export function graphql(
96102
argsOrSchema.variableValues,
97103
argsOrSchema.operationName,
98104
argsOrSchema.fieldResolver,
105+
argsOrSchema.typeResolver,
99106
)
100107
: graphqlImpl(
101108
argsOrSchema,
@@ -105,6 +112,7 @@ export function graphql(
105112
variableValues,
106113
operationName,
107114
fieldResolver,
115+
typeResolver,
108116
),
109117
),
110118
);
@@ -126,6 +134,7 @@ declare function graphqlSync(
126134
variableValues?: ?ObjMap<mixed>,
127135
operationName?: ?string,
128136
fieldResolver?: ?GraphQLFieldResolver<any, any>,
137+
typeResolver?: ?GraphQLTypeResolver<any, any>,
129138
): ExecutionResult;
130139
export function graphqlSync(
131140
argsOrSchema,
@@ -135,6 +144,7 @@ export function graphqlSync(
135144
variableValues,
136145
operationName,
137146
fieldResolver,
147+
typeResolver,
138148
) {
139149
/* eslint-enable no-redeclare */
140150
// Extract arguments from object args if provided.
@@ -148,6 +158,7 @@ export function graphqlSync(
148158
argsOrSchema.variableValues,
149159
argsOrSchema.operationName,
150160
argsOrSchema.fieldResolver,
161+
argsOrSchema.typeResolver,
151162
)
152163
: graphqlImpl(
153164
argsOrSchema,
@@ -157,6 +168,7 @@ export function graphqlSync(
157168
variableValues,
158169
operationName,
159170
fieldResolver,
171+
typeResolver,
160172
);
161173

162174
// Assert that the execution was synchronous.
@@ -175,6 +187,7 @@ function graphqlImpl(
175187
variableValues,
176188
operationName,
177189
fieldResolver,
190+
typeResolver,
178191
): MaybePromise<ExecutionResult> {
179192
// Validate Schema
180193
const schemaValidationErrors = validateSchema(schema);
@@ -205,5 +218,6 @@ function graphqlImpl(
205218
variableValues,
206219
operationName,
207220
fieldResolver,
221+
typeResolver,
208222
);
209223
}

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ export type {
281281
export {
282282
execute,
283283
defaultFieldResolver,
284+
defaultTypeResolver,
284285
responsePathAsArray,
285286
getDirectiveValues,
286287
} from './execution';

0 commit comments

Comments
 (0)