@graphql-mesh/graphql
Version:
163 lines (162 loc) • 7.52 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubgraphSDLQuery = void 0;
exports.getSubschemaForFederationWithTypeDefs = getSubschemaForFederationWithTypeDefs;
const graphql_1 = require("graphql");
const federation_1 = require("@graphql-tools/federation");
const merge_1 = require("@graphql-tools/merge");
const getKeyForFederation = (root) => root;
const SubgraphBaseSDL = /* GraphQL */ `
scalar _Any
scalar _FieldSet
scalar link__Import
enum link__Purpose {
SECURITY
EXECUTION
}
type _Service {
sdl: String!
}
type Query {
_service: _Service!
}
directive on FIELD_DEFINITION | OBJECT
directive on FIELD_DEFINITION
directive on FIELD_DEFINITION
directive repeatable on OBJECT | INTERFACE
directive repeatable on SCHEMA
directive repeatable on OBJECT | FIELD_DEFINITION
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
directive repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
directive on FIELD_DEFINITION
directive repeatable on SCHEMA
directive on OBJECT | INTERFACE
`;
exports.SubgraphSDLQuery = `
query SubgraphSDL {
_service {
sdl
}
}
`;
function getSubschemaForFederationWithTypeDefs(typeDefs) {
const subschemaConfig = {};
const typeMergingConfig = (subschemaConfig.merge = subschemaConfig.merge || {});
const entityTypes = [];
const visitor = (node) => {
if (node.directives) {
const typeName = node.name.value;
const selections = [];
for (const directive of node.directives) {
const directiveArgs = directive.arguments || [];
switch (directive.name.value) {
case 'key': {
if (directiveArgs.some(arg => arg.name.value === 'resolvable' &&
arg.value.kind === graphql_1.Kind.BOOLEAN &&
arg.value.value === false)) {
continue;
}
const selectionValueNode = directiveArgs.find(arg => arg.name.value === 'fields')?.value;
if (selectionValueNode?.kind === graphql_1.Kind.STRING) {
selections.push(selectionValueNode.value);
}
break;
}
case 'inaccessible':
return null;
}
}
// If it is not an entity, continue
if (selections.length === 0) {
return node;
}
const typeMergingTypeConfig = (typeMergingConfig[typeName] =
typeMergingConfig[typeName] || {});
if (node.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION &&
!node.directives?.some(d => d.name.value === 'extends')) {
typeMergingTypeConfig.canonical = true;
}
entityTypes.push(typeName);
const selectionsStr = selections.join(' ');
typeMergingTypeConfig.selectionSet = `{ ${selectionsStr} }`;
typeMergingTypeConfig.dataLoaderOptions = {
cacheKeyFn: (0, federation_1.getCacheKeyFnFromKey)(selectionsStr),
};
typeMergingTypeConfig.argsFromKeys = federation_1.getArgsFromKeysForFederation;
typeMergingTypeConfig.fieldName = `_entities`;
typeMergingTypeConfig.key = getKeyForFederation;
const fields = [];
if (node.fields) {
for (const fieldNode of node.fields) {
let removed = false;
if (fieldNode.directives) {
const fieldName = fieldNode.name.value;
for (const directive of fieldNode.directives) {
const directiveArgs = directive.arguments || [];
switch (directive.name.value) {
case 'requires': {
const typeMergingFieldsConfig = (typeMergingTypeConfig.fields =
typeMergingTypeConfig.fields || {});
typeMergingFieldsConfig[fieldName] = typeMergingFieldsConfig[fieldName] || {};
if (directiveArgs.some(arg => arg.name.value === 'resolvable' &&
arg.value.kind === graphql_1.Kind.BOOLEAN &&
arg.value.value === false)) {
continue;
}
const selectionValueNode = directiveArgs.find(arg => arg.name.value === 'fields')?.value;
if (selectionValueNode?.kind === graphql_1.Kind.STRING) {
typeMergingFieldsConfig[fieldName].selectionSet =
`{ ${selectionValueNode.value} }`;
typeMergingFieldsConfig[fieldName].computed = true;
}
break;
}
case 'external':
case 'inaccessible': {
removed = !typeMergingTypeConfig.selectionSet?.includes(` ${fieldName} `);
break;
}
case 'override': {
const typeMergingFieldsConfig = (typeMergingTypeConfig.fields =
typeMergingTypeConfig.fields || {});
typeMergingFieldsConfig[fieldName] = typeMergingFieldsConfig[fieldName] || {};
typeMergingFieldsConfig[fieldName].canonical = true;
break;
}
}
}
}
if (!removed) {
fields.push(fieldNode);
}
}
node.fields = fields;
}
}
return {
...node,
kind: graphql_1.Kind.OBJECT_TYPE_DEFINITION,
};
};
const parsedSDL = (0, graphql_1.visit)(typeDefs, {
ObjectTypeExtension: visitor,
ObjectTypeDefinition: visitor,
});
let extraSdl = SubgraphBaseSDL;
if (entityTypes.length > 0) {
extraSdl += `\nunion _Entity = ${entityTypes.join(' | ')}`;
extraSdl += `\nextend type Query { _entities(representations: [_Any!]!): [_Entity]! }`;
}
subschemaConfig.schema = (0, graphql_1.buildASTSchema)((0, merge_1.mergeTypeDefs)([extraSdl, parsedSDL]), {
assumeValidSDL: true,
assumeValid: true,
});
return subschemaConfig;
}