@graphql-mesh/fusion-composition
Version:
Basic composition utility for Fusion spec
140 lines (139 loc) • 6.49 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveToDirective = exports.resolveToSourceArgsScalar = void 0;
exports.createEncapsulateTransform = createEncapsulateTransform;
const graphql_1 = require("graphql");
const utils_1 = require("@graphql-tools/utils");
const federation_utils_js_1 = require("../federation-utils.js");
const filter_schema_js_1 = require("./filter-schema.js");
const OPERATION_TYPE_SUFFIX_MAP = {
query: 'Query',
mutation: 'Mutation',
subscription: 'Subscription',
};
const DEFAULT_APPLY_TO = {
query: true,
mutation: true,
subscription: true,
};
function createEncapsulateTransform(opts = {}) {
return function encapsulateTransform(schema, subgraphConfig) {
const groupName = opts.name || subgraphConfig.name;
const applyToMap = {
...DEFAULT_APPLY_TO,
...(opts.applyTo || {}),
};
const newRootTypes = {};
let inaccessibleDirectiveAdded = false;
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];
// Generate sourceArgs to forward all arguments
const sourceArgs = {};
if (originalFieldConfig.args) {
for (const argName in originalFieldConfig.args) {
sourceArgs[argName] = `{args.${argName}}`;
}
}
const wrappedFieldName = `_encapsulated_${groupName}_${fieldName}`;
wrappedFieldMap[fieldName] = {
...originalFieldConfig,
extensions: {
directives: {
resolveTo: [
{
sourceName: subgraphConfig.name,
sourceTypeName: originalType.name,
sourceFieldName: wrappedFieldName,
...(Object.keys(sourceArgs).length > 0 && { sourceArgs }),
},
],
},
},
};
const newOriginalFieldConfig = {
...originalFieldConfig,
astNode: undefined,
};
(0, filter_schema_js_1.addInaccessibleDirective)(newOriginalFieldConfig);
inaccessibleDirectiveAdded = true;
originalFieldMapWithHidden[wrappedFieldName] = newOriginalFieldConfig;
}
const wrappedType = new graphql_1.GraphQLObjectType({
name: wrappedTypeName,
fields: wrappedFieldMap,
});
newRootTypes[operationType] = new graphql_1.GraphQLObjectType({
...originalTypeConfig,
fields: {
...originalFieldMapWithHidden,
[groupName]: {
type: new graphql_1.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(exports.resolveToDirective);
}
const newSchema = new graphql_1.GraphQLSchema({
...schemaConfig,
types: undefined,
directives: newDirectives,
...newRootTypes,
});
const schemaLevelDirectives = (0, utils_1.getDirectiveExtensions)(newSchema);
const importStatement = schemaLevelDirectives?.link?.find(linkDirectiveArgs => linkDirectiveArgs.url?.startsWith('https://specs.apollo.dev/federation/') &&
linkDirectiveArgs.import);
if (importStatement && inaccessibleDirectiveAdded) {
return (0, federation_utils_js_1.importFederationDirectives)(newSchema, ['@inaccessible']);
}
return newSchema;
};
}
exports.resolveToSourceArgsScalar = new graphql_1.GraphQLScalarType({
name: 'ResolveToSourceArgs',
});
exports.resolveToDirective = new graphql_1.GraphQLDirective({
name: 'resolveTo',
locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION],
args: {
additionalArgs: { type: exports.resolveToSourceArgsScalar },
filterBy: { type: graphql_1.GraphQLString },
keyField: { type: graphql_1.GraphQLString },
keysArg: { type: graphql_1.GraphQLString },
pubsubTopic: { type: graphql_1.GraphQLString },
requiredSelectionSet: { type: graphql_1.GraphQLString },
result: { type: graphql_1.GraphQLString },
resultType: { type: graphql_1.GraphQLString },
sourceArgs: { type: exports.resolveToSourceArgsScalar },
sourceFieldName: { type: graphql_1.GraphQLString },
sourceName: { type: graphql_1.GraphQLString },
sourceSelectionSet: { type: graphql_1.GraphQLString },
sourceTypeName: { type: graphql_1.GraphQLString },
},
});