Skip to content

Commit

Permalink
Add transformFederatedSchema
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-watson committed Aug 23, 2023
1 parent c44f0ca commit b4d85c6
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
1 change: 1 addition & 0 deletions subgraph-js/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { buildSubgraphSchema } from './buildSubgraphSchema';
export { printSubgraphSchema } from './printSubgraphSchema';
export { transformFederatedSchema } from './transformFederatedSchema';
80 changes: 80 additions & 0 deletions subgraph-js/src/transformFederatedSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {
GraphQLSchema,
isObjectType,
isUnionType,
GraphQLUnionType,
GraphQLObjectType,
} from 'graphql';
import {
transformSchema,
addResolversToSchema,
GraphQLResolverMap,
} from './schema-helper';
import { typeIncludesDirective } from './directives';
import { serviceField, entitiesField, EntityType } from './types';
import { printSubgraphSchema } from './printSubgraphSchema';

export function transformFederatedSchema(
schema: GraphQLSchema,
resolvers: GraphQLResolverMap<any>[] = [],
): GraphQLSchema {
// At this point in time, we have a schema to be printed into SDL which is
// representative of what the user defined for their schema. This is before
// we process any of the federation directives and add custom federation types
// so its the right place to create our service definition sdl.
//
// We have to use a modified printSchema from graphql-js which includes
// support for preserving the *uses* of federation directives while removing
// their *definitions* from the sdl.
const sdl = printSubgraphSchema(schema);

// Add an empty query root type if none has been defined
if (!schema.getQueryType()) {
schema = new GraphQLSchema({
...schema.toConfig(),
query: new GraphQLObjectType({
name: 'Query',
fields: {},
}),
});
}

const entityTypes = Object.values(schema.getTypeMap()).filter(
type => isObjectType(type) && typeIncludesDirective(type, 'key'),
);
const hasEntities = entityTypes.length > 0;

schema = transformSchema(schema, type => {
// Add `_entities` and `_service` fields to query root type
if (isObjectType(type) && type === schema.getQueryType()) {
const config = type.toConfig();
return new GraphQLObjectType({
...config,
fields: {
...(hasEntities && { _entities: entitiesField }),
_service: {
...serviceField,
resolve: () => ({ sdl }),
},
...config.fields,
},
});
}

return undefined;
});

schema = transformSchema(schema, type => {
if (hasEntities && isUnionType(type) && type.name === EntityType.name) {
return new GraphQLUnionType({
...EntityType.toConfig(),
types: entityTypes.filter(isObjectType),
});
}
return undefined;
});

resolvers.forEach(resolver => addResolversToSchema(schema, resolver));

return schema;
}

0 comments on commit b4d85c6

Please sign in to comment.