Skip to content

Commit d6f428a

Browse files
committed
Provide GraphQLResolveInfo to resolveType
This solves the issue raised in #103 by providing a second argument with this information. There is also some minor renaming happening in this diff to match previous diffs.
1 parent 06ecf38 commit d6f428a

File tree

3 files changed

+96
-32
lines changed

3 files changed

+96
-32
lines changed

src/execution/__tests__/union-interface.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,4 +346,47 @@ describe('Execute: Union and intersection types', () => {
346346
}
347347
});
348348
});
349+
350+
it('gets execution info in resolver', async () => {
351+
var encounteredSchema;
352+
var encounteredRootValue;
353+
354+
var NamedType2 = new GraphQLInterfaceType({
355+
name: 'Named',
356+
fields: {
357+
name: { type: GraphQLString }
358+
},
359+
resolveType(obj, { schema: infoSchema, rootValue: infoRootValue }) {
360+
encounteredSchema = infoSchema;
361+
encounteredRootValue = infoRootValue;
362+
return PersonType2;
363+
}
364+
});
365+
366+
var PersonType2 = new GraphQLObjectType({
367+
name: 'Person',
368+
interfaces: [ NamedType2 ],
369+
fields: {
370+
name: { type: GraphQLString },
371+
friends: { type: new GraphQLList(NamedType2) },
372+
},
373+
});
374+
375+
var schema2 = new GraphQLSchema({
376+
query: PersonType2
377+
});
378+
379+
var john2 = new Person('John', [], [ liz ]);
380+
381+
var ast = parse(`{ name, friends { name } }`);
382+
383+
expect(
384+
await execute(schema2, ast, john2)
385+
).to.deep.equal({
386+
data: { name: 'John', friends: [ { name: 'Liz' } ] }
387+
});
388+
389+
expect(encounteredSchema).to.equal(schema2);
390+
expect(encounteredRootValue).to.equal(john2);
391+
});
349392
});

