Skip to content

Commit

Permalink
Change serialization for Int, Float and Boolean to work with objects (#…
Browse files Browse the repository at this point in the history
…2382)

It is good to have an opportunity to pass objects which have valueOf() method in resolvers.
For example, I have such objects as "Money", "Price" and so on in my app, and they have valueOf() method which returns a value.
  • Loading branch information
alex-knyazev authored and IvanGoncharov committed Jan 23, 2020
1 parent 9dba58e commit f31f505
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 18 deletions.
24 changes: 24 additions & 0 deletions src/type/__tests__/serialization-test.js
Expand Up @@ -20,6 +20,14 @@ describe('Type System: Scalar coercion', () => {
expect(GraphQLInt.serialize(1e5)).to.equal(100000);
expect(GraphQLInt.serialize(false)).to.equal(0);
expect(GraphQLInt.serialize(true)).to.equal(1);
expect(
GraphQLInt.serialize({
value: 5,
valueOf() {
return this.value;
},
}),
).to.equal(5);

// The GraphQL specification does not allow serializing non-integer values
// as Int to avoid accidental data loss.
Expand Down Expand Up @@ -79,6 +87,14 @@ describe('Type System: Scalar coercion', () => {
expect(GraphQLFloat.serialize('-1.1')).to.equal(-1.1);
expect(GraphQLFloat.serialize(false)).to.equal(0.0);
expect(GraphQLFloat.serialize(true)).to.equal(1.0);
expect(
GraphQLFloat.serialize({
value: 5.5,
valueOf() {
return this.value;
},
}),
).to.equal(5.5);

expect(() => GraphQLFloat.serialize(NaN)).to.throw(
'Float cannot represent non numeric value: NaN',
Expand Down Expand Up @@ -139,6 +155,14 @@ describe('Type System: Scalar coercion', () => {
expect(GraphQLBoolean.serialize(0)).to.equal(false);
expect(GraphQLBoolean.serialize(true)).to.equal(true);
expect(GraphQLBoolean.serialize(false)).to.equal(false);
expect(
GraphQLBoolean.serialize({
value: true,
valueOf() {
return this.value;
},
}),
).to.equal(true);

expect(() => GraphQLBoolean.serialize(NaN)).to.throw(
'Boolean cannot represent a non boolean value: NaN',
Expand Down
43 changes: 25 additions & 18 deletions src/type/scalars.js
Expand Up @@ -22,24 +22,26 @@ const MAX_INT = 2147483647;
const MIN_INT = -2147483648;

function serializeInt(outputValue: mixed): number {
if (typeof outputValue === 'boolean') {
return outputValue ? 1 : 0;
const coercedValue = serializeObject(outputValue);

if (typeof coercedValue === 'boolean') {
return coercedValue ? 1 : 0;
}

let num = outputValue;
if (typeof outputValue === 'string' && outputValue !== '') {
num = Number(outputValue);
let num = coercedValue;
if (typeof coercedValue === 'string' && coercedValue !== '') {
num = Number(coercedValue);
}

if (!isInteger(num)) {
throw new GraphQLError(
`Int cannot represent non-integer value: ${inspect(outputValue)}`,
`Int cannot represent non-integer value: ${inspect(coercedValue)}`,
);
}
if (num > MAX_INT || num < MIN_INT) {
throw new GraphQLError(
'Int cannot represent non 32-bit signed integer value: ' +
inspect(outputValue),
inspect(coercedValue),
);
}
return num;
Expand Down Expand Up @@ -84,17 +86,20 @@ export const GraphQLInt = new GraphQLScalarType({
});

function serializeFloat(outputValue: mixed): number {
if (typeof outputValue === 'boolean') {
return outputValue ? 1 : 0;
const coercedValue = serializeObject(outputValue);

if (typeof coercedValue === 'boolean') {
return coercedValue ? 1 : 0;
}

let num = outputValue;
if (typeof outputValue === 'string' && outputValue !== '') {
num = Number(outputValue);
let num = coercedValue;
if (typeof coercedValue === 'string' && coercedValue !== '') {
num = Number(coercedValue);
}

if (!isFinite(num)) {
throw new GraphQLError(
`Float cannot represent non numeric value: ${inspect(outputValue)}`,
`Float cannot represent non numeric value: ${inspect(coercedValue)}`,
);
}
return num;
Expand Down Expand Up @@ -191,14 +196,16 @@ export const GraphQLString = new GraphQLScalarType({
});

function serializeBoolean(outputValue: mixed): boolean {
if (typeof outputValue === 'boolean') {
return outputValue;
const coercedValue = serializeObject(outputValue);

if (typeof coercedValue === 'boolean') {
return coercedValue;
}
if (isFinite(outputValue)) {
return outputValue !== 0;
if (isFinite(coercedValue)) {
return coercedValue !== 0;
}
throw new GraphQLError(
`Boolean cannot represent a non boolean value: ${inspect(outputValue)}`,
`Boolean cannot represent a non boolean value: ${inspect(coercedValue)}`,
);
}

Expand Down

0 comments on commit f31f505

Please sign in to comment.