Skip to content

Commit 122efe8

Browse files
authored
This provides @deprecated on input fields and arguments (#2186)
* Starting branch for input deprecation - not finished * This should now be complete * left over test code * better test with negative cases
1 parent e166c25 commit 122efe8

File tree

12 files changed

+201
-80
lines changed

12 files changed

+201
-80
lines changed

src/main/java/graphql/Directives.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88

99
import static graphql.Scalars.GraphQLBoolean;
1010
import static graphql.Scalars.GraphQLString;
11+
import static graphql.introspection.Introspection.DirectiveLocation.ARGUMENT_DEFINITION;
1112
import static graphql.introspection.Introspection.DirectiveLocation.ENUM_VALUE;
1213
import static graphql.introspection.Introspection.DirectiveLocation.FIELD;
1314
import static graphql.introspection.Introspection.DirectiveLocation.FIELD_DEFINITION;
1415
import static graphql.introspection.Introspection.DirectiveLocation.FRAGMENT_SPREAD;
1516
import static graphql.introspection.Introspection.DirectiveLocation.INLINE_FRAGMENT;
17+
import static graphql.introspection.Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION;
1618
import static graphql.introspection.Introspection.DirectiveLocation.SCALAR;
1719
import static graphql.language.DirectiveLocation.newDirectiveLocation;
1820
import static graphql.language.InputValueDefinition.newInputValueDefinition;
@@ -40,6 +42,8 @@ public class Directives {
4042
.name(DEPRECATED)
4143
.directiveLocation(newDirectiveLocation().name(FIELD_DEFINITION.name()).build())
4244
.directiveLocation(newDirectiveLocation().name(ENUM_VALUE.name()).build())
45+
.directiveLocation(newDirectiveLocation().name(ARGUMENT_DEFINITION.name()).build())
46+
.directiveLocation(newDirectiveLocation().name(INPUT_FIELD_DEFINITION.name()).build())
4347
.description(createDescription("Marks the field or enum value as deprecated"))
4448
.inputValueDefinition(
4549
newInputValueDefinition()
@@ -91,13 +95,13 @@ public class Directives {
9195
*/
9296
public static final GraphQLDirective DeprecatedDirective = GraphQLDirective.newDirective()
9397
.name(DEPRECATED)
94-
.description("Marks the field or enum value as deprecated")
98+
.description("Marks the field, argument, input field or enum value as deprecated")
9599
.argument(newArgument()
96100
.name("reason")
97101
.type(GraphQLString)
98102
.defaultValue(NO_LONGER_SUPPORTED)
99103
.description("The reason for the deprecation"))
100-
.validLocations(FIELD_DEFINITION, ENUM_VALUE)
104+
.validLocations(FIELD_DEFINITION, ENUM_VALUE, ARGUMENT_DEFINITION, INPUT_FIELD_DEFINITION)
101105
.definition(DEPRECATED_DIRECTIVE_DEFINITION)
102106
.build();
103107

src/main/java/graphql/introspection/Introspection.java

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.util.List;
3939
import java.util.Map;
4040
import java.util.Set;
41+
import java.util.stream.Collectors;
4142

4243
import static graphql.Assert.assertTrue;
4344
import static graphql.Scalars.GraphQLBoolean;
@@ -148,19 +149,35 @@ public enum TypeKind {
148149
.field(newFieldDefinition()
149150
.name("defaultValue")
150151
.type(GraphQLString))
152+
.field(newFieldDefinition()
153+
.name("isDeprecated")
154+
.type(GraphQLBoolean))
155+
.field(newFieldDefinition()
156+
.name("deprecationReason")
157+
.type(GraphQLString))
151158
.build();
152159

153160
static {
154161
register(__InputValue, "defaultValue", environment -> {
155-
if (environment.getSource() instanceof GraphQLArgument) {
156-
GraphQLArgument inputField = environment.getSource();
162+
Object type = environment.getSource();
163+
if (type instanceof GraphQLArgument) {
164+
GraphQLArgument inputField = (GraphQLArgument) type;
157165
return inputField.getDefaultValue() != null ? print(inputField.getDefaultValue(), inputField.getType()) : null;
158-
} else if (environment.getSource() instanceof GraphQLInputObjectField) {
159-
GraphQLInputObjectField inputField = environment.getSource();
166+
} else if (type instanceof GraphQLInputObjectField) {
167+
GraphQLInputObjectField inputField = (GraphQLInputObjectField) type;
160168
return inputField.getDefaultValue() != null ? print(inputField.getDefaultValue(), inputField.getType()) : null;
161169
}
162170
return null;
163171
});
172+
register(__InputValue, "isDeprecated", environment -> {
173+
Object type = environment.getSource();
174+
if (type instanceof GraphQLArgument) {
175+
return ((GraphQLArgument) type).isDeprecated();
176+
} else if (type instanceof GraphQLInputObjectField) {
177+
return ((GraphQLInputObjectField) type).isDeprecated();
178+
}
179+
return null;
180+
});
164181
register(__InputValue, "name", nameDataFetcher);
165182
register(__InputValue, "description", descriptionDataFetcher);
166183
}
@@ -180,7 +197,11 @@ private static String print(Object value, GraphQLInputType type) {
180197
.type(GraphQLString))
181198
.field(newFieldDefinition()
182199
.name("args")
183-
.type(nonNull(list(nonNull(__InputValue)))))
200+
.type(nonNull(list(nonNull(__InputValue))))
201+
.argument(newArgument()
202+
.name("includeDeprecated")
203+
.type(GraphQLBoolean)
204+
.defaultValue(false)))
184205
.field(newFieldDefinition()
185206
.name("type")
186207
.type(nonNull(typeRef("__Type"))))
@@ -234,23 +255,16 @@ private static String print(Object value, GraphQLInputType type) {
234255

235256
private static final IntrospectionDataFetcher<?> fieldsFetcher = environment -> {
236257
Object type = environment.getSource();
237-
Boolean includeDeprecated = environment.getArgument("includeDeprecated");
238258
if (type instanceof GraphQLFieldsContainer) {
239259
GraphQLFieldsContainer fieldsContainer = (GraphQLFieldsContainer) type;
260+
Boolean includeDeprecated = environment.getArgument("includeDeprecated");
240261
List<GraphQLFieldDefinition> fieldDefinitions = environment
241262
.getGraphQLSchema()
242263
.getFieldVisibility()
243264
.getFieldDefinitions(fieldsContainer);
244-
if (includeDeprecated) {
245-
return fieldDefinitions;
246-
}
247-
List<GraphQLFieldDefinition> filtered = new ArrayList<>(fieldDefinitions);
248-
for (GraphQLFieldDefinition fieldDefinition : fieldDefinitions) {
249-
if (fieldDefinition.isDeprecated()) {
250-
filtered.remove(fieldDefinition);
251-
}
252-
}
253-
return filtered;
265+
return fieldDefinitions.stream()
266+
.filter(field -> includeDeprecated || !field.isDeprecated())
267+
.collect(Collectors.toList());
254268
}
255269
return null;
256270
};
@@ -283,27 +297,23 @@ private static String print(Object value, GraphQLInputType type) {
283297
Boolean includeDeprecated = environment.getArgument("includeDeprecated");
284298
if (type instanceof GraphQLEnumType) {
285299
List<GraphQLEnumValueDefinition> values = ((GraphQLEnumType) type).getValues();
286-
if (includeDeprecated) {
287-
return values;
288-
}
289-
List<GraphQLEnumValueDefinition> filtered = new ArrayList<>(values);
290-
for (GraphQLEnumValueDefinition valueDefinition : values) {
291-
if (valueDefinition.isDeprecated()) {
292-
filtered.remove(valueDefinition);
293-
}
294-
}
295-
return filtered;
300+
return values.stream()
301+
.filter(enumValue -> includeDeprecated || !enumValue.isDeprecated())
302+
.collect(Collectors.toList());
296303
}
297304
return null;
298305
};
299306

300307
private static final IntrospectionDataFetcher<?> inputFieldsFetcher = environment -> {
301308
Object type = environment.getSource();
302309
if (type instanceof GraphQLInputObjectType) {
310+
Boolean includeDeprecated = environment.getArgument("includeDeprecated");
303311
GraphqlFieldVisibility fieldVisibility = environment
304312
.getGraphQLSchema()
305313
.getFieldVisibility();
306-
return fieldVisibility.getFieldDefinitions((GraphQLInputObjectType) type);
314+
return fieldVisibility.getFieldDefinitions((GraphQLInputObjectType) type)
315+
.stream().filter(inputField -> includeDeprecated || !inputField.isDeprecated())
316+
.collect(Collectors.toList());
307317
}
308318
return null;
309319
};
@@ -357,7 +367,11 @@ private static String print(Object value, GraphQLInputType type) {
357367
.defaultValue(false)))
358368
.field(newFieldDefinition()
359369
.name("inputFields")
360-
.type(list(nonNull(__InputValue))))
370+
.type(list(nonNull(__InputValue)))
371+
.argument(newArgument()
372+
.name("includeDeprecated")
373+
.type(GraphQLBoolean)
374+
.defaultValue(false)))
361375
.field(newFieldDefinition()
362376
.name("ofType")
363377
.type(typeRef("__Type")))

src/main/java/graphql/introspection/IntrospectionQuery.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public interface IntrospectionQuery {
4242
" isDeprecated\n" +
4343
" deprecationReason\n" +
4444
" }\n" +
45-
" inputFields {\n" +
45+
" inputFields(includeDeprecated: true) {\n" +
4646
" ...InputValue\n" +
4747
" }\n" +
4848
" interfaces {\n" +
@@ -64,6 +64,8 @@ public interface IntrospectionQuery {
6464
" description\n" +
6565
" type { ...TypeRef }\n" +
6666
" defaultValue\n" +
67+
" isDeprecated\n" +
68+
" deprecationReason\n" +
6769
" }\n" +
6870
"\n" +
6971
//

src/main/java/graphql/schema/GraphQLArgument.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class GraphQLArgument implements GraphQLNamedSchemaElement, GraphQLInputV
4141

4242
private final String name;
4343
private final String description;
44+
private final String deprecationReason;
4445
private final GraphQLInputType originalType;
4546
private final Object value;
4647
private final Object defaultValue;
@@ -91,10 +92,10 @@ public GraphQLArgument(String name, GraphQLInputType type) {
9192
* @deprecated use the {@link #newArgument()} builder pattern instead, as this constructor will be made private in a future version.
9293
*/
9394
public GraphQLArgument(String name, String description, GraphQLInputType type, Object defaultValue, InputValueDefinition definition) {
94-
this(name, description, type, defaultValue, null, definition, Collections.emptyList());
95+
this(name, description, type, defaultValue, null, definition, Collections.emptyList(), null);
9596
}
9697

97-
private GraphQLArgument(String name, String description, GraphQLInputType type, Object defaultValue, Object value, InputValueDefinition definition, List<GraphQLDirective> directives) {
98+
private GraphQLArgument(String name, String description, GraphQLInputType type, Object defaultValue, Object value, InputValueDefinition definition, List<GraphQLDirective> directives, String deprecationReason) {
9899
assertValidName(name);
99100
assertNotNull(type, () -> "type can't be null");
100101
this.name = name;
@@ -103,6 +104,7 @@ private GraphQLArgument(String name, String description, GraphQLInputType type,
103104
this.defaultValue = defaultValue;
104105
this.value = value;
105106
this.definition = definition;
107+
this.deprecationReason = deprecationReason;
106108
this.directives = new DirectivesUtil.DirectivesHolder(directives);
107109
}
108110

@@ -149,6 +151,14 @@ public String getDescription() {
149151
return description;
150152
}
151153

154+
public String getDeprecationReason() {
155+
return deprecationReason;
156+
}
157+
158+
public boolean isDeprecated() {
159+
return deprecationReason != null;
160+
}
161+
152162
public InputValueDefinition getDefinition() {
153163
return definition;
154164
}
@@ -262,6 +272,7 @@ public static class Builder extends GraphqlTypeBuilder {
262272
private GraphQLInputType type;
263273
private Object defaultValue = DEFAULT_VALUE_SENTINEL;
264274
private Object value;
275+
private String deprecationReason;
265276
private InputValueDefinition definition;
266277
private final List<GraphQLDirective> directives = new ArrayList<>();
267278

@@ -275,6 +286,7 @@ public Builder(GraphQLArgument existing) {
275286
this.defaultValue = existing.defaultValue;
276287
this.description = existing.getDescription();
277288
this.definition = existing.getDefinition();
289+
this.deprecationReason = existing.deprecationReason;
278290
DirectivesUtil.enforceAddAll(this.directives, existing.getDirectives());
279291
}
280292

@@ -301,6 +313,10 @@ public Builder definition(InputValueDefinition definition) {
301313
return this;
302314
}
303315

316+
public Builder deprecate(String deprecationReason) {
317+
this.deprecationReason = deprecationReason;
318+
return this;
319+
}
304320

305321
public Builder type(GraphQLInputType type) {
306322
this.type = type;
@@ -362,7 +378,8 @@ public GraphQLArgument build() {
362378
defaultValue,
363379
value,
364380
definition,
365-
sort(directives, GraphQLArgument.class, GraphQLDirective.class)
381+
sort(directives, GraphQLArgument.class, GraphQLDirective.class),
382+
deprecationReason
366383
);
367384
}
368385
}

src/main/java/graphql/schema/GraphQLInputObjectField.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class GraphQLInputObjectField implements GraphQLNamedSchemaElement, Graph
3232
private final String description;
3333
private final GraphQLInputType originalType;
3434
private final Object defaultValue;
35+
private final String deprecationReason;
3536
private final InputValueDefinition definition;
3637
private final DirectivesUtil.DirectivesHolder directives;
3738

@@ -79,6 +80,10 @@ public GraphQLInputObjectField(String name, String description, GraphQLInputType
7980
@Internal
8081
@Deprecated
8182
public GraphQLInputObjectField(String name, String description, GraphQLInputType type, Object defaultValue, List<GraphQLDirective> directives, InputValueDefinition definition) {
83+
this(name, description, type, defaultValue, directives, definition, null);
84+
}
85+
86+
private GraphQLInputObjectField(String name, String description, GraphQLInputType type, Object defaultValue, List<GraphQLDirective> directives, InputValueDefinition definition, String deprecationReason) {
8287
assertValidName(name);
8388
assertNotNull(type, () -> "type can't be null");
8489
assertNotNull(directives, () -> "directives cannot be null");
@@ -89,6 +94,7 @@ public GraphQLInputObjectField(String name, String description, GraphQLInputType
8994
this.description = description;
9095
this.directives = new DirectivesUtil.DirectivesHolder(directives);
9196
this.definition = definition;
97+
this.deprecationReason = deprecationReason;
9298
}
9399

94100
void replaceType(GraphQLInputType type) {
@@ -112,6 +118,14 @@ public String getDescription() {
112118
return description;
113119
}
114120

121+
public String getDeprecationReason() {
122+
return deprecationReason;
123+
}
124+
125+
public boolean isDeprecated() {
126+
return deprecationReason != null;
127+
}
128+
115129
public InputValueDefinition getDefinition() {
116130
return definition;
117131
}
@@ -236,6 +250,7 @@ public static class Builder extends GraphqlTypeBuilder {
236250
private GraphQLInputType type;
237251
private InputValueDefinition definition;
238252
private final List<GraphQLDirective> directives = new ArrayList<>();
253+
private String deprecationReason;
239254

240255
public Builder() {
241256
}
@@ -246,7 +261,8 @@ public Builder(GraphQLInputObjectField existing) {
246261
this.defaultValue = existing.getDefaultValue();
247262
this.type = existing.originalType;
248263
this.definition = existing.getDefinition();
249-
DirectivesUtil.enforceAddAll(this.directives,existing.getDirectives());
264+
this.deprecationReason = existing.deprecationReason;
265+
DirectivesUtil.enforceAddAll(this.directives, existing.getDirectives());
250266
}
251267

252268
@Override
@@ -272,6 +288,11 @@ public Builder definition(InputValueDefinition definition) {
272288
return this;
273289
}
274290

291+
public Builder deprecate(String deprecationReason) {
292+
this.deprecationReason = deprecationReason;
293+
return this;
294+
}
295+
275296
public Builder type(GraphQLInputObjectType.Builder type) {
276297
return type(type.build());
277298
}
@@ -330,7 +351,8 @@ public GraphQLInputObjectField build() {
330351
type,
331352
defaultValue,
332353
sort(directives, GraphQLInputObjectField.class, GraphQLDirective.class),
333-
definition);
354+
definition,
355+
deprecationReason);
334356
}
335357
}
336358
}

0 commit comments

Comments
 (0)