import { GraphQLSchema, printSchema } from 'graphql'; import { DynamicModule, Inject, Module, OnModuleInit, Provider, } from '@nestjs/common'; import { ApplicationConfig, HttpAdapterHost } from '@nestjs/core'; import { MetadataScanner } from '@nestjs/core/metadata-scanner'; import { GraphQLTypesLoader, GraphQLSchemaBuilderModule, GraphQLAstExplorer, GraphQLSchemaHost, } from '@nestjs/graphql'; import { PluginsExplorerService, ResolversExplorerService, ScalarsExplorerService, } from '@nestjs/graphql/dist/services'; import { GRAPHQL_MODULE_OPTIONS, GRAPHQL_MODULE_ID, } from '@nestjs/graphql/dist/graphql.constants'; import { GraphQLSchemaBuilder } from '@nestjs/graphql/dist/graphql-schema.builder'; import { extend, generateString } from '@nestjs/graphql/dist/utils'; import { MercuriusModuleAsyncOptions, MercuriusModuleOptions, MercuriusOptionsFactory, } from './interfaces'; import { HookExplorerService, LoadersExplorerService } from './services'; import { mergeDefaults } from './utils/merge-defaults'; import { MercuriusCoreModule } from './mercurius-core.module'; import { GraphQLFactory } from './factories/graphql.factory'; import { BaseMercuriusModule } from './base-mercurius.module'; @Module({ imports: [GraphQLSchemaBuilderModule, MercuriusCoreModule], providers: [ GraphQLFactory, MetadataScanner, ResolversExplorerService, ScalarsExplorerService, PluginsExplorerService, GraphQLAstExplorer, GraphQLTypesLoader, GraphQLSchemaBuilder, GraphQLSchemaHost, LoadersExplorerService, HookExplorerService, ], }) export class MercuriusModule extends BaseMercuriusModule<MercuriusModuleOptions> implements OnModuleInit { constructor( private readonly graphqlFactory: GraphQLFactory, private readonly graphqlTypesLoader: GraphQLTypesLoader, @Inject(GRAPHQL_MODULE_OPTIONS) protected readonly options: MercuriusModuleOptions, protected readonly applicationConfig: ApplicationConfig, protected readonly httpAdapterHost: HttpAdapterHost, protected readonly hookExplorerService: HookExplorerService, ) { super(httpAdapterHost, applicationConfig, options, hookExplorerService); } static forRoot(options: MercuriusModuleOptions) { options = mergeDefaults(options); return { module: MercuriusModule, providers: [ { provide: GRAPHQL_MODULE_OPTIONS, useValue: options, }, ], }; } static forRootAsync(options: MercuriusModuleAsyncOptions): DynamicModule { return { module: MercuriusModule, imports: options.imports, providers: [ ...this.createAsyncProviders(options), { provide: GRAPHQL_MODULE_ID, useValue: generateString(), }, ], }; } private static createAsyncProviders( options: MercuriusModuleAsyncOptions, ): Provider[] { if (options.useExisting || options.useFactory) { return [this.createAsyncOptionsProvider(options)]; } return [ this.createAsyncOptionsProvider(options), { provide: options.useClass, useClass: options.useClass, }, ]; } private static createAsyncOptionsProvider( options: MercuriusModuleAsyncOptions, ): Provider { if (options.useFactory) { return { provide: GRAPHQL_MODULE_OPTIONS, useFactory: async (...args: any[]) => mergeDefaults(await options.useFactory(...args)), inject: options.inject || [], }; } return { provide: GRAPHQL_MODULE_OPTIONS, useFactory: async (optionsFactory: MercuriusOptionsFactory) => mergeDefaults(await optionsFactory.createMercuriusOptions()), inject: [options.useExisting || options.useClass], }; } async onModuleInit() { if (!this.httpAdapterHost) { return; } const httpAdapter = this.httpAdapterHost.httpAdapter; if (!httpAdapter) { return; } const typeDefs = (await this.graphqlTypesLoader.mergeTypesByPaths( this.options.typePaths, )) || []; const mergedTypeDefs = extend(typeDefs, this.options.typeDefs); const mercuriusOptions = (await this.graphqlFactory.mergeOptions({ ...this.options, typeDefs: mergedTypeDefs, } as any)) as unknown as MercuriusModuleOptions; if ( this.options.definitions && this.options.definitions.path && mercuriusOptions.schema instanceof GraphQLSchema ) { await this.graphqlFactory.generateDefinitions( printSchema(mercuriusOptions.schema), this.options as any, ); } await this.registerGqlServer(mercuriusOptions); } }