Skip to content

Commit bf798d6

Browse files
committed
Call 'toJSON' if present for ID and String serialize
Fixes #1518
1 parent 3e1c3d4 commit bf798d6

File tree

2 files changed

+56
-29
lines changed

2 files changed

+56
-29
lines changed

src/type/__tests__/serialization-test.js

+23-6
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,22 @@ describe('Type System: Scalar coercion', () => {
109109
expect(GraphQLString.serialize(true)).to.equal('true');
110110
expect(GraphQLString.serialize(false)).to.equal('false');
111111

112-
const stringableObjValue = {
112+
const objValueWithValueOf = {
113113
valueOf() {
114-
return 'something useful';
114+
return 'valueOf string';
115115
},
116116
};
117-
expect(GraphQLString.serialize(stringableObjValue)).to.equal(
118-
'something useful',
117+
expect(GraphQLString.serialize(objValueWithValueOf)).to.equal(
118+
'valueOf string',
119+
);
120+
121+
const objValueWithToJSON = {
122+
toJSON() {
123+
return 'toJSON string';
124+
},
125+
};
126+
expect(GraphQLString.serialize(objValueWithToJSON)).to.equal(
127+
'toJSON string',
119128
);
120129

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

166-
const objValue = {
175+
const objValueWithValueOf = {
167176
_id: 123,
168177
valueOf() {
169178
return this._id;
170179
},
171180
};
172-
expect(GraphQLID.serialize(objValue)).to.equal('123');
181+
expect(GraphQLID.serialize(objValueWithValueOf)).to.equal('123');
182+
183+
const objValueWithToJSON = {
184+
_id: 321,
185+
toJSON() {
186+
return this._id;
187+
},
188+
};
189+
expect(GraphQLID.serialize(objValueWithToJSON)).to.equal('321');
173190

174191
const badObjValue = {
175192
_id: false,

src/type/scalars.js

+33-23
Original file line numberDiff line numberDiff line change
@@ -117,24 +117,36 @@ export const GraphQLFloat = new GraphQLScalarType({
117117
},
118118
});
119119

120-
function serializeString(value: mixed): string {
121-
// Support serializing objects with custom valueOf() functions - a common way
122-
// to represent an complex value which can be represented as a string
123-
// (ex: MongoDB id objects).
124-
const result =
125-
value && typeof value.valueOf === 'function' ? value.valueOf() : value;
120+
// Support serializing objects with custom toJSON() or valueOf() functions -
121+
// a common way to represent a complex value which can be represented as
122+
// a string (ex: MongoDB id objects).
123+
function serializeObject(value: mixed): mixed {
124+
if (typeof value === 'object' && value !== null) {
125+
if (typeof value.toJSON === 'function') {
126+
return value.toJSON();
127+
}
128+
if (typeof value.valueOf === 'function') {
129+
return value.valueOf();
130+
}
131+
}
132+
return value;
133+
}
134+
135+
function serializeString(rawValue: mixed): string {
136+
const value = serializeObject(rawValue);
137+
126138
// Serialize string, boolean and number values to a string, but do not
127139
// attempt to coerce object, function, symbol, or other types as strings.
128-
if (typeof result === 'string') {
129-
return result;
140+
if (typeof value === 'string') {
141+
return value;
130142
}
131-
if (typeof result === 'boolean') {
132-
return result ? 'true' : 'false';
143+
if (typeof value === 'boolean') {
144+
return value ? 'true' : 'false';
133145
}
134-
if (isFinite(result)) {
135-
return result.toString();
146+
if (isFinite(value)) {
147+
return value.toString();
136148
}
137-
throw new TypeError(`String cannot represent value: ${inspect(value)}`);
149+
throw new TypeError(`String cannot represent value: ${inspect(rawValue)}`);
138150
}
139151

140152
function coerceString(value: mixed): string {
@@ -190,18 +202,16 @@ export const GraphQLBoolean = new GraphQLScalarType({
190202
},
191203
});
192204

193-
function serializeID(value: mixed): string {
194-
// Support serializing objects with custom valueOf() functions - a common way
195-
// to represent an object identifier (ex. MongoDB).
196-
const result =
197-
value && typeof value.valueOf === 'function' ? value.valueOf() : value;
198-
if (typeof result === 'string') {
199-
return result;
205+
function serializeID(rawValue: mixed): string {
206+
const value = serializeObject(rawValue);
207+
208+
if (typeof value === 'string') {
209+
return value;
200210
}
201-
if (isInteger(result)) {
202-
return String(result);
211+
if (isInteger(value)) {
212+
return String(value);
203213
}
204-
throw new TypeError(`ID cannot represent value: ${inspect(value)}`);
214+
throw new TypeError(`ID cannot represent value: ${inspect(rawValue)}`);
205215
}
206216

207217
function coerceID(value: mixed): string {

0 commit comments

Comments
 (0)