Skip to content

Commit ef0585a

Browse files
committed
Safer serialization for BigInt
1 parent ee66d2a commit ef0585a

File tree

2 files changed

+41
-13
lines changed

2 files changed

+41
-13
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'graphql-scalars': patch
3+
---
4+
5+
If JSON serializer is missing for `BigInt` use `number` serialization for safe integers and `string`
6+
for unsafe integers by warning the users.

src/scalars/BigInt.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,33 @@ import { GraphQLScalarType, GraphQLScalarTypeConfig, print } from 'graphql';
33
import { createGraphQLError } from '../error.js';
44
import { serializeObject } from './utilities.js';
55

6-
export const GraphQLBigIntConfig: GraphQLScalarTypeConfig<bigint | number, bigint | string | number> = /*#__PURE__*/ {
6+
let warned = false;
7+
8+
function isSafeInteger(val: bigint): boolean {
9+
return val <= Number.MAX_SAFE_INTEGER && val >= Number.MIN_SAFE_INTEGER;
10+
}
11+
12+
function serializeSafeBigInt(val: bigint): bigint | number | string {
13+
if ('toJSON' in BigInt.prototype) {
14+
return val;
15+
}
16+
if (isSafeInteger(val)) {
17+
return Number(val);
18+
}
19+
if (!warned) {
20+
warned = true;
21+
console.warn(
22+
'By default, BigInts are not serialized to JSON as numbers but instead as strings which may lead an unintegrity in your data. ' +
23+
'To fix this, you can use "json-bigint-patch" to enable correct serialization for BigInts.',
24+
);
25+
}
26+
return val.toString();
27+
}
28+
29+
export const GraphQLBigIntConfig: GraphQLScalarTypeConfig<
30+
bigint | number,
31+
bigint | string | number
32+
> = /*#__PURE__*/ {
733
name: 'BigInt',
834
description: 'The `BigInt` scalar type represents non-fractional signed whole numeric values.',
935
serialize(outputValue) {
@@ -33,22 +59,14 @@ export const GraphQLBigIntConfig: GraphQLScalarTypeConfig<bigint | number, bigin
3359
if (!Number.isInteger(coercedValue)) {
3460
throw createGraphQLError(`BigInt cannot represent non-integer value: ${coercedValue}`);
3561
}
36-
return coercedValue;
62+
num = BigInt(coercedValue);
3763
}
3864

3965
if (typeof num !== 'bigint') {
4066
throw createGraphQLError(`BigInt cannot represent non-integer value: ${coercedValue}`);
4167
}
4268

43-
if ('toJSON' in BigInt.prototype) {
44-
return num;
45-
}
46-
47-
if (Number.isSafeInteger(Number(num))) {
48-
return num;
49-
}
50-
51-
return num.toString();
69+
return serializeSafeBigInt(num);
5270
},
5371
parseValue(inputValue) {
5472
const bigint = BigInt(inputValue.toString());
@@ -59,7 +77,9 @@ export const GraphQLBigIntConfig: GraphQLScalarTypeConfig<bigint | number, bigin
5977
},
6078
parseLiteral(valueNode) {
6179
if (!('value' in valueNode)) {
62-
throw createGraphQLError(`BigInt cannot represent non-integer value: ${print(valueNode)}`, { nodes: valueNode });
80+
throw createGraphQLError(`BigInt cannot represent non-integer value: ${print(valueNode)}`, {
81+
nodes: valueNode,
82+
});
6383
}
6484
const strOrBooleanValue = valueNode.value;
6585
const bigint = BigInt(strOrBooleanValue);
@@ -77,4 +97,6 @@ export const GraphQLBigIntConfig: GraphQLScalarTypeConfig<bigint | number, bigin
7797
},
7898
};
7999

80-
export const GraphQLBigInt: GraphQLScalarType = /*#__PURE__*/ new GraphQLScalarType(GraphQLBigIntConfig);
100+
export const GraphQLBigInt: GraphQLScalarType = /*#__PURE__*/ new GraphQLScalarType(
101+
GraphQLBigIntConfig,
102+
);

0 commit comments

Comments
 (0)