src/execution/execute.js

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ import {
2424
isAbstractType
2525
} from '../type/definition';
2626
import type {
27-
GraphQLFieldDefinition,
2827
GraphQLType,
29-
GraphQLAbstractType
28+
GraphQLAbstractType,
29+
GraphQLFieldDefinition,
30+
GraphQLResolveInfo,
3031
} from '../type/definition';
3132
import type { GraphQLSchema } from '../type/schema';
3233
import {
@@ -482,7 +483,7 @@ function resolveField(
482483

483484
// The resolve function's optional third argument is a collection of
484485
// information about the current execution state.
485-
var info = {
486+
var info: GraphQLResolveInfo = {
486487
fieldName,
487488
fieldASTs,
488489
returnType,
@@ -509,25 +510,38 @@ function resolveField(
509510
return null;
510511
}
511512

512-
return completeValueCatchingError(exeContext, returnType, fieldASTs, result);
513+
return completeValueCatchingError(
514+
exeContext,
515+
returnType,
516+
fieldASTs,
517+
info,
518+
result
519+
);
513520
}
514521

515522
function completeValueCatchingError(
516523
exeContext: ExecutionContext,
517-
fieldType: GraphQLType,
524+
returnType: GraphQLType,
518525
fieldASTs: Array<Field>,
526+
info: GraphQLResolveInfo,
519527
result: any
520528
): any {
521529
// If the field type is non-nullable, then it is resolved without any
522530
// protection from errors.
523-
if (fieldType instanceof GraphQLNonNull) {
524-
return completeValue(exeContext, fieldType, fieldASTs, result);
531+
if (returnType instanceof GraphQLNonNull) {
532+
return completeValue(exeContext, returnType, fieldASTs, info, result);
525533
}
526534

527535
// Otherwise, error protection is applied, logging the error and resolving
528536
// a null value for this field if one is encountered.
529537
try {
530-
var completed = completeValue(exeContext, fieldType, fieldASTs, result);
538+
var completed = completeValue(
539+
exeContext,
540+
returnType,
541+
fieldASTs,
542+
info,
543+
result
544+
);
531545
if (isThenable(completed)) {
532546
// Note: we don't rely on a `catch` method, but we do expect "thenable"
533547
// to take a second callback for the error case.
@@ -563,26 +577,34 @@ function completeValueCatchingError(
563577
*/
564578
function completeValue(
565579
exeContext: ExecutionContext,
566-
fieldType: GraphQLType,
580+
returnType: GraphQLType,
567581
fieldASTs: Array<Field>,
582+
info: GraphQLResolveInfo,
568583
result: any
569584
): any {
570585
// If result is a Promise, resolve it, if the Promise is rejected, construct
571586
// a GraphQLError with proper locations.
572587
if (isThenable(result)) {
573588
return result.then(
574-
resolved => completeValue(exeContext, fieldType, fieldASTs, resolved),
589+
resolved => completeValue(
590+
exeContext,
591+
returnType,
592+
fieldASTs,
593+
info,
594+
resolved
595+
),
575596
error => Promise.reject(locatedError(error, fieldASTs))
576597
);
577598
}
578599

579600
// If field type is NonNull, complete for inner type, and throw field error
580601
// if result is null.
581-
if (fieldType instanceof GraphQLNonNull) {
602+
if (returnType instanceof GraphQLNonNull) {
582603
var completed = completeValue(
583604
exeContext,
584-
fieldType.ofType,
605+
returnType.ofType,
585606
fieldASTs,
607+
info,
586608
result
587609
);
588610
if (completed === null) {
@@ -600,19 +622,19 @@ function completeValue(
600622
}
601623

602624
// If field type is List, complete each item in the list with the inner type
603-
if (fieldType instanceof GraphQLList) {
625+
if (returnType instanceof GraphQLList) {
604626
invariant(
605627
Array.isArray(result),
606628
'User Error: expected iterable, but did not find one.'
607629
);
608630

609631
// This is specified as a simple map, however we're optimizing the path
610632
// where the list contains no Promises by avoiding creating another Promise.
611-
var itemType = fieldType.ofType;
633+
var itemType = returnType.ofType;
612634
var containsPromise = false;
613635
var completedResults = result.map(item => {
614636
var completedItem =
615-
completeValueCatchingError(exeContext, itemType, fieldASTs, item);
637+
completeValueCatchingError(exeContext, itemType, fieldASTs, info, item);
616638
if (!containsPromise && isThenable(completedItem)) {
617639
containsPromise = true;
618640
}
@@ -624,20 +646,19 @@ function completeValue(
624646

625647
// If field type is Scalar or Enum, serialize to a valid value, returning
626648
// null if serialization is not possible.
627-
if (fieldType instanceof GraphQLScalarType ||
628-
fieldType instanceof GraphQLEnumType) {
629-
invariant(fieldType.serialize, 'Missing serialize method on type');
630-
var serializedResult = fieldType.serialize(result);
649+
if (returnType instanceof GraphQLScalarType ||
650+
returnType instanceof GraphQLEnumType) {
651+
invariant(returnType.serialize, 'Missing serialize method on type');
652+
var serializedResult = returnType.serialize(result);
631653
return isNullish(serializedResult) ? null : serializedResult;
632654
}
633655

634656
// Field type must be Object, Interface or Union and expect sub-selections.
635-
636657
var objectType: ?GraphQLObjectType =
637-
fieldType instanceof GraphQLObjectType ? fieldType :
638-
isAbstractType(fieldType) ?
639-
((fieldType: any): GraphQLAbstractType).resolveType(result) :
640-
null;
658+
returnType instanceof GraphQLObjectType ? returnType :
659+
isAbstractType(returnType) ?
660+
((returnType: any): GraphQLAbstractType).resolveType(result, info) :
661+
null;
641662

642663
if (!objectType) {
643664
return null;

src/type/definition.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,10 @@ type GraphQLFieldConfigMapThunk = () => GraphQLFieldConfigMap;
358358
export type GraphQLFieldResolveFn = (
359359
source?: any,
360360
args?: {[argName: string]: any},
361-
info?: GraphQLFieldExeInfo
361+
info?: GraphQLResolveInfo
362362
) => any
363363

364-
export type GraphQLFieldExeInfo = {
364+
export type GraphQLResolveInfo = {
365365
fieldName: string,
366366
fieldASTs: Array<Field>,
367367
returnType: GraphQLOutputType,
@@ -472,9 +472,9 @@ export class GraphQLInterfaceType {
472472
return possibleTypeNames[type.name] === true;
473473
}
474474

475-
resolveType(value: any): ?GraphQLObjectType {
475+
resolveType(value: any, info: GraphQLResolveInfo): ?GraphQLObjectType {
476476
var resolver = this._typeConfig.resolveType;
477-
return resolver ? resolver(value) : getTypeOf(value, this);
477+
return resolver ? resolver(value, info) : getTypeOf(value, this);
478478
}
479479

480480
toString(): string {
@@ -513,7 +513,7 @@ export type GraphQLInterfaceTypeConfig = {
513513
* the default implemenation will call `isTypeOf` on each implementing
514514
* Object type.
515515
*/
516-
resolveType?: (value: any) => ?GraphQLObjectType,
516+
resolveType?: (value: any, info?: GraphQLResolveInfo) => ?GraphQLObjectType,
517517
description?: ?string
518518
};
519519

@@ -587,9 +587,9 @@ export class GraphQLUnionType {
587587
return possibleTypeNames[type.name] === true;
588588
}
589589

590-
resolveType(value: any): ?GraphQLObjectType {
590+
resolveType(value: any, info: GraphQLResolveInfo): ?GraphQLObjectType {
591591
var resolver = this._typeConfig.resolveType;
592-
return resolver ? resolver(value) : getTypeOf(value, this);
592+
return resolver ? resolver(value, info) : getTypeOf(value, this);
593593
}
594594

595595
toString(): string {
@@ -605,7 +605,7 @@ export type GraphQLUnionTypeConfig = {
605605
* the default implemenation will call `isTypeOf` on each implementing
606606
* Object type.
607607
*/
608-
resolveType?: (value: any) => ?GraphQLObjectType;
608+
resolveType?: (value: any, info?: GraphQLResolveInfo) => ?GraphQLObjectType;
609609
description?: ?string;
610610
};
611611

0 commit comments

Comments
 (0)