UNPKG

11.4 kBJavaScriptView Raw
1"use strict";
2var ResolversExplorerService_1;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.ResolversExplorerService = void 0;
5const tslib_1 = require("tslib");
6const common_1 = require("@nestjs/common");
7const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
8const core_1 = require("@nestjs/core");
9const external_context_creator_1 = require("@nestjs/core/helpers/external-context-creator");
10const constants_1 = require("@nestjs/core/injector/constants");
11const injector_1 = require("@nestjs/core/injector/injector");
12const internal_core_module_1 = require("@nestjs/core/injector/internal-core-module");
13const serialized_graph_1 = require("@nestjs/core/inspector/serialized-graph");
14const request_constants_1 = require("@nestjs/core/router/request/request-constants");
15const lodash_1 = require("lodash");
16const abstract_graphql_driver_1 = require("../drivers/abstract-graphql.driver");
17const gql_paramtype_enum_1 = require("../enums/gql-paramtype.enum");
18const resolver_enum_1 = require("../enums/resolver.enum");
19const params_factory_1 = require("../factories/params.factory");
20const graphql_constants_1 = require("../graphql.constants");
21const decorate_field_resolver_util_1 = require("../utils/decorate-field-resolver.util");
22const extract_metadata_util_1 = require("../utils/extract-metadata.util");
23const base_explorer_service_1 = require("./base-explorer.service");
24let ResolversExplorerService = exports.ResolversExplorerService = ResolversExplorerService_1 = class ResolversExplorerService extends base_explorer_service_1.BaseExplorerService {
25 constructor(modulesContainer, metadataScanner, externalContextCreator, gqlOptions, moduleRef, serializedGraph) {
26 super();
27 this.modulesContainer = modulesContainer;
28 this.metadataScanner = metadataScanner;
29 this.externalContextCreator = externalContextCreator;
30 this.gqlOptions = gqlOptions;
31 this.moduleRef = moduleRef;
32 this.serializedGraph = serializedGraph;
33 this.logger = new common_1.Logger(ResolversExplorerService_1.name);
34 this.gqlParamsFactory = new params_factory_1.GqlParamsFactory();
35 this.injector = new injector_1.Injector();
36 }
37 explore() {
38 const modules = this.getModules(this.modulesContainer, this.gqlOptions.include || []);
39 const gqlAdapter = this.moduleRef.get(abstract_graphql_driver_1.AbstractGraphQLDriver);
40 const resolvers = this.flatMap(modules, (instance, moduleRef) => this.filterResolvers(gqlAdapter, instance, moduleRef));
41 return this.groupMetadata(resolvers);
42 }
43 filterResolvers(gqlAdapter, wrapper, moduleRef) {
44 const { instance } = wrapper;
45 if (!instance) {
46 return undefined;
47 }
48 const prototype = Object.getPrototypeOf(instance);
49 const predicate = (resolverType, isReferenceResolver, isPropertyResolver) => (0, shared_utils_1.isUndefined)(resolverType) ||
50 (!isReferenceResolver &&
51 !isPropertyResolver &&
52 ![resolver_enum_1.Resolver.MUTATION, resolver_enum_1.Resolver.QUERY, resolver_enum_1.Resolver.SUBSCRIPTION].some((type) => type === resolverType));
53 const resolvers = this.metadataScanner
54 .getAllMethodNames(prototype)
55 .map((name) => (0, extract_metadata_util_1.extractMetadata)(instance, prototype, name, predicate))
56 .filter((resolver) => !!resolver);
57 const isRequestScoped = !wrapper.isDependencyTreeStatic();
58 return resolvers.map((resolver) => {
59 this.assignResolverConstructorUniqueId(instance.constructor, moduleRef);
60 const entrypointDefinition = {
61 id: `${wrapper.id}_${resolver.methodName}`,
62 type: 'graphql-entrypoint',
63 methodName: resolver.methodName,
64 className: wrapper.name,
65 classNodeId: wrapper.id,
66 metadata: {
67 key: resolver.name,
68 parentType: resolver.type,
69 },
70 };
71 this.serializedGraph.insertEntrypoint(entrypointDefinition, wrapper.id);
72 const createContext = (transform) => this.createContextCallback(instance, prototype, wrapper, moduleRef, resolver, isRequestScoped, transform);
73 if (resolver.type === graphql_constants_1.SUBSCRIPTION_TYPE) {
74 if (!wrapper.isDependencyTreeStatic()) {
75 // Note: We don't throw an exception here for backward
76 // compatibility reasons.
77 this.logger.error(`"${wrapper.metatype.name}" resolver is request or transient-scoped. Resolvers that register subscriptions with the "@Subscription()" decorator must be static (singleton).`);
78 }
79 const subscriptionOptions = Reflect.getMetadata(graphql_constants_1.SUBSCRIPTION_OPTIONS_METADATA, instance[resolver.methodName]);
80 return this.createSubscriptionMetadata(gqlAdapter, createContext, subscriptionOptions, resolver, instance);
81 }
82 return {
83 ...resolver,
84 callback: createContext(),
85 };
86 });
87 }
88 createContextCallback(instance, prototype, wrapper, moduleRef, resolver, isRequestScoped, transform = lodash_1.identity) {
89 const paramsFactory = this.gqlParamsFactory;
90 const isPropertyResolver = ![
91 resolver_enum_1.Resolver.MUTATION,
92 resolver_enum_1.Resolver.QUERY,
93 resolver_enum_1.Resolver.SUBSCRIPTION,
94 ].some((type) => type === resolver.type);
95 const fieldResolverEnhancers = this.gqlOptions.fieldResolverEnhancers || [];
96 const contextOptions = resolver.methodName === graphql_constants_1.FIELD_TYPENAME
97 ? { guards: false, filters: false, interceptors: false }
98 : isPropertyResolver
99 ? {
100 guards: fieldResolverEnhancers.includes('guards'),
101 filters: fieldResolverEnhancers.includes('filters'),
102 interceptors: fieldResolverEnhancers.includes('interceptors'),
103 }
104 : undefined;
105 if (isRequestScoped) {
106 const resolverCallback = async (...args) => {
107 const gqlContext = paramsFactory.exchangeKeyForValue(gql_paramtype_enum_1.GqlParamtype.CONTEXT, undefined, args);
108 const contextId = this.getContextId(gqlContext);
109 this.registerContextProvider(gqlContext, contextId);
110 const contextInstance = await this.injector.loadPerContext(instance, moduleRef, moduleRef.providers, contextId);
111 const callback = this.externalContextCreator.create(contextInstance, transform(contextInstance[resolver.methodName]), resolver.methodName, graphql_constants_1.PARAM_ARGS_METADATA, paramsFactory, contextId, wrapper.id, contextOptions, 'graphql');
112 return callback(...args);
113 };
114 return isPropertyResolver
115 ? this.registerFieldMiddlewareIfExists(resolverCallback, instance, resolver.methodName)
116 : resolverCallback;
117 }
118 const resolverCallback = this.externalContextCreator.create(instance, prototype[resolver.methodName], resolver.methodName, graphql_constants_1.PARAM_ARGS_METADATA, paramsFactory, undefined, undefined, contextOptions, 'graphql');
119 return isPropertyResolver
120 ? this.registerFieldMiddlewareIfExists(resolverCallback, instance, resolver.methodName)
121 : resolverCallback;
122 }
123 createSubscriptionMetadata(gqlAdapter, createSubscribeContext, subscriptionOptions, resolverMetadata, instanceRef) {
124 const resolveFunc = subscriptionOptions &&
125 subscriptionOptions.resolve &&
126 subscriptionOptions.resolve.bind(instanceRef);
127 const baseCallbackMetadata = {
128 resolve: resolveFunc,
129 };
130 if (subscriptionOptions && subscriptionOptions.filter) {
131 return {
132 ...resolverMetadata,
133 callback: {
134 ...baseCallbackMetadata,
135 subscribe: gqlAdapter.subscriptionWithFilter(instanceRef, subscriptionOptions.filter, createSubscribeContext),
136 },
137 };
138 }
139 return {
140 ...resolverMetadata,
141 callback: {
142 ...baseCallbackMetadata,
143 subscribe: createSubscribeContext(),
144 },
145 };
146 }
147 getAllCtors() {
148 const modules = this.getModules(this.modulesContainer, this.gqlOptions.include || []);
149 const resolvers = this.flatMap(modules, this.mapToCtor).filter(Boolean);
150 return resolvers;
151 }
152 mapToCtor(wrapper) {
153 const { instance } = wrapper;
154 if (!instance) {
155 return undefined;
156 }
157 return instance.constructor;
158 }
159 registerContextProvider(request, contextId) {
160 const coreModuleArray = [...this.modulesContainer.entries()]
161 .filter(([key, { metatype }]) => metatype && metatype.name === internal_core_module_1.InternalCoreModule.name)
162 .map(([key, value]) => value);
163 const coreModuleRef = (0, lodash_1.head)(coreModuleArray);
164 if (!coreModuleRef) {
165 return;
166 }
167 const wrapper = coreModuleRef.getProviderByKey(core_1.REQUEST);
168 wrapper.setInstanceByContextId(contextId, {
169 instance: contextId.getParent ? contextId.payload : request,
170 isResolved: true,
171 });
172 }
173 registerFieldMiddlewareIfExists(resolverFn, instance, methodKey) {
174 const fieldMiddleware = Reflect.getMetadata(graphql_constants_1.FIELD_RESOLVER_MIDDLEWARE_METADATA, instance[methodKey]);
175 const middlewareFunctions = (this.gqlOptions?.buildSchemaOptions?.fieldMiddleware || []).concat(fieldMiddleware || []);
176 if (middlewareFunctions?.length === 0) {
177 return resolverFn;
178 }
179 const originalResolveFnFactory = (...args) => () => resolverFn(...args);
180 return (0, decorate_field_resolver_util_1.decorateFieldResolverWithMiddleware)(originalResolveFnFactory, middlewareFunctions);
181 }
182 getContextId(gqlContext) {
183 const contextId = core_1.ContextIdFactory.getByRequest(gqlContext, ['req']);
184 if (!gqlContext[request_constants_1.REQUEST_CONTEXT_ID]) {
185 Object.defineProperty(gqlContext, request_constants_1.REQUEST_CONTEXT_ID, {
186 value: contextId,
187 enumerable: false,
188 configurable: false,
189 writable: false,
190 });
191 }
192 return contextId;
193 }
194 assignResolverConstructorUniqueId(resolverConstructor, moduleRef) {
195 if (resolverConstructor.hasOwnProperty(constants_1.CONTROLLER_ID_KEY)) {
196 return;
197 }
198 moduleRef.assignControllerUniqueId(resolverConstructor);
199 }
200};
201exports.ResolversExplorerService = ResolversExplorerService = ResolversExplorerService_1 = tslib_1.__decorate([
202 (0, common_1.Injectable)(),
203 tslib_1.__param(3, (0, common_1.Inject)(graphql_constants_1.GRAPHQL_MODULE_OPTIONS)),
204 tslib_1.__metadata("design:paramtypes", [core_1.ModulesContainer,
205 core_1.MetadataScanner,
206 external_context_creator_1.ExternalContextCreator, Object, core_1.ModuleRef,
207 serialized_graph_1.SerializedGraph])
208], ResolversExplorerService);