Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
- `apollo-env`
- <First `apollo-env` related entry goes here>
- `apollo-graphql`
- <First `apollo-graphql` related entry goes here>
- buildSchemaFromSDL - Add support for merging Scalar and Enum resolvers to schema [#1345](https://github.com/apollographql/apollo-tooling/pull/1345)
- `apollo-language-server`
- <First `apollo-language-server` related entry goes here>
- `apollo-tools`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import {
GraphQLDirective,
DirectiveLocation,
GraphQLObjectType,
GraphQLAbstractType
GraphQLAbstractType,
GraphQLScalarType,
GraphQLScalarTypeConfig,
GraphQLEnumType,
Kind,
execute,
ExecutionResult
} from "graphql";

import astSerializer from "./snapshotSerializers/astSerializer";
Expand Down Expand Up @@ -422,5 +428,80 @@ type MutationRoot {
expect(animalUnion.resolveType).toBe(resolveTypeUnion);
expect(creatureInterface.resolveType).toBe(resolveTypeInterface);
});

it(`should add resolvers for scalar types`, () => {
const typeDefs = gql`
scalar Custom
`;

const customTypeConfig: GraphQLScalarTypeConfig<string, string> = {
name: "Custom",
serialize: value => value,
parseValue: value => value,
parseLiteral: input => {
if (input.kind !== Kind.STRING) {
throw new Error("Expected value to be string");
}
return input.value;
}
};

const CustomType = new GraphQLScalarType(customTypeConfig);

const resolvers = { Custom: CustomType };

const schema = buildSchemaFromSDL([{ typeDefs, resolvers }]);
const custom = schema.getType("Custom") as GraphQLScalarType;

expect(custom.parseLiteral).toBe(CustomType.parseLiteral);
expect(custom.parseValue).toBe(CustomType.parseValue);
expect(custom.serialize).toBe(CustomType.serialize);
});

it(`should add resolvers to enum types`, () => {
const typeDefs = gql`
enum AllowedColor {
RED
GREEN
BLUE
}

type Query {
favoriteColor: AllowedColor
avatar(borderColor: AllowedColor): String
}
`;

const mockResolver = jest.fn();

const resolvers = {
AllowedColor: {
RED: "#f00",
GREEN: "#0f0",
BLUE: "#00f"
},
Query: {
favoriteColor: () => "#f00",
avatar: (_: any, params: any) => mockResolver(_, params)
}
};

const schema = buildSchemaFromSDL([{ typeDefs, resolvers }]);
const colorEnum = schema.getType("AllowedColor") as GraphQLEnumType;

let result = execute(
schema,
gql`
query {
favoriteColor
avatar(borderColor: RED)
}
`
);

expect((result as ExecutionResult).data!.favoriteColor).toBe("RED");
expect(colorEnum.getValue("RED")!.value).toBe("#f00");
expect(mockResolver).toBeCalledWith(undefined, { borderColor: "#f00" });
});
});
});
39 changes: 38 additions & 1 deletion packages/apollo-graphql/src/schema/buildSchemaFromSDL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import {
SchemaExtensionNode,
OperationTypeNode,
GraphQLObjectType,
isAbstractType
GraphQLEnumType,
isAbstractType,
isScalarType,
isEnumType,
GraphQLEnumValue
} from "graphql";
import { validateSDL } from "graphql/validation/validate";
import { isDocumentNode, isNode } from "../utilities/graphql";
Expand Down Expand Up @@ -216,6 +220,39 @@ export function addResolversToSchema(
}
}

if (isScalarType(type)) {
for (const fn in fieldConfigs) {
(type as any)[fn] = (fieldConfigs as any)[fn];
}
}

if (isEnumType(type)) {
const values = type.getValues();
const newValues: { [key: string]: GraphQLEnumValue } = {};
values.forEach(value => {
const newValue = (fieldConfigs as any)[value.name] || value.name;
newValues[value.name] = {
value: newValue,
deprecationReason: value.deprecationReason,
description: value.description,
astNode: value.astNode,
name: value.name
};
});

// In place updating hack to get around pulling in the full
// schema walking and immutable updating machinery from graphql-tools
Object.assign(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type,
new GraphQLEnumType({
name: type.name,
Comment thread
trevor-scheer marked this conversation as resolved.
Outdated
description: type.description,
astNode: type.astNode,
values: newValues
})
);
}

if (!isObjectType(type)) continue;

const fieldMap = type.getFields();
Expand Down
23 changes: 14 additions & 9 deletions packages/apollo-graphql/src/schema/resolverMap.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { GraphQLFieldResolver } from "graphql";
import { GraphQLFieldResolver, GraphQLScalarType } from "graphql";

export interface GraphQLResolverMap<TContext = {}> {
[typeName: string]: {
[fieldName: string]:
| GraphQLFieldResolver<any, TContext>
| {
requires?: string;
resolve: GraphQLFieldResolver<any, TContext>;
};
};
[typeName: string]:
| {
[fieldName: string]:
| GraphQLFieldResolver<any, TContext>
| {
requires?: string;
resolve: GraphQLFieldResolver<any, TContext>;
};
}
| GraphQLScalarType
| {
[enumValue: string]: string | number;
};
}