Skip to content

Commit 0ca6cf0

Browse files
committed
Merge branch 'astValueToData' of https://github.com/APIs-guru/graphql-js into APIs-guru-astValueToData
2 parents 37717b8 + 78e69d6 commit 0ca6cf0

9 files changed

+171
-21
lines changed

src/type/definition.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import isNullish from '../jsutils/isNullish';
1212
import type {ObjMap} from '../jsutils/ObjMap';
1313
import * as Kind from '../language/kinds';
1414
import { assertValidName } from '../utilities/assertValidName';
15+
import { scalarValueFromAST } from '../utilities/scalarValueFromAST';
1516
import type {
1617
ScalarTypeDefinitionNode,
1718
ObjectTypeDefinitionNode,
@@ -347,7 +348,10 @@ export class GraphQLScalarType {
347348
// Parses an externally provided value to use as an input.
348349
parseValue(value: mixed): mixed {
349350
const parser = this._scalarConfig.parseValue;
350-
return parser && !isNullish(value) ? parser(value) : undefined;
351+
if (isNullish(value)) {
352+
return undefined;
353+
}
354+
return parser ? parser(value) : value;
351355
}
352356

353357
// Determines if an internal value is valid for this type.
@@ -359,7 +363,7 @@ export class GraphQLScalarType {
359363
// Parses an externally provided literal value to use as an input.
360364
parseLiteral(valueNode: ValueNode): mixed {
361365
const parser = this._scalarConfig.parseLiteral;
362-
return parser ? parser(valueNode) : undefined;
366+
return (parser || scalarValueFromAST)(valueNode);
363367
}
364368

365369
toString(): string {

src/utilities/__tests__/buildASTSchema-test.js

+16
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,22 @@ describe('Schema Builder', () => {
473473
expect(output).to.equal(body);
474474
});
475475

476+
it('Custom scalar argument field with default', () => {
477+
const body = dedent`
478+
schema {
479+
query: Hello
480+
}
481+
482+
scalar CustomScalar
483+
484+
type Hello {
485+
str(int: CustomScalar = 2): String
486+
}
487+
`;
488+
const output = cycleOutput(body);
489+
expect(output).to.equal(body);
490+
});
491+
476492
it('Simple type with mutation', () => {
477493
const body = dedent`
478494
schema {

src/utilities/__tests__/buildClientSchema-test.js

+24
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,30 @@ describe('Type System: build schema from introspection', () => {
341341
await testSchema(schema);
342342
});
343343

344+
it('builds a schema with default value on custom scalar field', async () => {
345+
const schema = new GraphQLSchema({
346+
query: new GraphQLObjectType({
347+
name: 'ArgFields',
348+
fields: {
349+
testField: {
350+
type: GraphQLString,
351+
args: {
352+
testArg: {
353+
type: new GraphQLScalarType({
354+
name: 'CustomScalar',
355+
serialize: value => value
356+
}),
357+
defaultValue: 'default'
358+
}
359+
}
360+
}
361+
}
362+
})
363+
});
364+
365+
await testSchema(schema);
366+
});
367+
344368
it('builds a schema with an enum', async () => {
345369
const foodEnum = new GraphQLEnumType({
346370
name: 'Food',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* Copyright (c) 2017, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
import { describe, it } from 'mocha';
11+
import { expect } from 'chai';
12+
import { scalarValueFromAST } from '../scalarValueFromAST';
13+
import { parseValue } from '../../language';
14+
15+
describe('scalarValueFromAST', () => {
16+
17+
function testCase(valueText, expected) {
18+
expect(
19+
scalarValueFromAST(parseValue(valueText))
20+
).to.deep.equal(expected);
21+
}
22+
23+
function testNegativeCase(valueText, errorMsg) {
24+
expect(
25+
() => scalarValueFromAST(parseValue(valueText))
26+
).to.throw(errorMsg);
27+
}
28+
29+
it('parses simple values', () => {
30+
testCase('null', null);
31+
testCase('true', true);
32+
testCase('false', false);
33+
testCase('123', 123);
34+
testCase('123.456', 123.456);
35+
testCase('"abc123"', 'abc123');
36+
});
37+
38+
it('parses lists of values', () => {
39+
testCase('[true, false]', [ true, false ]);
40+
testCase('[true, 123.45]', [ true, 123.45 ]);
41+
testCase('[true, null]', [ true, null ]);
42+
testCase('[true, ["foo", 1.2]]', [ true, [ 'foo', 1.2 ] ]);
43+
});
44+
45+
it('parses input objects', () => {
46+
testCase(
47+
'{ int: 123, requiredBool: false }',
48+
{ int: 123, requiredBool: false }
49+
);
50+
testCase(
51+
'{ foo: [{ bar: "baz"}]}',
52+
{ foo: [ { bar: 'baz'} ] }
53+
);
54+
});
55+
56+
it('rejects enum values and query variables', () => {
57+
testNegativeCase('TEST_ENUM_VALUE', 'Scalar value can not contain Enum.');
58+
testNegativeCase(
59+
'$test_variable',
60+
'Scalar value can not contain Query variable.'
61+
);
62+
testNegativeCase('[TEST_ENUM_VALUE]', 'Scalar value can not contain Enum.');
63+
testNegativeCase(
64+
'[$test_variable]',
65+
'Scalar value can not contain Query variable.'
66+
);
67+
testNegativeCase(
68+
'{foo: TEST_ENUM_VALUE}',
69+
'Scalar value can not contain Enum.'
70+
);
71+
testNegativeCase(
72+
'{bar: $test_variable}',
73+
'Scalar value can not contain Query variable.'
74+
);
75+
});
76+
77+
});

src/utilities/buildASTSchema.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -446,13 +446,7 @@ export function buildASTSchema(
446446
name: def.name.value,
447447
description: getDescription(def, options),
448448
astNode: def,
449-
serialize: () => null,
450-
// Note: validation calls the parse functions to determine if a
451-
// literal value is correct. Returning null would cause use of custom
452-
// scalars to always fail validation. Returning false causes them to
453-
// always pass validation.
454-
parseValue: () => false,
455-
parseLiteral: () => false,
449+
serialize: value => value,
456450
});
457451
}
458452

src/utilities/buildClientSchema.js

-6
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,6 @@ export function buildClientSchema(
237237
name: scalarIntrospection.name,
238238
description: scalarIntrospection.description,
239239
serialize: id => id,
240-
// Note: validation calls the parse functions to determine if a
241-
// literal value is correct. Returning null would cause use of custom
242-
// scalars to always fail validation. Returning false causes them to
243-
// always pass validation.
244-
parseValue: () => false,
245-
parseLiteral: () => false,
246240
});
247241
}
248242

src/utilities/extendSchema.js

-6
Original file line numberDiff line numberDiff line change
@@ -506,12 +506,6 @@ export function extendSchema(
506506
description: getDescription(typeNode, options),
507507
astNode: typeNode,
508508
serialize: id => id,
509-
// Note: validation calls the parse functions to determine if a
510-
// literal value is correct. Returning null would cause use of custom
511-
// scalars to always fail validation. Returning false causes them to
512-
// always pass validation.
513-
parseValue: () => false,
514-
parseLiteral: () => false,
515509
});
516510
}
517511

src/utilities/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ export { valueFromAST } from './valueFromAST';
6161
// Create a GraphQL language AST from a JavaScript value.
6262
export { astFromValue } from './astFromValue';
6363

64+
// Create a JavaScript value from a GraphQL language AST representation
65+
// of Scalar.
66+
export { scalarValueFromAST } from './scalarValueFromAST';
67+
6468
// A helper to use within recursive-descent visitors which need to be aware of
6569
// the GraphQL type system.
6670
export { TypeInfo } from './TypeInfo';

src/utilities/scalarValueFromAST.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* @flow */
2+
/**
3+
* Copyright (c) 2017, Facebook, Inc.
4+
* All rights reserved.
5+
*
6+
* This source code is licensed under the BSD-style license found in the
7+
* LICENSE file in the root directory of this source tree. An additional grant
8+
* of patent rights can be found in the PATENTS file in the same directory.
9+
*/
10+
11+
import keyValMap from '../jsutils/keyValMap';
12+
import * as Kind from '../language/kinds';
13+
import type { ValueNode } from '../language/ast';
14+
15+
/**
16+
* Create a JavaScript value from a GraphQL language AST representation
17+
* of Scalar.
18+
*/
19+
export function scalarValueFromAST(astValue: ValueNode): mixed {
20+
switch (astValue.kind) {
21+
case Kind.NULL:
22+
return null;
23+
case Kind.INT:
24+
return parseInt(astValue.value, 10);
25+
case Kind.FLOAT:
26+
return parseFloat(astValue.value);
27+
case Kind.STRING:
28+
case Kind.BOOLEAN:
29+
return astValue.value;
30+
case Kind.LIST:
31+
return astValue.values.map(scalarValueFromAST);
32+
case Kind.OBJECT:
33+
return keyValMap(
34+
astValue.fields,
35+
field => field.name.value,
36+
field => scalarValueFromAST(field.value),
37+
);
38+
case Kind.ENUM:
39+
throw new Error('Scalar value can not contain Enum.');
40+
case Kind.VARIABLE:
41+
throw new Error('Scalar value can not contain Query variable.');
42+
}
43+
}

0 commit comments

Comments
 (0)