Skip to content

Commit 8c701b3

Browse files
committed
Adding scalars for BigInteger, BigDecimal, Byte, Short, Char, and accompanying tests.
1 parent d3a871b commit 8c701b3

File tree

4 files changed

+440
-25
lines changed

4 files changed

+440
-25
lines changed

src/main/java/graphql/Scalars.java

Lines changed: 163 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,22 @@
88
import graphql.schema.Coercing;
99
import graphql.schema.GraphQLScalarType;
1010

11+
import java.math.BigDecimal;
1112
import java.math.BigInteger;
1213

1314
public class Scalars {
1415

16+
private static final BigInteger LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE);
17+
private static final BigInteger LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE);
1518
private static final BigInteger INT_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
1619
private static final BigInteger INT_MIN = BigInteger.valueOf(Integer.MIN_VALUE);
20+
private static final BigInteger BYTE_MAX = BigInteger.valueOf(Byte.MAX_VALUE);
21+
private static final BigInteger BYTE_MIN = BigInteger.valueOf(Byte.MIN_VALUE);
22+
private static final BigInteger SHORT_MAX = BigInteger.valueOf(Short.MAX_VALUE);
23+
private static final BigInteger SHORT_MIN = BigInteger.valueOf(Short.MIN_VALUE);
1724

