graphql-modules
Version:
Create reusable, maintainable, testable and extendable GraphQL modules
69 lines (68 loc) • 2.84 kB
JavaScript
import { metadataFactory } from './metadata';
import { createResolvers } from './resolvers';
import { createTypeDefs } from './type-defs';
import { MODULE_ID } from './tokens';
import { ReflectiveInjector, onlySingletonProviders, onlyOperationProviders, } from '../di';
import { resolveProviders } from './../di/resolution';
function lazy(getter) {
let called = false;
let computedValue;
return {
get value() {
if (!called) {
called = true;
computedValue = getter();
}
return computedValue;
},
};
}
export function moduleFactory(config) {
const typeDefs = createTypeDefs(config);
const metadata = metadataFactory(typeDefs, config);
const providers = lazy(() => typeof config.providers === 'function'
? config.providers()
: config.providers);
// Filter providers and keep them this way
// so we don't do this filtering multiple times.
// Providers don't change over time, so it's safe to do it.
const operationProviders = lazy(() => ReflectiveInjector.resolve(onlyOperationProviders(providers.value)));
const singletonProviders = lazy(() => ReflectiveInjector.resolve(onlySingletonProviders(providers.value)));
const mod = {
id: config.id,
config,
metadata,
typeDefs,
// Factory is called once on application creation,
// before we even handle GraphQL Operation
factory(app) {
const resolvedModule = mod;
resolvedModule.singletonProviders = singletonProviders.value;
resolvedModule.operationProviders = operationProviders.value;
// Create a module-level Singleton injector
const injector = ReflectiveInjector.createFromResolved({
name: `Module "${config.id}" (Singleton Scope)`,
providers: resolvedModule.singletonProviders.concat(resolveProviders([
{
// with module's id, useful in Logging and stuff
provide: MODULE_ID,
useValue: config.id,
},
])),
parent: app.injector,
});
// We attach injector property to existing `mod` object
// because we want to keep references
// that are later on used in testing utils
resolvedModule.injector = injector;
// Create resolvers object based on module's config
// It involves wrapping a resolver with middlewares
// and other things like validation
resolvedModule.resolvers = createResolvers(config, metadata, {
middlewareMap: app.middlewares,
});
return resolvedModule;
},
};
return mod;
}