forked from graphql-java/graphql-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGraphQLEnumType.java
More file actions
227 lines (189 loc) · 7.86 KB
/
GraphQLEnumType.java
File metadata and controls
227 lines (189 loc) · 7.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package graphql.schema;
import graphql.AssertException;
import graphql.Internal;
import graphql.PublicApi;
import graphql.language.EnumTypeDefinition;
import graphql.language.EnumValue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static graphql.Assert.assertNotNull;
import static graphql.Assert.assertValidName;
import static java.util.Collections.emptyList;
/**
* A graphql enumeration type has a limited set of values.
*
* This allows you to validate that any arguments of this type are one of the allowed values
* and communicate through the type system that a field will always be one of a finite set of values.
*
* See http://graphql.org/learn/schema/#enumeration-types for more details
*/
@PublicApi
public class GraphQLEnumType implements GraphQLType, GraphQLInputType, GraphQLOutputType, GraphQLUnmodifiedType, GraphQLNullableType, GraphQLDirectiveContainer {
private final String name;
private final String description;
private final Map<String, GraphQLEnumValueDefinition> valueDefinitionMap = new LinkedHashMap<>();
private final EnumTypeDefinition definition;
private final List<GraphQLDirective> directives;
private final Coercing coercing = new Coercing() {
@Override
public Object serialize(Object input) {
return getNameByValue(input);
}
@Override
public Object parseValue(Object input) {
return getValueByName(input);
}
private String typeName(Object input) {
if (input == null) {
return "null";
}
return input.getClass().getSimpleName();
}
@Override
public Object parseLiteral(Object input) {
if (!(input instanceof EnumValue)) {
throw new CoercingParseLiteralException(
"Expected AST type 'EnumValue' but was '" + typeName(input) + "'."
);
}
EnumValue enumValue = (EnumValue) input;
GraphQLEnumValueDefinition enumValueDefinition = valueDefinitionMap.get(enumValue.getName());
if (enumValueDefinition == null) {
throw new CoercingParseLiteralException(
"Expected enum literal value not in allowable values - '" + String.valueOf(input) + "'."
);
}
return enumValueDefinition.getValue();
}
};
@Internal
public GraphQLEnumType(String name, String description, List<GraphQLEnumValueDefinition> values) {
this(name, description, values, emptyList(), null);
}
@Internal
public GraphQLEnumType(String name, String description, List<GraphQLEnumValueDefinition> values, List<GraphQLDirective> directives, EnumTypeDefinition definition) {
assertValidName(name);
assertNotNull(directives, "directives cannot be null");
this.name = name;
this.description = description;
this.definition = definition;
this.directives = directives;
buildMap(values);
}
public List<GraphQLEnumValueDefinition> getValues() {
return new ArrayList<>(valueDefinitionMap.values());
}
public GraphQLEnumValueDefinition getValue(String name) {
return valueDefinitionMap.get(name);
}
private void buildMap(List<GraphQLEnumValueDefinition> values) {
for (GraphQLEnumValueDefinition valueDefinition : values) {
String name = valueDefinition.getName();
if (valueDefinitionMap.containsKey(name))
throw new AssertException("value " + name + " redefined");
valueDefinitionMap.put(name, valueDefinition);
}
}
private Object getValueByName(Object value) {
GraphQLEnumValueDefinition enumValueDefinition = valueDefinitionMap.get(value.toString());
if (enumValueDefinition != null) return enumValueDefinition.getValue();
throw new CoercingParseValueException("Invalid input for Enum '" + name + "'. No value found for name '" + value.toString() + "'");
}
private Object getNameByValue(Object value) {
for (GraphQLEnumValueDefinition valueDefinition : valueDefinitionMap.values()) {
Object definitionValue = valueDefinition.getValue();
if (value.equals(definitionValue)) {
return valueDefinition.getName();
}
// we can treat enum backing values as strings in effect
if (definitionValue instanceof Enum && value instanceof String) {
if (value.equals(((Enum) definitionValue).name())) {
return valueDefinition.getName();
}
}
}
// ok we didn't match on pure object.equals(). Lets try the Java enum strategy
if (value instanceof Enum) {
String enumNameValue = ((Enum<?>) value).name();
for (GraphQLEnumValueDefinition valueDefinition : valueDefinitionMap.values()) {
Object definitionValue = String.valueOf(valueDefinition.getValue());
if (enumNameValue.equals(definitionValue)) {
return valueDefinition.getName();
}
}
}
throw new CoercingSerializeException("Invalid input for Enum '" + name + "'. Unknown value '" + value + "'");
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public Coercing getCoercing() {
return coercing;
}
public EnumTypeDefinition getDefinition() {
return definition;
}
@Override
public List<GraphQLDirective> getDirectives() {
return new ArrayList<>(directives);
}
public static Builder newEnum() {
return new Builder();
}
public static class Builder {
private String name;
private String description;
private EnumTypeDefinition definition;
private final List<GraphQLEnumValueDefinition> values = new ArrayList<>();
private final List<GraphQLDirective> directives = new ArrayList<>();
public Builder name(String name) {
this.name = name;
return this;
}
public Builder description(String description) {
this.description = description;
return this;
}
public Builder definition(EnumTypeDefinition definition) {
this.definition = definition;
return this;
}
public Builder value(String name, Object value, String description, String deprecationReason) {
values.add(new GraphQLEnumValueDefinition(name, description, value, deprecationReason));
return this;
}
public Builder value(String name, Object value, String description) {
values.add(new GraphQLEnumValueDefinition(name, description, value));
return this;
}
public Builder value(String name, Object value) {
assertNotNull(value, "value can't be null");
values.add(new GraphQLEnumValueDefinition(name, null, value));
return this;
}
public Builder value(String name) {
values.add(new GraphQLEnumValueDefinition(name, null, name));
return this;
}
public Builder value(GraphQLEnumValueDefinition enumValueDefinition) {
values.add(enumValueDefinition);
return this;
}
public boolean hasValue(String name) {
return values.stream().anyMatch(evd -> evd.getName().equals(name));
}
public Builder withDirectives(GraphQLDirective... directives) {
Collections.addAll(this.directives, directives);
return this;
}
public GraphQLEnumType build() {
return new GraphQLEnumType(name, description, values, directives, definition);
}
}
}