Skip to content

Commit

Permalink
Call 'toJSON' if present for ID and String serialize
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanGoncharov committed Sep 11, 2018
1 parent 3e1c3d4 commit dabbf10
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 29 deletions.
29 changes: 23 additions & 6 deletions src/type/__tests__/serialization-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,22 @@ describe('Type System: Scalar coercion', () => {
expect(GraphQLString.serialize(true)).to.equal('true');
expect(GraphQLString.serialize(false)).to.equal('false');

const stringableObjValue = {
const objValueWithValueOf = {
valueOf() {
return 'something useful';
return 'valueOf string';
},
};
expect(GraphQLString.serialize(stringableObjValue)).to.equal(
'something useful',
expect(GraphQLString.serialize(objValueWithValueOf)).to.equal(
'valueOf string',
);

const objValueWithToJSON = {
toJSON() {
return 'toJSON string';
},
};
expect(GraphQLString.serialize(objValueWithToJSON)).to.equal(
'toJSON string',
);

expect(() => GraphQLString.serialize(NaN)).to.throw(
Expand Down Expand Up @@ -163,13 +172,21 @@ describe('Type System: Scalar coercion', () => {
expect(GraphQLID.serialize(0)).to.equal('0');
expect(GraphQLID.serialize(-1)).to.equal('-1');

const objValue = {
const objValueWithValueOf = {
_id: 123,
valueOf() {
return this._id;
},
};
expect(GraphQLID.serialize(objValue)).to.equal('123');
expect(GraphQLID.serialize(objValueWithValueOf)).to.equal('123');

const objValueWithToJSON = {
_id: 321,
toJSON() {
return this._id;
},
};
expect(GraphQLID.serialize(objValueWithToJSON)).to.equal('321');

const badObjValue = {
_id: false,
Expand Down
56 changes: 33 additions & 23 deletions src/type/scalars.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,24 +117,36 @@ export const GraphQLFloat = new GraphQLScalarType({
},
});

function serializeString(value: mixed): string {
// Support serializing objects with custom valueOf() functions - a common way
// to represent an complex value which can be represented as a string
// (ex: MongoDB id objects).
const result =
value && typeof value.valueOf === 'function' ? value.valueOf() : value;
// Support serializing objects with custom toJSON() or valueOf() functions -
// a common way to represent an complex value which can be represented as
// a string (ex: MongoDB id objects).
function serializeObject(value: mixed): mixed {
if (typeof value === 'object' && value !== null) {
if (typeof value.toJSON === 'function') {
return value.toJSON();
}
if (typeof value.valueOf === 'function') {
return value.valueOf();
}
}
return value;
}

function serializeString(rawValue: mixed): string {
const value = serializeObject(rawValue);

// Serialize string, boolean and number values to a string, but do not
// attempt to coerce object, function, symbol, or other types as strings.
if (typeof result === 'string') {
return result;
if (typeof value === 'string') {
return value;
}
if (typeof result === 'boolean') {
return result ? 'true' : 'false';
if (typeof value === 'boolean') {
return value ? 'true' : 'false';
}
if (isFinite(result)) {
return result.toString();
if (isFinite(value)) {
return value.toString();
}
throw new TypeError(`String cannot represent value: ${inspect(value)}`);
throw new TypeError(`String cannot represent value: ${inspect(rawValue)}`);
}

function coerceString(value: mixed): string {
Expand Down Expand Up @@ -190,18 +202,16 @@ export const GraphQLBoolean = new GraphQLScalarType({
},
});

function serializeID(value: mixed): string {
// Support serializing objects with custom valueOf() functions - a common way
// to represent an object identifier (ex. MongoDB).
const result =
value && typeof value.valueOf === 'function' ? value.valueOf() : value;
if (typeof result === 'string') {
return result;
function serializeID(rawValue: mixed): string {
const value = serializeObject(rawValue);

if (typeof value === 'string') {
return value;
}
if (isInteger(result)) {
return String(result);
if (isInteger(value)) {
return String(value);
}
throw new TypeError(`ID cannot represent value: ${inspect(value)}`);
throw new TypeError(`ID cannot represent value: ${inspect(rawValue)}`);
}

function coerceID(value: mixed): string {
Expand Down

0 comments on commit dabbf10

Please sign in to comment.