@pothos/plugin-federation
Version:
A Pothos plugin for implementing apollo federation subGraphs
124 lines (123 loc) • 6.04 kB
JavaScript
import { printSubgraphSchema } from '@apollo/subgraph';
import { EntityType, entitiesField, serviceField } from '@apollo/subgraph/dist/types.js';
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 _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);
}
var _type_extensions_directives;
const directives = (_type_extensions_directives = (_type_extensions1 = type.extensions) === null || _type_extensions1 === void 0 ? void 0 : _type_extensions1.directives) !== null && _type_extensions_directives !== void 0 ? _type_extensions_directives : {};
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 _options_extensions, _options_composeDirectives;
var _options_composeDirectives_map;
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)
}
},
...(_options_composeDirectives_map = (_options_composeDirectives = options.composeDirectives) === null || _options_composeDirectives === void 0 ? void 0 : _options_composeDirectives.map((name) => ({
name: "composeDirective",
args: {
name
}
}))) !== null && _options_composeDirectives_map !== void 0 ? _options_composeDirectives_map : []
])
}
});
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;
var _queryType_name;
const newQuery = new GraphQLObjectType({
name: (_queryType_name = queryType === null || queryType === void 0 ? void 0 : queryType.name) !== null && _queryType_name !== void 0 ? _queryType_name : "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