@pothos/plugin-federation
Version:
A Pothos plugin for implementing apollo federation subGraphs
123 lines (122 loc) • 5.82 kB
JavaScript
import { printSubgraphSchema } from '@apollo/subgraph';
import { EntityType, entitiesField, serviceField } from '@apollo/subgraph/dist/types';
import SchemaBuilder from '@pothos/core';
import { GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLUnionType, isObjectType, lexicographicSortSchema } from 'graphql';
import { ExternalEntityRef } from './external-ref.js';
import { selectionShapeKey } from './types.js';
import { entityMapping, getUsedDirectives, mergeDirectives } from './util.js';
const schemaBuilderProto = SchemaBuilder.prototype;
export function hasResolvableKey(type) {
var _ref;
var _type_extensions, _type_extensions1, _directives_key;
if (Array.isArray((_type_extensions = type.extensions) === null || _type_extensions === void 0 ? void 0 : _type_extensions.directives)) {
var _type_extensions2;
return (_type_extensions2 = type.extensions) === null || _type_extensions2 === void 0 ? void 0 : _type_extensions2.directives.some((d)=>d.name === 'key' && d.args.resolvable !== false);
}
const directives = (_ref = (_type_extensions1 = type.extensions) === null || _type_extensions1 === void 0 ? void 0 : _type_extensions1.directives) !== null && _ref !== void 0 ? _ref : {};
if (!('key' in directives)) {
return false;
}
if (Array.isArray(directives.key)) {
return directives.key.some((d)=>d.resolvable !== false);
}
return ((_directives_key = directives.key) === null || _directives_key === void 0 ? void 0 : _directives_key.resolvable) !== false;
}
schemaBuilderProto.selection = (selection)=>({
selection,
[selectionShapeKey]: {}
});
schemaBuilderProto.keyDirective = (key, resolvable)=>({
...key,
resolvable
});
schemaBuilderProto.externalRef = function externalRef(name, key, resolveReference) {
return new ExternalEntityRef(this, name, {
key,
resolveReference
});
};
schemaBuilderProto.toSubGraphSchema = function toSubGraphSchema({ linkUrl = 'https://specs.apollo.dev/federation/v2.6', federationDirectives = getUsedDirectives(this), ...options }) {
var _ref, _ref1;
var _options_extensions, _options_composeDirectives;
const schema = this.toSchema({
...options,
extensions: {
...options.extensions,
directives: mergeDirectives(options === null || options === void 0 ? void 0 : (_options_extensions = options.extensions) === null || _options_extensions === void 0 ? void 0 : _options_extensions.directives, [
{
name: 'link',
args: {
url: linkUrl,
import: [
...federationDirectives,
options.composeDirectives ? '@composeDirective' : null
].filter(Boolean)
}
},
...(_ref = (_options_composeDirectives = options.composeDirectives) === null || _options_composeDirectives === void 0 ? void 0 : _options_composeDirectives.map((name)=>({
name: 'composeDirective',
args: {
name
}
}))) !== null && _ref !== void 0 ? _ref : []
])
}
});
const queryType = schema.getQueryType();
const types = schema.getTypeMap();
queryType === null || queryType === void 0 ? void 0 : queryType.toConfig();
const entityTypes = Object.values(types).filter((type)=>isObjectType(type) && hasResolvableKey(type));
const hasEntities = entityTypes.length > 0;
const newQuery = new GraphQLObjectType({
name: (_ref1 = queryType === null || queryType === void 0 ? void 0 : queryType.name) !== null && _ref1 !== void 0 ? _ref1 : 'Query',
description: queryType === null || queryType === void 0 ? void 0 : queryType.description,
astNode: queryType === null || queryType === void 0 ? void 0 : queryType.astNode,
extensions: queryType === null || queryType === void 0 ? void 0 : queryType.extensions,
fields: ()=>{
const updatedEntityType = new GraphQLUnionType({
...EntityType.toConfig(),
types: entityTypes.filter(isObjectType).map((type)=>type === queryType ? newQuery : type)
});
return {
...hasEntities && {
_entities: {
...entitiesField,
type: new GraphQLNonNull(new GraphQLList(updatedEntityType))
}
},
_service: {
...serviceField,
resolve: ()=>({
sdl
})
},
...queryType === null || queryType === void 0 ? void 0 : queryType.toConfig().fields
};
}
});
const subGraphSchema = new GraphQLSchema({
query: newQuery,
mutation: schema.getMutationType(),
subscription: schema.getSubscriptionType(),
extensions: schema.extensions,
directives: schema.getDirectives(),
extensionASTNodes: schema.extensionASTNodes,
types: [
...Object.values(types).filter((type)=>type.name !== 'Query'),
newQuery
]
});
const sorted = lexicographicSortSchema(subGraphSchema);
const sdl = printSubgraphSchema(sorted);
return sorted;
};
schemaBuilderProto.asEntity = function asEntity(param, options) {
if (!entityMapping.has(this)) {
entityMapping.set(this, new Map());
}
this.configStore.onTypeConfig(param, (config)=>{
entityMapping.get(this).set(config.name, options);
});
};
//# sourceMappingURL=schema-builder.js.map