Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQLScalarType: make 'serialize' optional with 'identityFunc' as default #1946

Merged
merged 1 commit into from Jun 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 4 additions & 25 deletions src/type/__tests__/definition-test.js
Expand Up @@ -25,7 +25,7 @@ import {
GraphQLNonNull,
} from '../definition';

const ScalarType = new GraphQLScalarType({ name: 'Scalar', serialize() {} });
const ScalarType = new GraphQLScalarType({ name: 'Scalar' });
const ObjectType = new GraphQLObjectType({ name: 'Object', fields: {} });
const InterfaceType = new GraphQLInterfaceType({
name: 'Interface',
Expand All @@ -45,46 +45,28 @@ const NonNullListofScalars = GraphQLNonNull(ListOfScalarsType);

describe('Type System: Scalars', () => {
it('accepts a Scalar type defining serialize', () => {
expect(
() =>
new GraphQLScalarType({
name: 'SomeScalar',
serialize: () => null,
}),
).not.to.throw();
expect(() => new GraphQLScalarType({ name: 'SomeScalar' })).not.to.throw();
});

it('accepts a Scalar type defining parseValue and parseLiteral', () => {
expect(
() =>
new GraphQLScalarType({
name: 'SomeScalar',
serialize: () => null,
parseValue: () => null,
parseLiteral: () => null,
}),
).not.to.throw();
});

it('provides default methods if omitted', () => {
const scalar = new GraphQLScalarType({
name: 'Foo',
serialize: () => null,
});
const scalar = new GraphQLScalarType({ name: 'Foo' });

expect(scalar.serialize).to.equal(identityFunc);
expect(scalar.parseValue).to.equal(identityFunc);
expect(scalar.parseLiteral).to.equal(valueFromASTUntyped);
});

it('rejects a Scalar type not defining serialize', () => {
expect(
// $DisableFlowOnNegativeTest
() => new GraphQLScalarType({ name: 'SomeScalar' }),
).to.throw(
'SomeScalar must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.',
);
});

it('rejects a Scalar type defining serialize with an incorrect type', () => {
expect(
() =>
Expand All @@ -103,7 +85,6 @@ describe('Type System: Scalars', () => {
() =>
new GraphQLScalarType({
name: 'SomeScalar',
serialize: () => null,
parseValue: () => null,
}),
).to.throw(
Expand All @@ -116,7 +97,6 @@ describe('Type System: Scalars', () => {
() =>
new GraphQLScalarType({
name: 'SomeScalar',
serialize: () => null,
parseLiteral: () => null,
}),
).to.throw(
Expand All @@ -129,7 +109,6 @@ describe('Type System: Scalars', () => {
() =>
new GraphQLScalarType({
name: 'SomeScalar',
serialize: () => null,
// $DisableFlowOnNegativeTest
parseValue: {},
// $DisableFlowOnNegativeTest
Expand Down
6 changes: 1 addition & 5 deletions src/type/__tests__/predicate-test.js
Expand Up @@ -83,10 +83,7 @@ const InputObjectType = new GraphQLInputObjectType({
name: 'InputObject',
fields: {},
});
const ScalarType = new GraphQLScalarType({
name: 'Scalar',
serialize() {},
});
const ScalarType = new GraphQLScalarType({ name: 'Scalar' });
const Directive = new GraphQLDirective({
name: 'Directive',
locations: ['QUERY'],
Expand Down Expand Up @@ -711,7 +708,6 @@ describe('Directive predicates', () => {
it('returns false for scalar type named like specified directive', () => {
const ScalarNamedLikeDirective = new GraphQLScalarType({
name: 'deprecated',
serialize: () => null,
});
expect(isSpecifiedDirective(ScalarNamedLikeDirective)).to.equal(false);
});
Expand Down
5 changes: 1 addition & 4 deletions src/type/__tests__/schema-test.js
Expand Up @@ -298,10 +298,7 @@ describe('Type System: Schema', () => {

describe('A Schema must contain uniquely named types', () => {
it('rejects a Schema which redefines a built-in type', () => {
const FakeString = new GraphQLScalarType({
name: 'String',
serialize: () => null,
});
const FakeString = new GraphQLScalarType({ name: 'String' });

const QueryType = new GraphQLObjectType({
name: 'Query',
Expand Down
5 changes: 1 addition & 4 deletions src/type/__tests__/validation-test.js
Expand Up @@ -30,10 +30,7 @@ import { validateSchema } from '../validate';
import { buildSchema } from '../../utilities/buildASTSchema';
import { extendSchema } from '../../utilities/extendSchema';

const SomeScalarType = new GraphQLScalarType({
name: 'SomeScalar',
serialize() {},
});
const SomeScalarType = new GraphQLScalarType({ name: 'SomeScalar' });

const SomeInterfaceType = new GraphQLInterfaceType({
name: 'SomeInterface',
Expand Down
7 changes: 4 additions & 3 deletions src/type/definition.js
Expand Up @@ -559,14 +559,14 @@ export class GraphQLScalarType {
constructor(config: GraphQLScalarTypeConfig<*, *>): void {
this.name = config.name;
this.description = config.description;
this.serialize = config.serialize;
this.serialize = config.serialize || identityFunc;
this.parseValue = config.parseValue || identityFunc;
this.parseLiteral = config.parseLiteral || valueFromASTUntyped;
this.astNode = config.astNode;
this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes);
invariant(typeof config.name === 'string', 'Must provide name.');
invariant(
typeof config.serialize === 'function',
config.serialize == null || typeof config.serialize === 'function',
`${this.name} must provide "serialize" function. If this custom Scalar ` +
'is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.',
);
Expand All @@ -582,6 +582,7 @@ export class GraphQLScalarType {

toConfig(): {|
...GraphQLScalarTypeConfig<*, *>,
serialize: GraphQLScalarSerializer<*>,
parseValue: GraphQLScalarValueParser<*>,
parseLiteral: GraphQLScalarLiteralParser<*>,
extensionASTNodes: $ReadOnlyArray<ScalarTypeExtensionNode>,
Expand Down Expand Up @@ -617,7 +618,7 @@ export type GraphQLScalarTypeConfig<TInternal, TExternal> = {|
name: string,
description?: ?string,
// Serializes an internal value to include in a response.
serialize: GraphQLScalarSerializer<TExternal>,
serialize?: GraphQLScalarSerializer<TExternal>,
// Parses an externally provided value to use as an input.
parseValue?: GraphQLScalarValueParser<TInternal>,
// Parses an externally provided literal value to use as an input.
Expand Down
5 changes: 1 addition & 4 deletions src/utilities/__tests__/extendSchema-test.js
Expand Up @@ -45,10 +45,7 @@ import {
} from '../../type';

// Test schema.
const SomeScalarType = new GraphQLScalarType({
name: 'SomeScalar',
serialize: x => x,
});
const SomeScalarType = new GraphQLScalarType({ name: 'SomeScalar' });

const SomeInterfaceType = new GraphQLInterfaceType({
name: 'SomeInterface',
Expand Down
5 changes: 1 addition & 4 deletions src/utilities/__tests__/schemaPrinter-test.js
Expand Up @@ -405,10 +405,7 @@ describe('Type System Printer', () => {
});

it('Custom Scalar', () => {
const OddType = new GraphQLScalarType({
name: 'Odd',
serialize() {},
});
const OddType = new GraphQLScalarType({ name: 'Odd' });

const Schema = new GraphQLSchema({ types: [OddType] });
const output = printForTest(Schema);
Expand Down
2 changes: 0 additions & 2 deletions src/utilities/buildASTSchema.js
Expand Up @@ -12,7 +12,6 @@ import inspect from '../jsutils/inspect';
import invariant from '../jsutils/invariant';
import keyMap from '../jsutils/keyMap';
import keyValMap from '../jsutils/keyValMap';
import identityFunc from '../jsutils/identityFunc';
import { type ObjMap } from '../jsutils/ObjMap';
import { valueFromAST } from './valueFromAST';
import { assertValidSDL } from '../validation/validate';
Expand Down Expand Up @@ -400,7 +399,6 @@ export class ASTDefinitionBuilder {
name: astNode.name.value,
description: getDescription(astNode, this._options),
astNode,
serialize: identityFunc,
});
}

Expand Down
2 changes: 0 additions & 2 deletions src/utilities/buildClientSchema.js
Expand Up @@ -11,7 +11,6 @@ import objectValues from '../polyfills/objectValues';
import inspect from '../jsutils/inspect';
import invariant from '../jsutils/invariant';
import keyValMap from '../jsutils/keyValMap';
import identityFunc from '../jsutils/identityFunc';
import { valueFromAST } from './valueFromAST';
import { parseValue } from '../language/parser';
import {
Expand Down Expand Up @@ -231,7 +230,6 @@ export function buildClientSchema(
return new GraphQLScalarType({
name: scalarIntrospection.name,
description: scalarIntrospection.description,
serialize: identityFunc,
});
}

Expand Down
10 changes: 1 addition & 9 deletions src/validation/__tests__/harness.js
Expand Up @@ -293,9 +293,6 @@ const ComplicatedArgs = new GraphQLObjectType({

const InvalidScalar = new GraphQLScalarType({
name: 'Invalid',
serialize(value) {
return value;
},
parseLiteral(valueNode) {
throw new Error(`Invalid scalar is always invalid: ${print(valueNode)}`);
},
Expand All @@ -304,12 +301,7 @@ const InvalidScalar = new GraphQLScalarType({
},
});

const AnyScalar = new GraphQLScalarType({
name: 'Any',
serialize(value) {
return value;
},
});
const AnyScalar = new GraphQLScalarType({ name: 'Any' });

const QueryRoot = new GraphQLObjectType({
name: 'QueryRoot',
Expand Down