1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.GraphQLFederationFactory = void 0;
|
4 | const tslib_1 = require("tslib");
|
5 | const schema_1 = require("@graphql-tools/schema");
|
6 | const utils_1 = require("@graphql-tools/utils");
|
7 | const common_1 = require("@nestjs/common");
|
8 | const load_package_util_1 = require("@nestjs/common/utils/load-package.util");
|
9 | const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
|
10 | const graphql_1 = require("graphql");
|
11 | const graphql_tag_1 = require("graphql-tag");
|
12 | const lodash_1 = require("lodash");
|
13 | const graphql_schema_builder_1 = require("../graphql-schema.builder");
|
14 | const services_1 = require("../services");
|
15 | const utils_2 = require("../utils");
|
16 | const transform_schema_util_1 = require("../utils/transform-schema.util");
|
17 | const type_defs_decorator_factory_1 = require("./type-defs-decorator.factory");
|
18 | const DEFAULT_FEDERATION_VERSION = 1;
|
19 | let GraphQLFederationFactory = class GraphQLFederationFactory {
|
20 | constructor(resolversExplorerService, scalarsExplorerService, gqlSchemaBuilder, typeDefsDecoratorFactory) {
|
21 | this.resolversExplorerService = resolversExplorerService;
|
22 | this.scalarsExplorerService = scalarsExplorerService;
|
23 | this.gqlSchemaBuilder = gqlSchemaBuilder;
|
24 | this.typeDefsDecoratorFactory = typeDefsDecoratorFactory;
|
25 | }
|
26 | async generateSchema(options = {}, buildFederatedSchema) {
|
27 | const transformSchema = options.transformSchema ?? ((schema) => schema);
|
28 | let schema;
|
29 | if (options.autoSchemaFile) {
|
30 | schema = await this.generateSchemaFromCodeFirst(options, buildFederatedSchema);
|
31 | }
|
32 | else if ((0, lodash_1.isEmpty)(options.typeDefs)) {
|
33 | schema = options.schema;
|
34 | }
|
35 | else {
|
36 | schema = this.buildSchemaFromTypeDefs(options);
|
37 | }
|
38 | return await transformSchema(schema);
|
39 | }
|
40 | buildSchemaFromTypeDefs(options) {
|
41 | const { buildSubgraphSchema } = (0, load_package_util_1.loadPackage)('@apollo/subgraph', 'ApolloFederation', () => require('@apollo/subgraph'));
|
42 | const resolvers = this.getResolvers(options.resolvers);
|
43 | return (0, schema_1.addResolversToSchema)({
|
44 | resolverValidationOptions: options.resolverValidationOptions,
|
45 | inheritResolversFromInterfaces: options.inheritResolversFromInterfaces,
|
46 | resolvers,
|
47 | schema: buildSubgraphSchema([
|
48 | {
|
49 | typeDefs: (0, graphql_tag_1.gql) `
|
50 | ${options.typeDefs}
|
51 | `,
|
52 | resolvers,
|
53 | },
|
54 | ]),
|
55 | });
|
56 | }
|
57 | async generateSchemaFromCodeFirst(options, buildFederatedSchema) {
|
58 | const apolloSubgraph = (0, load_package_util_1.loadPackage)('@apollo/subgraph', 'ApolloFederation', () => require('@apollo/subgraph'));
|
59 | const apolloSubgraphVersion = (await Promise.resolve().then(() => require('@apollo/subgraph/package.json'))).version;
|
60 | const apolloSubgraphMajorVersion = Number(apolloSubgraphVersion.split('.')[0]);
|
61 | const printSubgraphSchema = apolloSubgraph.printSubgraphSchema;
|
62 | if (!buildFederatedSchema) {
|
63 | buildFederatedSchema = apolloSubgraph.buildSubgraphSchema;
|
64 | }
|
65 | const autoGeneratedSchema = await this.buildFederatedSchema(options.autoSchemaFile, options, this.resolversExplorerService.getAllCtors());
|
66 | let typeDefs = apolloSubgraphMajorVersion >= 2
|
67 | ? (0, utils_1.printSchemaWithDirectives)(autoGeneratedSchema)
|
68 | : printSubgraphSchema(autoGeneratedSchema);
|
69 | const [federationVersion, federationOptions] = this.getFederationVersionAndConfig(options.autoSchemaFile);
|
70 | const typeDefsDecorator = this.typeDefsDecoratorFactory.create(federationVersion, apolloSubgraphMajorVersion);
|
71 | if (typeDefsDecorator) {
|
72 | typeDefs = typeDefsDecorator.decorate(typeDefs, federationOptions);
|
73 | }
|
74 | let executableSchema = buildFederatedSchema({
|
75 | typeDefs: (0, graphql_tag_1.gql)(typeDefs),
|
76 | resolvers: this.getResolvers(options.resolvers),
|
77 | });
|
78 | executableSchema = this.overrideOrExtendResolvers(executableSchema, autoGeneratedSchema, printSubgraphSchema);
|
79 | const schema = options.schema
|
80 | ? (0, schema_1.mergeSchemas)({
|
81 | schemas: [options.schema, executableSchema],
|
82 | })
|
83 | : executableSchema;
|
84 | return schema;
|
85 | }
|
86 | getResolvers(optionResolvers) {
|
87 | optionResolvers = Array.isArray(optionResolvers)
|
88 | ? optionResolvers
|
89 | : [optionResolvers];
|
90 | return this.extendResolvers([
|
91 | this.resolversExplorerService.explore(),
|
92 | ...this.scalarsExplorerService.explore(),
|
93 | ...optionResolvers,
|
94 | ]);
|
95 | }
|
96 | extendResolvers(resolvers) {
|
97 | return resolvers.reduce((prev, curr) => (0, utils_2.extend)(prev, curr), {});
|
98 | }
|
99 | overrideOrExtendResolvers(executableSchema, autoGeneratedSchema, printSchema) {
|
100 | return (0, transform_schema_util_1.transformSchema)(executableSchema, (type) => {
|
101 | if ((0, graphql_1.isUnionType)(type) && type.name !== '_Entity') {
|
102 | return this.overrideFederatedResolveType(type, autoGeneratedSchema);
|
103 | }
|
104 | else if ((0, graphql_1.isInterfaceType)(type)) {
|
105 | return this.overrideFederatedResolveType(type, autoGeneratedSchema);
|
106 | }
|
107 | else if ((0, graphql_1.isEnumType)(type)) {
|
108 | return autoGeneratedSchema.getType(type.name);
|
109 | }
|
110 | else if ((0, graphql_1.isInputObjectType)(type)) {
|
111 | const autoGeneratedInputType = autoGeneratedSchema.getType(type.name);
|
112 | if (!autoGeneratedInputType) {
|
113 | return type;
|
114 | }
|
115 | const fields = type.getFields();
|
116 | (0, lodash_1.forEach)(fields, (value, key) => {
|
117 | const field = autoGeneratedInputType.getFields()[key];
|
118 | if (!field) {
|
119 | return;
|
120 | }
|
121 | value.extensions = field.extensions;
|
122 | value.astNode = field.astNode;
|
123 | });
|
124 | type.extensions = autoGeneratedInputType.extensions;
|
125 | return type;
|
126 | }
|
127 | else if ((0, graphql_1.isObjectType)(type)) {
|
128 | const autoGeneratedObjectType = autoGeneratedSchema.getType(type.name);
|
129 | if (!autoGeneratedObjectType) {
|
130 | return type;
|
131 | }
|
132 | const fields = type.getFields();
|
133 | (0, lodash_1.forEach)(fields, (value, key) => {
|
134 | const field = autoGeneratedObjectType.getFields()[key];
|
135 | if (!field) {
|
136 | return;
|
137 | }
|
138 | value.extensions = field.extensions;
|
139 | value.astNode = field.astNode;
|
140 | if (!value.resolve) {
|
141 | value.resolve = field.resolve;
|
142 | }
|
143 | });
|
144 | if (autoGeneratedObjectType.astNode) {
|
145 | type.astNode = {
|
146 | ...type.astNode,
|
147 | ...autoGeneratedObjectType.astNode,
|
148 | };
|
149 | }
|
150 | type.extensions = {
|
151 | ...type.extensions,
|
152 | ...autoGeneratedObjectType.extensions,
|
153 | };
|
154 | return type;
|
155 | }
|
156 | else if ((0, graphql_1.isScalarType)(type) && type.name === 'DateTime') {
|
157 | const autoGeneratedScalar = autoGeneratedSchema.getType(type.name);
|
158 | if (!autoGeneratedScalar) {
|
159 | return type;
|
160 | }
|
161 | type.parseLiteral = autoGeneratedScalar.parseLiteral;
|
162 | type.parseValue = autoGeneratedScalar.parseValue;
|
163 | return type;
|
164 | }
|
165 | return type;
|
166 | });
|
167 | }
|
168 | |
169 |
|
170 |
|
171 |
|
172 | overrideFederatedResolveType(typeInFederatedSchema, autoGeneratedSchema) {
|
173 |
|
174 | const autoGeneratedType = autoGeneratedSchema.getType(typeInFederatedSchema.name);
|
175 |
|
176 | if (!autoGeneratedType ||
|
177 | !(autoGeneratedType instanceof graphql_1.GraphQLUnionType ||
|
178 | autoGeneratedType instanceof graphql_1.GraphQLInterfaceType) ||
|
179 | !autoGeneratedType.resolveType) {
|
180 | return typeInFederatedSchema;
|
181 | }
|
182 | typeInFederatedSchema.resolveType = async (value, context, info, abstractType) => {
|
183 | const resultFromAutogenSchema = await autoGeneratedType.resolveType(value, context, info, abstractType);
|
184 |
|
185 | if (!resultFromAutogenSchema || (0, shared_utils_1.isString)(resultFromAutogenSchema)) {
|
186 | return resultFromAutogenSchema;
|
187 | }
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 | const resultFromFederatedSchema = info.schema.getType(resultFromAutogenSchema.name);
|
195 | if (resultFromFederatedSchema &&
|
196 | resultFromFederatedSchema instanceof graphql_1.GraphQLObjectType) {
|
197 | return resultFromFederatedSchema;
|
198 | }
|
199 |
|
200 |
|
201 | return resultFromAutogenSchema;
|
202 | };
|
203 | return typeInFederatedSchema;
|
204 | }
|
205 | async buildFederatedSchema(autoSchemaFile, options, resolvers) {
|
206 | const scalarsMap = this.scalarsExplorerService.getScalarsMap();
|
207 | try {
|
208 | const buildSchemaOptions = options.buildSchemaOptions || {};
|
209 | const directives = [...graphql_1.specifiedDirectives];
|
210 | const [federationVersion] = this.getFederationVersionAndConfig(autoSchemaFile);
|
211 | if (federationVersion < 2) {
|
212 | directives.push(...this.loadFederationDirectives());
|
213 | }
|
214 | if (buildSchemaOptions?.directives) {
|
215 | directives.push(...buildSchemaOptions.directives);
|
216 | }
|
217 | return await this.gqlSchemaBuilder.generateSchema(resolvers, autoSchemaFile, {
|
218 | ...buildSchemaOptions,
|
219 | directives,
|
220 | scalarsMap,
|
221 | skipCheck: true,
|
222 | }, options.sortSchema, options.transformAutoSchemaFile && options.transformSchema);
|
223 | }
|
224 | catch (err) {
|
225 | if (err && err.details) {
|
226 | console.error(err.details);
|
227 | }
|
228 | throw err;
|
229 | }
|
230 | }
|
231 | getFederationVersionAndConfig(autoSchemaFile) {
|
232 | if (!autoSchemaFile || typeof autoSchemaFile !== 'object') {
|
233 | return [DEFAULT_FEDERATION_VERSION];
|
234 | }
|
235 | if (typeof autoSchemaFile.federation !== 'object') {
|
236 | return [autoSchemaFile.federation ?? DEFAULT_FEDERATION_VERSION];
|
237 | }
|
238 | return [
|
239 | autoSchemaFile.federation?.version ?? DEFAULT_FEDERATION_VERSION,
|
240 | autoSchemaFile.federation,
|
241 | ];
|
242 | }
|
243 | loadFederationDirectives() {
|
244 | const { federationDirectives, directivesWithNoDefinitionNeeded } = (0, load_package_util_1.loadPackage)('@apollo/subgraph/dist/directives', 'SchemaBuilder', () => require('@apollo/subgraph/dist/directives'));
|
245 | return federationDirectives ?? directivesWithNoDefinitionNeeded;
|
246 | }
|
247 | };
|
248 | exports.GraphQLFederationFactory = GraphQLFederationFactory;
|
249 | exports.GraphQLFederationFactory = GraphQLFederationFactory = tslib_1.__decorate([
|
250 | (0, common_1.Injectable)(),
|
251 | tslib_1.__metadata("design:paramtypes", [services_1.ResolversExplorerService,
|
252 | services_1.ScalarsExplorerService,
|
253 | graphql_schema_builder_1.GraphQLSchemaBuilder,
|
254 | type_defs_decorator_factory_1.TypeDefsDecoratorFactory])
|
255 | ], GraphQLFederationFactory);
|