@@ -65,7 +65,7 @@ export interface GraphQLModuleOptions<Config, Request, Context> {
6565 * Context builder method. Use this to add your own fields and data to the GraphQL `context`
6666 * of each execution of GraphQL.
6767 */
68- context ?: BuildContextFn < Config , Request , Context > | Context ;
68+ context ?: BuildContextFn < Config , Request , Context > | Promise < Context > | Context ;
6969 /**
7070 * The dependencies that this module need to run correctly, you can either provide the `GraphQLModule`,
7171 * or provide a string with the name of the other module.
@@ -111,7 +111,7 @@ export interface ModuleCache<Request, Context> {
111111 typeDefs : DocumentNode ;
112112 resolvers : IResolvers < any , ModuleContext < Context > > ;
113113 schemaDirectives : ISchemaDirectives ;
114- contextBuilder : ( req : Request ) => Promise < Context > ;
114+ contextBuilder : ( req : Request , excludeRequest ?: boolean ) => Promise < Context > ;
115115 modulesMap : ModulesMap < Request > ;
116116 extraSchemas : GraphQLSchema [ ] ;
117117 directiveResolvers : IDirectiveResolvers ;
@@ -385,8 +385,8 @@ export class GraphQLModule<Config = any, Request = any, Context = any> {
385385 return directiveResolvers ;
386386 }
387387
388- private checkIfResolverCalledSafely ( resolverPath : string , appContext : any , info : any ) {
389- if ( ! ( ' request' in appContext ) ) {
388+ private checkIfResolverCalledSafely ( resolverPath : string , request : any , info : any ) {
389+ if ( typeof request === 'undefined' ) {
390390 throw new IllegalResolverInvocationError ( resolverPath , this . name , `Network Request hasn't been passed!` ) ;
391391 }
392392 if ( typeof info === 'undefined' ) {
@@ -399,29 +399,30 @@ export class GraphQLModule<Config = any, Request = any, Context = any> {
399399 // tslint:disable-next-line:forin
400400 for ( const type in resolvers ) {
401401 const typeResolvers = resolvers [ type ] ;
402- if ( typeResolvers instanceof GraphQLScalarType ) {
403- continue ;
404- }
405- // tslint:disable-next-line:forin
406- for ( const prop in resolvers [ type ] ) {
407- const resolver = typeResolvers [ prop ] ;
408- if ( typeof resolver === 'function' ) {
409- if ( prop !== '__resolveType' ) {
410- typeResolvers [ prop ] = async ( root : any , args : any , appContext : any , info : any ) => {
411- this . checkIfResolverCalledSafely ( `${ type } .${ prop } ` , appContext , info ) ;
412- const { request } = appContext ;
413- const moduleContext = await this . context ( request ) ;
414- info . schema = this . _cache . schema ;
415- return resolver . call ( typeResolvers , root , args , moduleContext , info ) ;
416- } ;
417- } else {
418- typeResolvers [ prop ] = async ( root : any , appContext : any , info : any ) => {
419- this . checkIfResolverCalledSafely ( `${ type } .${ prop } ` , appContext , info ) ;
420- const { request } = appContext ;
421- const moduleContext = await this . context ( request ) ;
422- info . schema = this . _cache . schema ;
423- return resolver . call ( typeResolvers , root , moduleContext as any , info ) ;
424- } ;
402+ if ( ! ( typeResolvers instanceof GraphQLScalarType ) ) {
403+ // tslint:disable-next-line:forin
404+ for ( const prop in resolvers [ type ] ) {
405+ const resolver = typeResolvers [ prop ] ;
406+ if ( typeof resolver === 'function' ) {
407+ if ( prop !== '__resolveType' ) {
408+ typeResolvers [ prop ] = async ( root : any , args : any , appContext : any , info : any ) => {
409+ const request = info . request || appContext . request ;
410+ info . request = request ;
411+ this . checkIfResolverCalledSafely ( `${ type } .${ prop } ` , request , info ) ;
412+ const moduleContext = await this . context ( request , true ) ;
413+ info . schema = this . schema ;
414+ return resolver . call ( typeResolvers , root , args , moduleContext , info ) ;
415+ } ;
416+ } else {
417+ typeResolvers [ prop ] = async ( root : any , appContext : any , info : any ) => {
418+ const request = info . request || appContext . request ;
419+ info . request = request ;
420+ this . checkIfResolverCalledSafely ( `${ type } .${ prop } ` , request , info ) ;
421+ const moduleContext = await this . context ( request , true ) ;
422+ info . schema = this . schema ;
423+ return resolver . call ( typeResolvers , root , moduleContext , info ) ;
424+ } ;
425+ }
425426 }
426427 }
427428 }
@@ -436,10 +437,11 @@ export class GraphQLModule<Config = any, Request = any, Context = any> {
436437 const compositionArr = asArray ( resolversComposition [ path ] ) ;
437438 resolversComposition [ path ] = [
438439 ( next : any ) => async ( root : any , args : any , appContext : any , info : any ) => {
439- this . checkIfResolverCalledSafely ( path , appContext , info ) ;
440- const { request } = appContext ;
441- const moduleContext = await this . context ( request ) ;
442- info . schema = this . _cache . schema ;
440+ const request = info . request || appContext . request ;
441+ info . request = request ;
442+ this . checkIfResolverCalledSafely ( path , request , info ) ;
443+ const moduleContext = await this . context ( request , true ) ;
444+ info . schema = this . schema ;
443445 return next ( root , args , moduleContext , info ) ;
444446 } ,
445447 ...compositionArr ,
@@ -479,7 +481,7 @@ export class GraphQLModule<Config = any, Request = any, Context = any> {
479481 const importsTypeDefs = new Set < DocumentNode > ( ) ;
480482 const importsResolvers = new Set < IResolvers < any , any > > ( ) ;
481483 const importsInjectors = new Set < Injector > ( ) ;
482- const importsContextBuilders = new Set < ( req : Request ) => Promise < Context > > ( ) ;
484+ const importsContextBuilders = new Set < ( req : Request , excludeRequest ?: boolean ) => Promise < Context > > ( ) ;
483485 const importsSchemaDirectives = new Set < ISchemaDirectives > ( ) ;
484486 const importsExtraSchemas = new Set < GraphQLSchema > ( ) ;
485487 const importsDirectiveResolvers = new Set < IDirectiveResolvers > ( ) ;
@@ -610,40 +612,45 @@ export class GraphQLModule<Config = any, Request = any, Context = any> {
610612 }
611613 }
612614
613- this . _cache . contextBuilder = async request => {
614- request [ 'moduleNameContextMap' ] = request [ 'moduleNameContextMap' ] || new Map ( ) ;
615- const moduleNameContextMap : Map < string , any > = request [ 'moduleNameContextMap' ] ;
615+ this . _cache . contextBuilder = async ( request , excludeRequest = false ) => {
616+ const moduleNameContextMap = this . getModuleNameContextMap ( request ) ;
616617 if ( ! ( moduleNameContextMap . has ( this . name ) ) ) {
617- const importsContextArr$ = [ ...importsContextBuilders ] . map ( contextBuilder => contextBuilder ( request ) ) ;
618+ const importsContextArr$ = [ ...importsContextBuilders ] . map ( contextBuilder => contextBuilder ( request , true ) ) ;
618619 const importsContextArr = await Promise . all ( importsContextArr$ ) ;
619- const importsContext = importsContextArr . reduce ( ( acc , curr ) => ( { ...acc , ...( curr as any ) } ) , { } ) ;
620+ const importsContext = importsContextArr . reduce ( ( acc , curr ) => ( { ...acc , ...curr } ) , { } as any ) ;
620621 const applicationInjector = this . injector ;
621622 const sessionInjector = applicationInjector . getSessionInjector ( request ) ;
622- const moduleSessionInfo = sessionInjector . has ( ModuleSessionInfo ) ? sessionInjector . get ( ModuleSessionInfo ) : new ModuleSessionInfo < Config , any , Context > ( this , request , importsContext ) ;
623+ const moduleSessionInfo = sessionInjector . has ( ModuleSessionInfo ) ? sessionInjector . get ( ModuleSessionInfo ) : new ModuleSessionInfo < Config , any , Context > ( this , request ) ;
623624 let moduleContext = { } ;
624625 const moduleContextDeclaration = this . _options . context ;
625626 if ( moduleContextDeclaration ) {
626- if ( typeof moduleContextDeclaration === 'function' ) {
627- moduleContext = await ( moduleContextDeclaration as any ) ( request , importsContext , moduleSessionInfo ) ;
627+ if ( moduleContextDeclaration instanceof Function ) {
628+ moduleContext = await moduleContextDeclaration ( request , { ... importsContext , injector } , moduleSessionInfo ) ;
628629 } else {
629- moduleContext = moduleContextDeclaration ;
630+ moduleContext = await moduleContextDeclaration ;
630631 }
631632 }
632- const builtResult = {
633+ moduleNameContextMap . set ( this . name , {
633634 ...importsContext ,
634- ...moduleContext as any ,
635+ ...moduleContext ,
635636 injector : sessionInjector ,
636- request,
637- } ;
637+ } ) ;
638638 const requestHooks$ = [
639639 ...applicationInjector . scopeSet ,
640640 ...sessionInjector . scopeSet ,
641641 ] . map ( serviceIdentifier => moduleSessionInfo . callRequestHook ( serviceIdentifier ) ,
642642 ) ;
643643 await Promise . all ( requestHooks$ ) ;
644- moduleNameContextMap . set ( this . name , builtResult ) ;
645644 }
646- return moduleNameContextMap . get ( this . name ) ;
645+ const moduleContext = moduleNameContextMap . get ( this . name ) ;
646+ if ( excludeRequest ) {
647+ return moduleContext ;
648+ } else {
649+ return {
650+ ...moduleContext ,
651+ request,
652+ } ;
653+ }
647654 } ;
648655
649656 if ( 'middleware' in this . _options ) {
@@ -652,6 +659,15 @@ export class GraphQLModule<Config = any, Request = any, Context = any> {
652659 }
653660 }
654661
662+ private static requestModuleNameContextMap = new WeakMap < any , Map < string , any > > ( ) ;
663+
664+ getModuleNameContextMap ( request : Request ) {
665+ if ( ! GraphQLModule . requestModuleNameContextMap . has ( request ) ) {
666+ GraphQLModule . requestModuleNameContextMap . set ( request , new Map ( ) ) ;
667+ }
668+ return GraphQLModule . requestModuleNameContextMap . get ( request ) ;
669+ }
670+
655671 /**
656672 * Build a GraphQL `context` object based on a network request.
657673 * It iterates over all modules by their dependency-based order, and executes
@@ -665,7 +681,7 @@ export class GraphQLModule<Config = any, Request = any, Context = any> {
665681 *
666682 * @param request - the network request from `connect`, `express`, etc...
667683 */
668- get context ( ) : ( request : Request ) => Promise < ModuleContext < Context > > {
684+ get context ( ) : ( request : Request , excludeRequest ?: boolean ) => Promise < ModuleContext < Context > > {
669685 if ( ! this . _cache . contextBuilder ) {
670686 this . buildSchemaAndInjector ( ) ;
671687 }
@@ -848,8 +864,8 @@ export class GraphQLModule<Config = any, Request = any, Context = any> {
848864 const accContext = await accContextBuilder ( request , currentContext , injector ) ;
849865 const moduleContext = typeof currentContextBuilder === 'function' ? await currentContextBuilder ( request , currentContext , injector ) : ( currentContextBuilder || { } ) ;
850866 return {
851- ...accContext as any ,
852- ...moduleContext as any ,
867+ ...accContext ,
868+ ...moduleContext ,
853869 } ;
854870 } ;
855871 } ,
0 commit comments