Skip to content

Commit 8c3b172

Browse files
authored
Merge pull request #55 from graphql-java/ravikancherla-master
UUID scalar support
2 parents c2e844f + 3080b81 commit 8c3b172

File tree

5 files changed

+217
-0
lines changed

5 files changed

+217
-0
lines changed

readme.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ And example query might look like:
9393
}
9494

9595
```
96+
## ID Scalars
97+
98+
* `UUID`
99+
* A universally unique identifier scalar that accepts uuid values like `2423f0a0-3b81-4115-a189-18df8b35e8fc` and produces
100+
`java.util.UUID` instances at runtime.
96101

97102
## Object / JSON Scalars
98103

src/main/java/graphql/scalars/ExtendedScalars.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import graphql.scalars.datetime.TimeScalar;
99
import graphql.scalars.java.JavaPrimitives;
1010
import graphql.scalars.locale.LocaleScalar;
11+
import graphql.scalars.id.UUIDScalar;
1112
import graphql.scalars.numeric.NegativeFloatScalar;
1213
import graphql.scalars.numeric.NegativeIntScalar;
1314
import graphql.scalars.numeric.NonNegativeFloatScalar;
@@ -22,6 +23,8 @@
2223
import graphql.scalars.url.UrlScalar;
2324
import graphql.schema.GraphQLScalarType;
2425

26+
import java.util.UUID;
27+
2528
/**
2629
* This is the API entry point for all the extended scalars
2730
*/
@@ -135,6 +138,12 @@ public class ExtendedScalars {
135138
*/
136139
public static GraphQLScalarType Locale = LocaleScalar.INSTANCE;
137140

141+
/**
142+
* A UUID scalar that accepts a universally unique identifier and produces {@link
143+
* java.util.UUID} objects at runtime.
144+
*/
145+
public static GraphQLScalarType UUID = UUIDScalar.INSTANCE;
146+
138147
/**
139148
* An `Int` scalar that MUST be greater than zero
140149
*
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package graphql.scalars.id;
2+
3+
import graphql.Internal;
4+
import graphql.language.StringValue;
5+
import graphql.language.Value;
6+
import graphql.scalars.util.Kit;
7+
import graphql.schema.Coercing;
8+
import graphql.schema.CoercingParseLiteralException;
9+
import graphql.schema.CoercingParseValueException;
10+
import graphql.schema.CoercingSerializeException;
11+
import graphql.schema.GraphQLScalarType;
12+
13+
import java.util.UUID;
14+
15+
import static graphql.scalars.util.Kit.typeName;
16+
17+
/**
18+
* Access this via {@link graphql.scalars.ExtendedScalars#UUID}
19+
*/
20+
@Internal
21+
public class UUIDScalar {
22+
23+
public static GraphQLScalarType INSTANCE;
24+
25+
static {
26+
Coercing<UUID, String> coercing = new Coercing<UUID, String>() {
27+
private UUID convertImpl(Object input) {
28+
if (input instanceof String) {
29+
try {
30+
return (UUID.fromString((String) input));
31+
} catch (IllegalArgumentException ex) {
32+
return null;
33+
}
34+
} else if (input instanceof UUID) {
35+
return (UUID) input;
36+
}
37+
return null;
38+
}
39+
40+
@Override
41+
public String serialize(Object input) throws CoercingSerializeException {
42+
UUID result = convertImpl(input);
43+
if (result == null) {
44+
throw new CoercingSerializeException(
45+
"Expected type 'UUID' but was '" + Kit.typeName(input) + "'."
46+
);
47+
}
48+
return result.toString();
49+
}
50+
51+
@Override
52+
public UUID parseValue(Object input) throws CoercingParseValueException {
53+
UUID result = convertImpl(input);
54+
if (result == null) {
55+
throw new CoercingParseValueException(
56+
"Expected type 'UUID' but was '" + Kit.typeName(input) + "'."
57+
);
58+
}
59+
return result;
60+
}
61+
62+
@Override
63+
public UUID parseLiteral(Object input) throws CoercingParseLiteralException {
64+
if (!(input instanceof StringValue)) {
65+
throw new CoercingParseLiteralException(
66+
"Expected a 'java.util.UUID' AST type object but was '" + typeName(input) + "'."
67+
);
68+
}
69+
try {
70+
return UUID.fromString(((StringValue) input).getValue());
71+
} catch (IllegalArgumentException ex) {
72+
throw new CoercingParseLiteralException(
73+
"Expected something that we can convert to a UUID but was invalid"
74+
);
75+
}
76+
}
77+
78+
@Override
79+
public Value<?> valueToLiteral(Object input) {
80+
String s = serialize(input);
81+
return StringValue.newStringValue(s).build();
82+
}
83+
};
84+
85+
86+
INSTANCE = GraphQLScalarType.newScalar()
87+
.name("UUID")
88+
.description("A universally unique identifier compliant UUID Scalar")
89+
.coercing(coercing)
90+
.build();
91+
92+
}
93+
94+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package graphql.scalars.id
2+
3+
import graphql.language.StringValue
4+
import graphql.scalars.ExtendedScalars
5+
import graphql.schema.CoercingParseLiteralException
6+
import graphql.schema.CoercingParseValueException
7+
import graphql.schema.CoercingSerializeException
8+
import spock.lang.Specification
9+
import spock.lang.Unroll
10+
11+
import static graphql.scalars.util.TestKit.mkStringValue
12+
import static graphql.scalars.util.TestKit.mkUUIDValue
13+
14+
class UUIDScalarTest extends Specification {
15+
16+
def coercing = ExtendedScalars.UUID.getCoercing()
17+
18+
@Unroll
19+
def "UUID parseValue"() {
20+
21+
when:
22+
def result = coercing.parseValue(input)
23+
then:
24+
result == expectedValue
25+
where:
26+
input | expectedValue
27+
"43f20307-603c-4ad1-83c6-6010d224fabf" | mkUUIDValue("43f20307-603c-4ad1-83c6-6010d224fabf")
28+
"787dbc2b-3ddb-4098-ad1d-63d026bac111" | mkUUIDValue("787dbc2b-3ddb-4098-ad1d-63d026bac111")
29+
}
30+
31+
@Unroll
32+
def "UUID parseValue bad inputs"() {
33+
34+
when:
35+
coercing.parseValue(input)
36+
then:
37+
thrown(expectedValue)
38+
where:
39+
input | expectedValue
40+
"a-string-that-is-not-uuid" | CoercingParseValueException
41+
100 | CoercingParseValueException
42+
"1985-04-12" | CoercingParseValueException
43+
}
44+
45+
def "UUID AST literal"() {
46+
47+
when:
48+
def result = coercing.parseLiteral(input)
49+
then:
50+
result == expectedValue
51+
where:
52+
input | expectedValue
53+
new StringValue("6972117d-3963-4214-ab2c-fa973d7e996b") | mkUUIDValue("6972117d-3963-4214-ab2c-fa973d7e996b")
54+
}
55+
56+
def "UUID AST literal bad inputs"() {
57+
58+
when:
59+
coercing.parseLiteral(input)
60+
then:
61+
thrown(expectedValue)
62+
where:
63+
input | expectedValue
64+
new StringValue("a-string-that-us-not-uuid") | CoercingParseLiteralException
65+
}
66+
67+
def "UUID serialization"() {
68+
69+
when:
70+
def result = coercing.serialize(input)
71+
then:
72+
result == expectedValue
73+
where:
74+
input | expectedValue
75+
"42287d47-c5bd-45e4-b470-53e426d3d503" | "42287d47-c5bd-45e4-b470-53e426d3d503"
76+
"423df0f3-cf05-4eb5-b708-ae2f4b4a052d" | "423df0f3-cf05-4eb5-b708-ae2f4b4a052d"
77+
mkUUIDValue("6a90b1e6-20f3-43e5-a7ba-34db8010c071") | "6a90b1e6-20f3-43e5-a7ba-34db8010c071"
78+
}
79+
80+
def "UUID serialization bad inputs"() {
81+
82+
when:
83+
coercing.serialize(input)
84+
then:
85+
thrown(expectedValue)
86+
where:
87+
input | expectedValue
88+
"1985-04-12" | CoercingSerializeException
89+
100 | CoercingSerializeException
90+
}
91+
92+
@Unroll
93+
def "UUID valueToLiteral"() {
94+
95+
when:
96+
def result = coercing.valueToLiteral(input)
97+
then:
98+
result.isEqualTo(expectedValue)
99+
where:
100+
input | expectedValue
101+
"42287d47-c5bd-45e4-b470-53e426d3d503" | mkStringValue("42287d47-c5bd-45e4-b470-53e426d3d503")
102+
"423df0f3-cf05-4eb5-b708-ae2f4b4a052d" | mkStringValue("423df0f3-cf05-4eb5-b708-ae2f4b4a052d")
103+
mkUUIDValue("6a90b1e6-20f3-43e5-a7ba-34db8010c071") | mkStringValue("6a90b1e6-20f3-43e5-a7ba-34db8010c071")
104+
}
105+
}

src/test/groovy/graphql/scalars/util/TestKit.groovy

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,8 @@ class TestKit {
8585
return new FloatValue(new BigDecimal(d))
8686
}
8787

88+
static UUID mkUUIDValue(String s) {
89+
return UUID.fromString(s)
90+
}
91+
8892
}

0 commit comments

Comments
 (0)