UNPKG

@graphql-mesh/fusion-runtime

Version:

Runtime for GraphQL Mesh Fusion Supergraph

195 lines (194 loc) • 9.87 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.handleFederationSupergraph = exports.restoreExtraDirectives = void 0; exports.getStitchingDirectivesTransformerForSubschema = getStitchingDirectivesTransformerForSubschema; const graphql_1 = require("graphql"); const utils_1 = require("@graphql-mesh/utils"); const federation_1 = require("@graphql-tools/federation"); const merge_1 = require("@graphql-tools/merge"); const stitching_directives_1 = require("@graphql-tools/stitching-directives"); const utils_2 = require("@graphql-tools/utils"); const filterHiddenPartsInSchema_js_1 = require("../filterHiddenPartsInSchema.js"); const subgraph_js_1 = require("./subgraph.js"); // Memoize to avoid re-parsing the same schema AST // Workaround for unsupported directives on composition: restore extra directives exports.restoreExtraDirectives = (0, utils_2.memoize1)(function restoreExtraDirectives(schema) { const queryType = schema.getQueryType(); const queryTypeExtensions = (0, utils_2.getDirectiveExtensions)(queryType); const extraSchemaDefinitionDirectives = queryTypeExtensions?.extraSchemaDefinitionDirective; if (extraSchemaDefinitionDirectives?.length) { schema = (0, utils_2.mapSchema)(schema, { [utils_2.MapperKind.TYPE]: type => { const typeDirectiveExtensions = (0, utils_2.getDirectiveExtensions)(type) || {}; const TypeCtor = Object.getPrototypeOf(type).constructor; if (type.name === queryType.name) { const typeConfig = type.toConfig(); // Cleanup extra directives on Query type return new TypeCtor({ ...typeConfig, extensions: { ...(type.extensions || {}), directives: { ...typeDirectiveExtensions, extraSchemaDefinitionDirective: [], }, }, // Cleanup ASTNode to prevent conflicts astNode: undefined, }); } }, }); if (extraSchemaDefinitionDirectives?.length) { const schemaDirectives = (0, utils_2.getDirectiveExtensions)(schema); for (const { directives } of extraSchemaDefinitionDirectives) { for (const directiveName in directives) { schemaDirectives[directiveName] ||= []; schemaDirectives[directiveName].push(...directives[directiveName]); } } const schemaExtensions = (schema.extensions ||= {}); schemaExtensions.directives = schemaDirectives; } } return schema; }); function getStitchingDirectivesTransformerForSubschema() { const { stitchingDirectivesTransformer } = (0, stitching_directives_1.stitchingDirectives)({ keyDirectiveName: 'stitch__key', computedDirectiveName: 'stitch__computed', mergeDirectiveName: 'merge', canonicalDirectiveName: 'stitch__canonical', }); return stitchingDirectivesTransformer; } const handleFederationSupergraph = function ({ unifiedGraph, onSubgraphExecute, additionalTypeDefs: additionalTypeDefsFromConfig = [], additionalResolvers: additionalResolversFromConfig = [], transportEntryAdditions, batch = true, }) { const additionalTypeDefs = [...(0, utils_2.asArray)(additionalTypeDefsFromConfig)]; const additionalResolvers = [...(0, utils_2.asArray)(additionalResolversFromConfig)]; const transportEntryMap = {}; let subschemas = []; const stitchingDirectivesTransformer = getStitchingDirectivesTransformerForSubschema(); unifiedGraph = (0, exports.restoreExtraDirectives)(unifiedGraph); // Get Transport Information from Schema Directives const schemaDirectives = (0, utils_2.getDirectiveExtensions)(unifiedGraph); // Workaround to get the real name of the subschema const realSubgraphNameMap = new Map(); const joinGraphType = unifiedGraph.getType('join__Graph'); if ((0, graphql_1.isEnumType)(joinGraphType)) { for (const enumValue of joinGraphType.getValues()) { const enumValueDirectives = (0, utils_2.getDirectiveExtensions)(enumValue); const joinGraphDirectives = enumValueDirectives?.join__graph; if (joinGraphDirectives?.length) { for (const joinGraphDirective of joinGraphDirectives) { realSubgraphNameMap.set(enumValue.name, joinGraphDirective.name); } } } } let executableUnifiedGraph = (0, federation_1.getStitchedSchemaFromSupergraphSdl)({ supergraphSdl: (0, utils_2.getDocumentNodeFromSchema)(unifiedGraph), /** * This visits over the subgraph schema to get; * - Extra Type Defs and Resolvers (additionalTypeDefs & additionalResolvers) * - Transport Entries (transportEntryMap) * - Type Merging Configuration for the subgraph (subschemaConfig.merge) * - Set the executor for the subschema (subschemaConfig.executor) */ onSubschemaConfig: subschemaConfig => (0, subgraph_js_1.handleFederationSubschema)({ subschemaConfig, realSubgraphNameMap, schemaDirectives, transportEntryMap, additionalTypeDefs, stitchingDirectivesTransformer, onSubgraphExecute, }), batch, onStitchingOptions(opts) { subschemas = opts.subschemas; const mergedTypeDefs = (0, merge_1.mergeTypeDefs)([opts.typeDefs, additionalTypeDefs]); (0, graphql_1.visit)(mergedTypeDefs, { [graphql_1.Kind.FIELD_DEFINITION](field, _key, _parent, _path, ancestors) { const fieldDirectives = (0, utils_2.getDirectiveExtensions)({ astNode: field }); const resolveToDirectives = fieldDirectives?.resolveTo; if (resolveToDirectives?.length) { const targetTypeName = ancestors[ancestors.length - 1] .name.value; const targetFieldName = field.name.value; for (const resolveToDirective of resolveToDirectives) { additionalResolvers.push((0, utils_1.resolveAdditionalResolversWithoutImport)({ targetTypeName, targetFieldName, ...resolveToDirective, })); } } }, }); opts.typeDefs = mergedTypeDefs; opts.resolvers = additionalResolvers; }, onSubgraphAST(_name, subgraphAST) { return (0, graphql_1.visit)(subgraphAST, { [graphql_1.Kind.OBJECT_TYPE_DEFINITION](node) { const typeName = node.name.value; return { ...node, fields: node.fields.filter(fieldNode => { const fieldDirectives = (0, utils_2.getDirectiveExtensions)({ astNode: fieldNode }); const resolveToDirectives = fieldDirectives.resolveTo; if (resolveToDirectives?.length > 0) { additionalTypeDefs.push({ kind: graphql_1.Kind.DOCUMENT, definitions: [ { kind: graphql_1.Kind.OBJECT_TYPE_DEFINITION, name: { kind: graphql_1.Kind.NAME, value: typeName }, fields: [fieldNode], }, ], }); } const additionalFieldDirectives = fieldDirectives.additionalField; if (additionalFieldDirectives?.length > 0) { return false; } return true; }), }; }, }); }, }); // Filter hidden elements with @hidden directive executableUnifiedGraph = (0, filterHiddenPartsInSchema_js_1.filterHiddenPartsInSchema)(executableUnifiedGraph); if (transportEntryAdditions) { const wildcardTransportOptions = transportEntryAdditions['*']; for (const subgraphName in transportEntryMap) { const toBeMerged = []; const transportEntry = transportEntryMap[subgraphName]; if (transportEntry) { toBeMerged.push(transportEntry); } const transportOptionBySubgraph = transportEntryAdditions[subgraphName]; if (transportOptionBySubgraph) { toBeMerged.push(transportOptionBySubgraph); } const transportOptionByKind = transportEntryAdditions['*.' + transportEntry?.kind]; if (transportOptionByKind) { toBeMerged.push(transportOptionByKind); } if (wildcardTransportOptions) { toBeMerged.push(wildcardTransportOptions); } transportEntryMap[subgraphName] = (0, utils_2.mergeDeep)(toBeMerged); } } return { unifiedGraph: executableUnifiedGraph, subschemas, transportEntryMap, additionalResolvers, }; }; exports.handleFederationSupergraph = handleFederationSupergraph;