@@ -13,6 +13,7 @@ import {
13
13
print ,
14
14
Kind ,
15
15
DefinitionNode ,
16
+ DirectiveNode ,
16
17
defaultFieldResolver ,
17
18
buildASTSchema ,
18
19
extendSchema ,
@@ -27,6 +28,7 @@ import {
27
28
GraphQLInterfaceType ,
28
29
GraphQLFieldMap ,
29
30
} from 'graphql' ;
31
+ import { getArgumentValues } from 'graphql/execution/values' ;
30
32
import {
31
33
IExecutableSchemaDefinition ,
32
34
ILogger ,
@@ -38,6 +40,7 @@ import {
38
40
IConnector ,
39
41
IConnectorCls ,
40
42
IResolverValidationOptions ,
43
+ IDirectiveResolvers ,
41
44
} from './Interfaces' ;
42
45
43
46
import { deprecated } from 'deprecated-decorator' ;
@@ -62,6 +65,7 @@ function _generateSchema(
62
65
// TODO: rename to allowUndefinedInResolve to be consistent
63
66
allowUndefinedInResolve : boolean ,
64
67
resolverValidationOptions : IResolverValidationOptions ,
68
+ directiveResolvers : IDirectiveResolvers < any , any > ,
65
69
) {
66
70
if ( typeof resolverValidationOptions !== 'object' ) {
67
71
throw new SchemaError (
@@ -95,6 +99,10 @@ function _generateSchema(
95
99
addErrorLoggingToSchema ( schema , logger ) ;
96
100
}
97
101
102
+ if ( directiveResolvers ) {
103
+ attachDirectiveResolvers ( schema , directiveResolvers ) ;
104
+ }
105
+
98
106
return schema ;
99
107
}
100
108
@@ -105,13 +113,15 @@ function makeExecutableSchema({
105
113
logger,
106
114
allowUndefinedInResolve = true ,
107
115
resolverValidationOptions = { } ,
116
+ directiveResolvers = null ,
108
117
} : IExecutableSchemaDefinition ) {
109
118
const jsSchema = _generateSchema (
110
119
typeDefs ,
111
120
resolvers ,
112
121
logger ,
113
122
allowUndefinedInResolve ,
114
123
resolverValidationOptions ,
124
+ directiveResolvers ,
115
125
) ;
116
126
if ( typeof resolvers [ '__schema' ] === 'function' ) {
117
127
// TODO a bit of a hack now, better rewrite generateSchema to attach it there.
@@ -378,11 +388,12 @@ function addResolveFunctionsToSchema(
378
388
// is inside NPM
379
389
if ( ! ( type as any ) . isValidValue ( fieldName ) ) {
380
390
throw new SchemaError (
381
- `${ typeName } .${ fieldName } was defined in resolvers, but enum is not in schema` ,
391
+ `${ typeName } .${ fieldName } was defined in resolvers, but enum is not in schema` ,
382
392
) ;
383
393
}
384
394
385
- type . getValue ( fieldName ) [ 'value' ] = resolveFunctions [ typeName ] [ fieldName ] ;
395
+ type . getValue ( fieldName ) [ 'value' ] =
396
+ resolveFunctions [ typeName ] [ fieldName ] ;
386
397
return ;
387
398
}
388
399
@@ -637,6 +648,62 @@ function runAtMostOncePerRequest(
637
648
} ;
638
649
}
639
650
651
+ function attachDirectiveResolvers (
652
+ schema : GraphQLSchema ,
653
+ directiveResolvers : IDirectiveResolvers < any , any > ,
654
+ ) {
655
+ if ( typeof directiveResolvers !== 'object' ) {
656
+ throw new Error (
657
+ `Expected directiveResolvers to be of type object, got ${ typeof directiveResolvers } ` ,
658
+ ) ;
659
+ }
660
+ if ( Array . isArray ( directiveResolvers ) ) {
661
+ throw new Error (
662
+ 'Expected directiveResolvers to be of type object, got Array' ,
663
+ ) ;
664
+ }
665
+ forEachField ( schema , ( field : GraphQLField < any , any > ) => {
666
+ const directives = field . astNode . directives ;
667
+ directives . forEach ( ( directive : DirectiveNode ) => {
668
+ const directiveName = directive . name . value ;
669
+ const resolver = directiveResolvers [ directiveName ] ;
670
+
671
+ if ( resolver ) {
672
+ const originalResolver = field . resolve || defaultFieldResolver ;
673
+ const Directive = schema . getDirective ( directiveName ) ;
674
+ if ( typeof Directive === 'undefined' ) {
675
+ throw new Error (
676
+ `Directive @${ directiveName } is undefined. ` +
677
+ 'Please define in schema before using' ,
678
+ ) ;
679
+ }
680
+ const directiveArgs = getArgumentValues ( Directive , directive ) ;
681
+
682
+ field . resolve = ( ...args : any [ ] ) => {
683
+ const [ source , , context , info ] = args ;
684
+ return resolver (
685
+ ( ) => {
686
+ try {
687
+ const promise = originalResolver . call ( field , ...args ) ;
688
+ if ( promise instanceof Promise ) {
689
+ return promise ;
690
+ }
691
+ return Promise . resolve ( promise ) ;
692
+ } catch ( error ) {
693
+ return Promise . reject ( error ) ;
694
+ }
695
+ } ,
696
+ source ,
697
+ directiveArgs ,
698
+ context ,
699
+ info ,
700
+ ) ;
701
+ } ;
702
+ }
703
+ } ) ;
704
+ } ) ;
705
+ }
706
+
640
707
export {
641
708
makeExecutableSchema ,
642
709
SchemaError ,
@@ -650,4 +717,5 @@ export {
650
717
addSchemaLevelResolveFunction ,
651
718
attachConnectorsToContext ,
652
719
concatenateTypeDefs ,
720
+ attachDirectiveResolvers ,
653
721
} ;
0 commit comments