1825
public static GraphQLScalarType GraphQLInt = new GraphQLScalarType("Int", "Built-in Int", new Coercing() {
19-
26+
@Override
2027
public Object serialize(Object input) {
2128
if (input instanceof String) {
2229
return Integer.parseInt((String) input);
@@ -70,7 +77,9 @@ public Object parseLiteral(Object input) {
7077
} else if (input instanceof IntValue) {
7178
BigInteger value = ((IntValue) input).getValue();
7279
// Check if out of bounds.
73-
Long.parseLong(value.toString());
80+
if (value.compareTo(LONG_MIN) < 0 || value.compareTo(LONG_MAX) > 0) {
81+
throw new GraphQLException("Int literal is too big or too small for a long, would cause overflow");
82+
}
7483
return value.longValue();
7584
}
7685
return null;
@@ -178,4 +187,156 @@ public Object parseLiteral(Object input) {
178187
}
179188
});
180189

190+
public static GraphQLScalarType GraphQLBigInteger = new GraphQLScalarType("BigInteger", "Built-in java.math.BigInteger", new Coercing() {
191+
@Override
192+
public BigInteger serialize(Object input) {
193+
if (input instanceof BigInteger) {
194+
return (BigInteger) input;
195+
} else if (input instanceof String) {
196+
return new BigInteger((String) input);
197+
} else if (input instanceof Integer) {
198+
return BigInteger.valueOf((Integer) input);
199+
} else if (input instanceof Long) {
200+
return BigInteger.valueOf((Long) input);
201+
} else {
202+
return null;
203+
}
204+
}
205+
206+
@Override
207+
public BigInteger parseValue(Object input) {
208+
return serialize(input);
209+
}
210+
211+
@Override
212+
public BigInteger parseLiteral(Object input) {
213+
if (input instanceof StringValue) {
214+
return new BigInteger(((StringValue) input).getValue());
215+
} else if (input instanceof IntValue) {
216+
return ((IntValue) input).getValue();
217+
}
218+
return null;
219+
}
220+
});
221+
222+
public static GraphQLScalarType GraphQLBigDecimal = new GraphQLScalarType("BigDecimal", "Built-in java.math.BigDecimal", new Coercing() {
223+
@Override
224+
public BigDecimal serialize(Object input) {
225+
if (input instanceof BigDecimal) {
226+
return (BigDecimal) input;
227+
} else if (input instanceof String) {
228+
return new BigDecimal((String) input);
229+
} else if (input instanceof Float) {
230+
return BigDecimal.valueOf((Float) input);
231+
} else if (input instanceof Double) {
232+
return BigDecimal.valueOf((Double) input);
233+
} else if (input instanceof Integer) {
234+
return BigDecimal.valueOf((Integer) input);
235+
} else if (input instanceof Long) {
236+
return BigDecimal.valueOf((Long) input);
237+
} else {
238+
return null;
239+
}
240+
}
241+
242+
@Override
243+
public BigDecimal parseValue(Object input) {
244+
return serialize(input);
245+
}
246+
247+
@Override
248+
public BigDecimal parseLiteral(Object input) {
249+
if (input instanceof StringValue) {
250+
return new BigDecimal(((StringValue) input).getValue());
251+
} else if (input instanceof IntValue) {
252+
return new BigDecimal(((IntValue) input).getValue());
253+
} else if (input instanceof FloatValue) {
254+
return ((FloatValue) input).getValue();
255+
}
256+
return null;
257+
}
258+
});
259+
260+
public static GraphQLScalarType GraphQLByte = new GraphQLScalarType("Byte", "Built-in Byte as Int", new Coercing() {
261+
@Override
262+
public Byte serialize(Object input) {
263+
if (input instanceof String) {
264+
return Byte.parseByte((String) input);
265+
} else if (input instanceof Byte) {
266+
return (Byte) input;
267+
} else {
268+
return null;
269+
}
270+
}
271+
272+
@Override
273+
public Byte parseValue(Object input) {
274+
return serialize(input);
275+
}
276+
277+
@Override
278+
public Byte parseLiteral(Object input) {
279+
if (!(input instanceof IntValue)) return null;
280+
BigInteger value = ((IntValue) input).getValue();
281+
if (value.compareTo(BYTE_MIN) < 0 || value.compareTo(BYTE_MAX) > 0) {
282+
throw new GraphQLException("Int literal is too big or too small for a byte, would cause overflow");
283+
}
284+
return value.byteValue();
285+
}
286+
});
287+
288+
public static GraphQLScalarType GraphQLShort = new GraphQLScalarType("Short", "Built-in Short as Int", new Coercing() {
289+
@Override
290+
public Short serialize(Object input) {
291+
if (input instanceof String) {
292+
return Short.parseShort((String) input);
293+
} else if (input instanceof Short) {
294+
return (Short) input;
295+
} else {
296+
return null;
297+
}
298+
}
299+
300+
@Override
301+
public Short parseValue(Object input) {
302+
return serialize(input);
303+
}
304+
305+
@Override
306+
public Short parseLiteral(Object input) {
307+
if (!(input instanceof IntValue)) return null;
308+
BigInteger value = ((IntValue) input).getValue();
309+
if (value.compareTo(SHORT_MIN) < 0 || value.compareTo(SHORT_MAX) > 0) {
310+
throw new GraphQLException("Int literal is too big or too small for a short, would cause overflow");
311+
}
312+
return value.shortValue();
313+
}
314+
});
315+
316+
public static GraphQLScalarType GraphQLChar = new GraphQLScalarType("Char", "Built-in Char as Character", new Coercing() {
317+
@Override
318+
public Character serialize(Object input) {
319+
if (input instanceof String) {
320+
return ((String) input).length() != 1 ?
321+
null : ((String) input).charAt(0);
322+
} else if (input instanceof Character) {
323+
return (Character) input;
324+
} else {
325+
return null;
326+
}
327+
}
328+
329+
@Override
330+
public Character parseValue(Object input) {
331+
return serialize(input);
332+
}
333+
334+
@Override
335+
public Character parseLiteral(Object input) {
336+
if (!(input instanceof StringValue)) return null;
337+
String value = ((StringValue) input).getValue();
338+
if (value == null || value.length() != 1) return null;
339+
return value.charAt(0);
340+
}
341+
});
181342
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package graphql;
2+
3+
4+
import graphql.schema.*;
5+
6+
import static graphql.schema.GraphQLArgument.newArgument;
7+
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
8+
import static graphql.schema.GraphQLObjectType.newObject;
9+
10+
import java.math.BigDecimal;
11+
import java.math.BigInteger;
12+
13+
public class ScalarsQuerySchema {
14+
15+
public static GraphQLObjectType queryType = newObject()
16+
.name("QueryType")
17+
.field(newFieldDefinition()
18+
.name("bigInteger")
19+
.type(Scalars.GraphQLBigInteger)
20+
.staticValue(BigInteger.valueOf(9999))
21+
.build())
22+
.field(newFieldDefinition()
23+
.name("bigDecimal")
24+
.type(Scalars.GraphQLBigDecimal)
25+
.staticValue(BigDecimal.valueOf(1234.0))
26+
.build())
27+
.field(newFieldDefinition()
28+
.name("bigIntegerInput")
29+
.type(Scalars.GraphQLBigInteger)
30+
.argument(newArgument()
31+
.name("input")
32+
.type(new GraphQLNonNull(Scalars.GraphQLBigInteger))
33+
.build())
34+
.dataFetcher(new DataFetcher() {
35+
@Override
36+
public Object get(DataFetchingEnvironment environment) {
37+
return environment.getArgument("input");
38+
}
39+
})
40+
.build())
41+
.field(newFieldDefinition()
42+
.name("bigDecimalInput")
43+
.type(Scalars.GraphQLBigDecimal)
44+
.argument(newArgument()
45+
.name("input")
46+
.type(new GraphQLNonNull(Scalars.GraphQLBigDecimal))
47+
.build())
48+
.dataFetcher(new DataFetcher() {
49+
@Override
50+
public Object get(DataFetchingEnvironment environment) {
51+
return environment.getArgument("input");
52+
}
53+
})
54+
.build())
55+
.build();
56+
57+
58+
public static GraphQLSchema scalarsQuerySchema = GraphQLSchema.newSchema()
59+
.query(queryType)
60+
.build();
61+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package graphql
2+
3+
import spock.lang.Specification
4+
5+
class ScalarsQueryTest extends Specification {
6+
7+
def 'Large BigIntegers'() {
8+
given:
9+
def query = """
10+
query BigInteger {
11+
bigInteger
12+
i1: bigIntegerInput(input: 1234567890123456789012345678901234567890)
13+
i2: bigIntegerInput(input: "1234567890123456789012345678901234567890")
14+
}
15+
"""
16+
def expected = [
17+
bigInteger: 9999,
18+
i1: 1234567890123456789012345678901234567890,
19+
i2: 1234567890123456789012345678901234567890
20+
]
21+
22+
when:
23+
def result = new GraphQL(ScalarsQuerySchema.scalarsQuerySchema).execute(query).data
24+
25+
then:
26+
result == expected
27+
}
28+
29+
def 'Large BigDecimals'() {
30+
given:
31+
def query = """
32+
query BigDecimal {
33+
bigDecimal
34+
d1: bigDecimalInput(input: "1234567890123456789012345678901234567890.0")
35+
d2: bigDecimalInput(input: 1234567890123456789012345678901234567890.0)
36+
}
37+
"""
38+
def expected = [
39+
bigDecimal: 1234.0,
40+
d1: 1234567890123456789012345678901234567890.0,
41+
d2: 1234567890123456789012345678901234567890.0
42+
]
43+
44+
when:
45+
def result = new GraphQL(ScalarsQuerySchema.scalarsQuerySchema).execute(query).data
46+
47+
then:
48+
result == expected
49+
}
50+
}

0 commit comments

Comments
 (0)