UNPKG

type-graphql

Version:

Create GraphQL schema and resolvers with TypeScript, using classes and decorators!

416 lines (415 loc) 18.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MetadataStorage = void 0; const errors_1 = require("../errors"); const utils_1 = require("./utils"); class MetadataStorage { constructor() { this.queries = []; this.mutations = []; this.subscriptions = []; this.fieldResolvers = []; this.objectTypes = []; this.objectTypesCache = new Map(); this.inputTypes = []; this.argumentTypes = []; this.interfaceTypes = []; this.interfaceTypesCache = new Map(); this.authorizedFields = []; this.authorizedFieldsByTargetAndFieldCache = new Map(); this.authorizedResolver = []; this.authorizedResolverByTargetCache = new Map(); this.enums = []; this.unions = []; this.middlewares = []; this.middlewaresByTargetAndFieldCache = new Map(); this.resolverMiddlewares = []; this.resolverMiddlewaresByTargetCache = new Map(); this.classDirectives = []; this.classDirectivesByTargetCache = new Map(); this.fieldDirectives = []; this.fieldDirectivesByTargetAndFieldCache = new Map(); this.argumentDirectives = []; this.classExtensions = []; this.fieldExtensions = []; this.resolverClasses = []; this.resolverClassesCache = new Map(); this.fields = []; this.fieldsCache = new Map(); this.params = []; this.paramsCache = new Map(); } collectQueryHandlerMetadata(definition) { this.queries.push(definition); } collectMutationHandlerMetadata(definition) { this.mutations.push(definition); } collectSubscriptionHandlerMetadata(definition) { this.subscriptions.push(definition); } collectFieldResolverMetadata(definition) { this.fieldResolvers.push(definition); } collectObjectMetadata(definition) { this.objectTypes.push(definition); } collectInputMetadata(definition) { this.inputTypes.push(definition); } collectArgsMetadata(definition) { this.argumentTypes.push(definition); } collectInterfaceMetadata(definition) { this.interfaceTypes.push(definition); } collectAuthorizedFieldMetadata(definition) { this.authorizedFields.push(definition); } collectAuthorizedResolverMetadata(definition) { this.authorizedResolver.push(definition); } collectEnumMetadata(definition) { this.enums.push(definition); } collectUnionMetadata(definition) { const unionSymbol = Symbol(definition.name); this.unions.push({ ...definition, symbol: unionSymbol, }); return unionSymbol; } collectMiddlewareMetadata(definition) { this.middlewares.push(definition); } collectResolverMiddlewareMetadata(definition) { this.resolverMiddlewares.push(definition); } collectResolverClassMetadata(definition) { this.resolverClasses.push(definition); } collectClassFieldMetadata(definition) { this.fields.push(definition); } collectHandlerParamMetadata(definition) { this.params.push(definition); } collectDirectiveClassMetadata(definition) { this.classDirectives.push(definition); } collectDirectiveFieldMetadata(definition) { this.fieldDirectives.push(definition); } collectDirectiveArgumentMetadata(definition) { this.argumentDirectives.push(definition); } collectExtensionsClassMetadata(definition) { this.classExtensions.push(definition); } collectExtensionsFieldMetadata(definition) { this.fieldExtensions.push(definition); } initCache() { if (this.resolverClasses?.length) { this.resolverClasses.forEach(resolverClass => { if (!this.resolverClassesCache.has(resolverClass.target)) { this.resolverClassesCache.set(resolverClass.target, resolverClass); } }); } if (this.params?.length) { this.params.forEach(param => { if (!this.paramsCache.has(param.target)) { this.paramsCache.set(param.target, new Map()); } if (!this.paramsCache.get(param.target).has(param.methodName)) { this.paramsCache.get(param.target).set(param.methodName, []); } this.paramsCache.get(param.target).get(param.methodName).push(param); }); } if (this.middlewares?.length) { this.middlewares.forEach(middleware => { if (!this.middlewaresByTargetAndFieldCache.has(middleware.target)) { this.middlewaresByTargetAndFieldCache.set(middleware.target, new Map()); } if (!this.middlewaresByTargetAndFieldCache.get(middleware.target).has(middleware.fieldName)) { this.middlewaresByTargetAndFieldCache .get(middleware.target) .set(middleware.fieldName, new Set()); } if (!this.middlewaresByTargetAndFieldCache .get(middleware.target) .get(middleware.fieldName) .has(middleware)) { this.middlewaresByTargetAndFieldCache .get(middleware.target) .get(middleware.fieldName) .add(middleware); } }); } if (this.resolverMiddlewares?.length) { this.resolverMiddlewares.forEach(middleware => { const key = middleware.target; if (!this.resolverMiddlewaresByTargetCache.has(key)) { this.resolverMiddlewaresByTargetCache.set(key, new Set()); } if (!this.resolverMiddlewaresByTargetCache.get(key).has(middleware)) { this.resolverMiddlewaresByTargetCache.get(key).add(middleware); } }); } if (this.fieldDirectives?.length) { this.fieldDirectives.forEach(directive => { if (!this.fieldDirectivesByTargetAndFieldCache.has(directive.target)) { this.fieldDirectivesByTargetAndFieldCache.set(directive.target, new Map()); } if (!this.fieldDirectivesByTargetAndFieldCache.get(directive.target).has(directive.fieldName)) { this.fieldDirectivesByTargetAndFieldCache .get(directive.target) .set(directive.fieldName, []); } this.fieldDirectivesByTargetAndFieldCache .get(directive.target) .get(directive.fieldName) .push(directive); }); } if (this.classDirectives?.length) { this.classDirectives.forEach(directive => { const key = directive.target; if (!this.classDirectivesByTargetCache.has(key)) { this.classDirectivesByTargetCache.set(key, []); } this.classDirectivesByTargetCache.get(key).push(directive); }); } if (this.authorizedFields?.length) { this.authorizedFields.forEach(field => { if (!this.authorizedFieldsByTargetAndFieldCache.has(field.target)) { this.authorizedFieldsByTargetAndFieldCache.set(field.target, new Map()); } if (!this.authorizedFieldsByTargetAndFieldCache.get(field.target).has(field.fieldName)) { this.authorizedFieldsByTargetAndFieldCache.get(field.target).set(field.fieldName, field); } }); } if (this.authorizedResolver?.length) { this.authorizedResolver.forEach(resolver => { const key = resolver.target; if (!this.authorizedResolverByTargetCache.has(key)) { this.authorizedResolverByTargetCache.set(key, resolver); } }); } if (this.fields?.length) { this.fields.forEach(field => { if (!this.fieldsCache.has(field.target)) { this.fieldsCache.set(field.target, []); } this.fieldsCache.get(field.target).push(field); }); } if (this.objectTypes?.length) { this.objectTypes.forEach(objType => { this.objectTypesCache.set(objType.target, objType); }); } if (this.interfaceTypes?.length) { this.interfaceTypes.forEach(interfaceType => { this.interfaceTypesCache.set(interfaceType.target, interfaceType); }); } } build(options) { this.classDirectives.reverse(); this.fieldDirectives.reverse(); this.argumentDirectives.reverse(); this.classExtensions.reverse(); this.fieldExtensions.reverse(); this.initCache(); this.buildClassMetadata(this.objectTypes); this.buildClassMetadata(this.inputTypes); this.buildClassMetadata(this.argumentTypes); this.buildClassMetadata(this.interfaceTypes); this.buildFieldResolverMetadata(this.fieldResolvers, options); this.buildResolversMetadata(this.queries); this.buildResolversMetadata(this.mutations); this.buildResolversMetadata(this.subscriptions); this.buildExtendedResolversMetadata(); } clear() { this.queries = []; this.mutations = []; this.subscriptions = []; this.fieldResolvers = []; this.objectTypes = []; this.inputTypes = []; this.argumentTypes = []; this.interfaceTypes = []; this.authorizedFields = []; this.authorizedResolver = []; this.enums = []; this.unions = []; this.middlewares = []; this.resolverMiddlewares = []; this.classDirectives = []; this.fieldDirectives = []; this.argumentDirectives = []; this.classExtensions = []; this.fieldExtensions = []; this.fieldsCache = new Map(); this.objectTypesCache = new Map(); this.interfaceTypesCache = new Map(); this.middlewaresByTargetAndFieldCache = new Map(); this.resolverMiddlewaresByTargetCache = new Map(); this.paramsCache = new Map(); this.fieldDirectivesByTargetAndFieldCache = new Map(); this.classDirectivesByTargetCache = new Map(); this.authorizedFieldsByTargetAndFieldCache = new Map(); this.authorizedResolverByTargetCache = new Map(); this.resolverClassesCache = new Map(); this.resolverClasses = []; this.fields = []; this.params = []; } buildClassMetadata(definitions) { definitions.forEach(def => { if (!def.fields) { const fields = this.fieldsCache.get(def.target) || []; fields.forEach(field => { field.roles = this.findFieldRoles(field.target, field.name); field.params = this.paramsCache.get(field.target)?.get(field.name) || []; field.middlewares = [ ...(0, utils_1.mapMiddlewareMetadataToArray)([ ...(this.resolverMiddlewaresByTargetCache.get(field.target) || []), ]), ...(0, utils_1.mapMiddlewareMetadataToArray)([ ...(this.middlewaresByTargetAndFieldCache.get(field.target)?.get(field.name) || []), ]), ]; field.directives = (this.fieldDirectivesByTargetAndFieldCache.get(field.target)?.get(field.name) || []).map(it => it.directive); field.extensions = this.findExtensions(field.target, field.name); }); def.fields = fields; } if (!def.directives) { def.directives = (this.classDirectivesByTargetCache.get(def.target) || []).map(it => it.directive); } if (!def.extensions) { def.extensions = this.findExtensions(def.target); } }); } buildResolversMetadata(definitions) { definitions.forEach(def => { def.resolverClassMetadata = this.resolverClassesCache.get(def.target); def.params = this.paramsCache.get(def.target)?.get(def.methodName) || []; def.roles = this.findFieldRoles(def.target, def.methodName); def.middlewares = [ ...(0, utils_1.mapMiddlewareMetadataToArray)([ ...(this.resolverMiddlewaresByTargetCache.get(def.target) || []), ]), ...(0, utils_1.mapMiddlewareMetadataToArray)([ ...(this.middlewaresByTargetAndFieldCache.get(def.target)?.get(def.methodName) || []), ]), ]; def.directives = (this.fieldDirectivesByTargetAndFieldCache.get(def.target)?.get(def.methodName) || []).map(it => it.directive); def.extensions = this.findExtensions(def.target, def.methodName); }); } buildFieldResolverMetadata(definitions, options) { this.buildResolversMetadata(definitions); definitions.forEach(def => { def.roles = this.findFieldRoles(def.target, def.methodName); def.directives = (this.fieldDirectivesByTargetAndFieldCache.get(def.target)?.get(def.methodName) || []).map(it => it.directive); def.extensions = this.findExtensions(def.target, def.methodName); def.getObjectType = def.kind === "external" ? this.resolverClassesCache.get(def.target).getObjectType : () => def.target; if (def.kind === "external") { const typeClass = this.resolverClassesCache.get(def.target).getObjectType(); const typeMetadata = this.objectTypesCache.get(typeClass) || this.interfaceTypesCache.get(typeClass); if (!typeMetadata) { throw new Error(`Unable to find type metadata for input type or object type named '${typeClass.name}'`); } const typeField = typeMetadata.fields.find(fieldDef => fieldDef.schemaName === def.schemaName); if (!typeField) { const shouldCollectFieldMetadata = !options.resolvers || options.resolvers.some(resolverCls => resolverCls === def.target || Object.prototype.isPrototypeOf.call(def.target, resolverCls)); if (!def.getType || !def.typeOptions) { throw new errors_1.NoExplicitTypeError(def.target.name, def.methodName); } if (shouldCollectFieldMetadata) { const fieldMetadata = { name: def.methodName, schemaName: def.schemaName, getType: def.getType, target: typeClass, typeOptions: def.typeOptions, deprecationReason: def.deprecationReason, description: def.description, complexity: def.complexity, roles: def.roles, middlewares: def.middlewares, params: def.params, directives: def.directives, extensions: def.extensions, }; this.collectClassFieldMetadata(fieldMetadata); typeMetadata.fields.push(fieldMetadata); } } else { typeField.complexity = def.complexity; if (typeField.params.length === 0) { typeField.params = def.params; } if (def.roles) { typeField.roles = def.roles; } else if (typeField.roles) { def.roles = typeField.roles; } } } }); } buildExtendedResolversMetadata() { this.resolverClasses.forEach(def => { let superResolver = Object.getPrototypeOf(def.target); while (superResolver.prototype) { const superResolverMetadata = this.resolverClassesCache.get(superResolver); if (superResolverMetadata) { this.queries = (0, utils_1.mapSuperResolverHandlers)(this.queries, superResolver, def); this.mutations = (0, utils_1.mapSuperResolverHandlers)(this.mutations, superResolver, def); this.subscriptions = (0, utils_1.mapSuperResolverHandlers)(this.subscriptions, superResolver, def); this.fieldResolvers = (0, utils_1.mapSuperFieldResolverHandlers)(this.fieldResolvers, superResolver, def); } superResolver = Object.getPrototypeOf(superResolver); } }); } findFieldRoles(target, fieldName) { const authorizedField = this.authorizedFieldsByTargetAndFieldCache.get(target)?.get(fieldName) || this.authorizedResolverByTargetCache.get(target); if (!authorizedField) { return undefined; } return authorizedField.roles; } findExtensions(target, fieldName) { const storedExtensions = fieldName ? this.fieldExtensions : this.classExtensions; return storedExtensions .filter(entry => (entry.target === target || Object.prototype.isPrototypeOf.call(entry.target, target)) && (!("fieldName" in entry) || entry.fieldName === fieldName)) .reduce((extensions, entry) => ({ ...extensions, ...entry.extensions }), {}); } } exports.MetadataStorage = MetadataStorage;