UNPKG

@graphql-mesh/fusion-composition

Version:

Basic composition utility for Fusion spec

116 lines (115 loc) 4.91 kB
import { DirectiveLocation, GraphQLDirective, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, } from 'graphql'; import { addInaccessibleDirective } from './filter-schema.js'; const OPERATION_TYPE_SUFFIX_MAP = { query: 'Query', mutation: 'Mutation', subscription: 'Subscription', }; const DEFAULT_APPLY_TO = { query: true, mutation: true, subscription: true, }; export function createEncapsulateTransform(opts = {}) { return function encapsulateTransform(schema, subgraphConfig) { const groupName = opts.name || subgraphConfig.name; const applyToMap = { ...DEFAULT_APPLY_TO, ...(opts.applyTo || {}), }; const newRootTypes = {}; for (const opTypeString in applyToMap) { const operationType = opTypeString; const originalType = schema.getRootType(operationType); if (originalType && applyToMap[operationType]) { const originalTypeConfig = originalType.toConfig(); const wrappedTypeName = `${groupName}${OPERATION_TYPE_SUFFIX_MAP[operationType]}`; const originalFieldMapWithHidden = {}; const wrappedFieldMap = {}; for (const fieldName in originalTypeConfig.fields) { const originalFieldConfig = originalTypeConfig.fields[fieldName]; wrappedFieldMap[fieldName] = { ...originalFieldConfig, extensions: { directives: { resolveTo: [ { sourceName: subgraphConfig.name, sourceTypeName: originalType.name, sourceFieldName: fieldName, }, ], }, }, }; const newOriginalFieldConfig = { ...originalFieldConfig, astNode: undefined, }; addInaccessibleDirective(newOriginalFieldConfig); originalFieldMapWithHidden[fieldName] = newOriginalFieldConfig; } const wrappedType = new GraphQLObjectType({ name: wrappedTypeName, fields: wrappedFieldMap, }); newRootTypes[operationType] = new GraphQLObjectType({ ...originalTypeConfig, fields: { ...originalFieldMapWithHidden, [groupName]: { type: new GraphQLNonNull(wrappedType), extensions: { directives: { resolveTo: [ { sourceName: subgraphConfig.name, sourceTypeName: originalType.name, sourceFieldName: '__typename', }, ], }, }, }, }, }); } else { newRootTypes[operationType] = originalType; } } const schemaConfig = schema.toConfig(); const newDirectives = [...schemaConfig.directives]; if (!newDirectives.some(directive => directive.name === 'resolveTo')) { newDirectives.push(resolveToDirective); } return new GraphQLSchema({ ...schemaConfig, types: undefined, directives: newDirectives, ...newRootTypes, }); }; } export const resolveToSourceArgsScalar = new GraphQLScalarType({ name: 'ResolveToSourceArgs', }); export const resolveToDirective = new GraphQLDirective({ name: 'resolveTo', locations: [DirectiveLocation.FIELD_DEFINITION], args: { additionalArgs: { type: resolveToSourceArgsScalar }, filterBy: { type: GraphQLString }, keyField: { type: GraphQLString }, keysArg: { type: GraphQLString }, pubsubTopic: { type: GraphQLString }, requiredSelectionSet: { type: GraphQLString }, result: { type: GraphQLString }, resultType: { type: GraphQLString }, sourceArgs: { type: resolveToSourceArgsScalar }, sourceFieldName: { type: GraphQLString }, sourceName: { type: GraphQLString }, sourceSelectionSet: { type: GraphQLString }, sourceTypeName: { type: GraphQLString }, }, });