UNPKG

@nestjs/graphql

Version:

Nest - modern, fast, powerful node.js web framework (@graphql)

161 lines (160 loc) 8.03 kB
import { __decorate, __metadata } from "tslib"; import { Injectable } from '@nestjs/common'; import { isUndefined } from '@nestjs/common/utils/shared.utils.js'; import { GraphQLInterfaceType, } from 'graphql'; import { InterfaceNotRegisteredError } from '../errors/interface-not-registered.error.js'; import { ReturnTypeCannotBeResolvedError } from '../errors/return-type-cannot-be-resolved.error.js'; import { OrphanedReferenceRegistry } from '../services/orphaned-reference.registry.js'; import { TypeFieldsAccessor } from '../services/type-fields.accessor.js'; import { TypeDefinitionsStorage } from '../storages/type-definitions.storage.js'; import { TypeMetadataStorage } from '../storages/type-metadata.storage.js'; import { getInterfacesArray } from '../utils/get-interfaces-array.util.js'; import { ArgsFactory } from './args.factory.js'; import { AstDefinitionNodeFactory } from './ast-definition-node.factory.js'; import { OutputTypeFactory } from './output-type.factory.js'; import { ResolveTypeFactory } from './resolve-type.factory.js'; let InterfaceDefinitionFactory = class InterfaceDefinitionFactory { constructor(resolveTypeFactory, typeDefinitionsStorage, outputTypeFactory, orphanedReferenceRegistry, typeFieldsAccessor, argsFactory, astDefinitionNodeFactory) { this.resolveTypeFactory = resolveTypeFactory; this.typeDefinitionsStorage = typeDefinitionsStorage; this.outputTypeFactory = outputTypeFactory; this.orphanedReferenceRegistry = orphanedReferenceRegistry; this.typeFieldsAccessor = typeFieldsAccessor; this.argsFactory = argsFactory; this.astDefinitionNodeFactory = astDefinitionNodeFactory; } create(metadata, options) { const prototype = Object.getPrototypeOf(metadata.target); const getParentType = () => { const parentTypeDefinition = this.typeDefinitionsStorage.getObjectTypeByTarget(prototype) || this.typeDefinitionsStorage.getInterfaceByTarget(prototype); return parentTypeDefinition ? parentTypeDefinition.type : undefined; }; const resolveType = this.createResolveTypeFn(metadata); return { target: metadata.target, isAbstract: metadata.isAbstract || false, interfaces: getInterfacesArray(metadata.interfaces), type: new GraphQLInterfaceType({ name: metadata.name, description: metadata.description, fields: this.generateFields(metadata, options), interfaces: this.generateInterfaces(metadata, getParentType), resolveType, /** * AST node has to be manually created in order to define directives * (more on this topic here: https://github.com/graphql/graphql-js/issues/1343) */ astNode: this.astDefinitionNodeFactory.createInterfaceTypeNode(metadata.name, metadata.directives), }), }; } createResolveTypeFn(metadata) { const objectTypesMetadata = TypeMetadataStorage.getObjectTypesMetadata(); const implementedTypes = objectTypesMetadata .filter((objectType) => { const interfaces = getInterfacesArray(objectType.interfaces); return interfaces.includes(metadata.target); }) .map((objectType) => objectType.target); return metadata.resolveType ? this.resolveTypeFactory.getResolveTypeFunction(metadata.resolveType) : (instance) => { const target = implementedTypes.find((Type) => instance instanceof Type); if (!target) { if (Reflect.has(instance, '__typename')) { return instance.__typename; } throw new ReturnTypeCannotBeResolvedError(metadata.name); } return this.typeDefinitionsStorage.getObjectTypeByTarget(target).type ?.name; }; } generateFields(metadata, options) { const prototype = Object.getPrototypeOf(metadata.target); metadata.properties.forEach(({ typeFn }) => this.orphanedReferenceRegistry.addToRegistryIfOrphaned(typeFn())); const getParentType = () => { const parentTypeDefinition = this.typeDefinitionsStorage.getInterfaceByTarget(prototype); return parentTypeDefinition ? parentTypeDefinition.type : undefined; }; return () => { let fields = {}; let properties = []; if (metadata.interfaces) { const implementedInterfaces = TypeMetadataStorage.getInterfacesMetadata() .filter((it) => getInterfacesArray(metadata.interfaces).includes(it.target)) .map((it) => it.properties); implementedInterfaces.forEach((fields) => properties.push(...(fields || []))); } properties = properties.concat(metadata.properties); properties.forEach((field) => { const type = this.outputTypeFactory.create(field.name, field.typeFn(), options, field.options); fields[field.schemaName] = { description: field.description, type, args: this.argsFactory.create(field.methodArgs, options), resolve: (root) => { const value = root[field.name]; return typeof value === 'undefined' ? field.options.defaultValue : value; }, deprecationReason: field.deprecationReason, /** * AST node has to be manually created in order to define directives * (more on this topic here: https://github.com/graphql/graphql-js/issues/1343) */ astNode: this.astDefinitionNodeFactory.createFieldNode(field.name, type, field.directives), extensions: { complexity: field.complexity, ...field.extensions, }, }; }); if (!isUndefined(prototype.prototype)) { const parentClassRef = getParentType(); if (parentClassRef) { const parentFields = this.typeFieldsAccessor.extractFromInterfaceOrObjectType(parentClassRef); fields = { ...parentFields, ...fields, }; } } return fields; }; } generateInterfaces(metadata, getParentType) { const prototype = Object.getPrototypeOf(metadata.target); return () => { const interfaces = getInterfacesArray(metadata.interfaces).map((item) => { const definition = this.typeDefinitionsStorage.getInterfaceByTarget(item); if (!definition) { throw new InterfaceNotRegisteredError(metadata.name, item); } return definition.type; }); if (!isUndefined(prototype)) { const parentClass = getParentType(); if (!parentClass) { return interfaces; } const parentInterfaces = parentClass.getInterfaces?.() ?? []; return Array.from(new Set([...interfaces, ...parentInterfaces])); } return interfaces; }; } }; InterfaceDefinitionFactory = __decorate([ Injectable(), __metadata("design:paramtypes", [ResolveTypeFactory, TypeDefinitionsStorage, OutputTypeFactory, OrphanedReferenceRegistry, TypeFieldsAccessor, ArgsFactory, AstDefinitionNodeFactory]) ], InterfaceDefinitionFactory); export { InterfaceDefinitionFactory };