Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/main/antlr/GraphqlSDL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ directiveDefinition

typeSystemExtension :
schemaExtension |
typeExtension
typeExtension |
directiveExtension
;

schemaDefinition : description? SCHEMA directives? '{' operationTypeDefinition+ '}';
Expand Down Expand Up @@ -121,7 +122,9 @@ inputObjectValueDefinitions : '{' inputValueDefinition* '}';
extensionInputObjectValueDefinitions : '{' inputValueDefinition+ '}';


directiveDefinition : description? DIRECTIVE '@' name argumentsDefinition? REPEATABLE? ON_KEYWORD directiveLocations;
directiveDefinition : description? DIRECTIVE '@' name argumentsDefinition? directives? REPEATABLE? ON_KEYWORD directiveLocations;

directiveExtension : EXTEND DIRECTIVE '@' name directives;

directiveLocation : name;

Expand Down
8 changes: 5 additions & 3 deletions src/main/java/graphql/Directives.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static graphql.Scalars.GraphQLBoolean;
import static graphql.Scalars.GraphQLString;
import static graphql.introspection.Introspection.DirectiveLocation.ARGUMENT_DEFINITION;
import static graphql.introspection.Introspection.DirectiveLocation.DIRECTIVE_DEFINITION;
import static graphql.introspection.Introspection.DirectiveLocation.ENUM_VALUE;
import static graphql.introspection.Introspection.DirectiveLocation.FIELD;
import static graphql.introspection.Introspection.DirectiveLocation.FIELD_DEFINITION;
Expand Down Expand Up @@ -73,7 +74,8 @@ public class Directives {
.directiveLocation(newDirectiveLocation().name(ENUM_VALUE.name()).build())
.directiveLocation(newDirectiveLocation().name(ARGUMENT_DEFINITION.name()).build())
.directiveLocation(newDirectiveLocation().name(INPUT_FIELD_DEFINITION.name()).build())
.description(createDescription("Marks the field, argument, input field or enum value as deprecated"))
.directiveLocation(newDirectiveLocation().name(DIRECTIVE_DEFINITION.name()).build())
.description(createDescription("Marks an element of a GraphQL schema as no longer supported."))
.inputValueDefinition(
newInputValueDefinition()
.name("reason")
Expand Down Expand Up @@ -216,13 +218,13 @@ public class Directives {
*/
public static final GraphQLDirective DeprecatedDirective = GraphQLDirective.newDirective()
.name(DEPRECATED)
.description("Marks the field, argument, input field or enum value as deprecated")
.description("Marks an element of a GraphQL schema as no longer supported.")
.argument(newArgument()
.name("reason")
.type(nonNull(GraphQLString))
.defaultValueProgrammatic(NO_LONGER_SUPPORTED)
.description("The reason for the deprecation"))
.validLocations(FIELD_DEFINITION, ENUM_VALUE, ARGUMENT_DEFINITION, INPUT_FIELD_DEFINITION)
.validLocations(FIELD_DEFINITION, ENUM_VALUE, ARGUMENT_DEFINITION, INPUT_FIELD_DEFINITION, DIRECTIVE_DEFINITION)
.definition(DEPRECATED_DIRECTIVE_DEFINITION)
.build();

Expand Down
25 changes: 22 additions & 3 deletions src/main/java/graphql/introspection/Introspection.java
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,8 @@ public enum DirectiveLocation {
ENUM,
ENUM_VALUE,
INPUT_OBJECT,
INPUT_FIELD_DEFINITION
INPUT_FIELD_DEFINITION,
DIRECTIVE_DEFINITION
}

public static final GraphQLEnumType __DirectiveLocation = GraphQLEnumType.newEnum()
Expand Down Expand Up @@ -606,6 +607,7 @@ public enum DirectiveLocation {
.value("ENUM_VALUE", DirectiveLocation.ENUM_VALUE, "Indicates the directive is valid on an enum value SDL definition.")
.value("INPUT_OBJECT", DirectiveLocation.INPUT_OBJECT, "Indicates the directive is valid on an input object SDL definition.")
.value("INPUT_FIELD_DEFINITION", DirectiveLocation.INPUT_FIELD_DEFINITION, "Indicates the directive is valid on an input object field SDL definition.")
.value("DIRECTIVE_DEFINITION", DirectiveLocation.DIRECTIVE_DEFINITION, "Indicates the directive is valid on a directive SDL definition.")
.build();


Expand All @@ -631,6 +633,12 @@ public enum DirectiveLocation {
.name("includeDeprecated")
.type(nonNull(GraphQLBoolean))
.defaultValueProgrammatic(false)))
.field(newFieldDefinition()
.name("isDeprecated")
.type(nonNull(GraphQLBoolean)))
.field(newFieldDefinition()
.name("deprecationReason")
.type(GraphQLString))
.build();

static {
Expand All @@ -649,6 +657,8 @@ public enum DirectiveLocation {
register(__Directive, "isRepeatable", GraphQLDirective.class, GraphQLDirective::isRepeatable);
register(__Directive, "locations", locationsDataFetcher);
register(__Directive, "args", argsDataFetcher);
register(__Directive, "isDeprecated", GraphQLDirective.class, GraphQLDirective::isDeprecated);
register(__Directive, "deprecationReason", GraphQLDirective.class, GraphQLDirective::getDeprecationReason);
}

public static final GraphQLObjectType __Schema = newObject()
Expand All @@ -674,7 +684,11 @@ public enum DirectiveLocation {
.field(newFieldDefinition()
.name("directives")
.description("A list of all directives supported by this server.")
.type(nonNull(list(nonNull(__Directive)))))
.type(nonNull(list(nonNull(__Directive))))
.argument(newArgument()
.name("includeDeprecated")
.type(nonNull(GraphQLBoolean))
.defaultValueProgrammatic(false)))
.field(newFieldDefinition()
.name("subscriptionType")
.description("If this server support subscription, the type that subscription operations will be rooted at.")
Expand All @@ -688,7 +702,12 @@ public enum DirectiveLocation {
register(__Schema, "types", GraphQLSchema.class, GraphQLSchema::getAllTypesAsList);
register(__Schema, "queryType", GraphQLSchema.class, GraphQLSchema::getQueryType);
register(__Schema, "mutationType", GraphQLSchema.class, GraphQLSchema::getMutationType);
register(__Schema, "directives", GraphQLSchema.class, GraphQLSchema::getDirectives);
IntrospectionDataFetcher<?> directivesDataFetcher = environment -> {
Boolean includeDeprecated = environment.getArgument("includeDeprecated");
return ImmutableKit.filter(environment.getGraphQLSchema().getDirectives(),
directive -> includeDeprecated || !directive.isDeprecated());
};
register(__Schema, "directives", directivesDataFetcher);
register(__Schema, "subscriptionType", GraphQLSchema.class, GraphQLSchema::getSubscriptionType);
}

Expand Down
45 changes: 41 additions & 4 deletions src/main/java/graphql/introspection/IntrospectionQueryBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public static class Options {

private final boolean inputValueDeprecation;

private final boolean directiveDeprecation;

private final int typeRefFragmentDepth;

private Options(boolean descriptions,
Expand All @@ -48,13 +50,15 @@ private Options(boolean descriptions,
boolean directiveIsRepeatable,
boolean schemaDescription,
boolean inputValueDeprecation,
boolean directiveDeprecation,
int typeRefFragmentDepth) {
this.descriptions = descriptions;
this.specifiedByUrl = specifiedByUrl;
this.isOneOf = isOneOf;
this.directiveIsRepeatable = directiveIsRepeatable;
this.schemaDescription = schemaDescription;
this.inputValueDeprecation = inputValueDeprecation;
this.directiveDeprecation = directiveDeprecation;
this.typeRefFragmentDepth = typeRefFragmentDepth;
}

Expand Down Expand Up @@ -82,6 +86,10 @@ public boolean isInputValueDeprecation() {
return inputValueDeprecation;
}

public boolean isDirectiveDeprecation() {
return directiveDeprecation;
}

public int getTypeRefFragmentDepth() {
return typeRefFragmentDepth;
}
Expand All @@ -94,6 +102,7 @@ public static Options defaultOptions() {
true,
false,
true,
true,
7
);
}
Expand All @@ -112,6 +121,7 @@ public Options descriptions(boolean flag) {
this.directiveIsRepeatable,
this.schemaDescription,
this.inputValueDeprecation,
this.directiveDeprecation,
this.typeRefFragmentDepth);
}

Expand All @@ -129,6 +139,7 @@ public Options specifiedByUrl(boolean flag) {
this.directiveIsRepeatable,
this.schemaDescription,
this.inputValueDeprecation,
this.directiveDeprecation,
this.typeRefFragmentDepth);
}

Expand All @@ -149,6 +160,7 @@ public Options isOneOf(boolean flag) {
this.directiveIsRepeatable,
this.schemaDescription,
this.inputValueDeprecation,
this.directiveDeprecation,
this.typeRefFragmentDepth);
}

Expand All @@ -166,6 +178,7 @@ public Options directiveIsRepeatable(boolean flag) {
flag,
this.schemaDescription,
this.inputValueDeprecation,
this.directiveDeprecation,
this.typeRefFragmentDepth);
}

Expand All @@ -183,6 +196,7 @@ public Options schemaDescription(boolean flag) {
this.directiveIsRepeatable,
flag,
this.inputValueDeprecation,
this.directiveDeprecation,
this.typeRefFragmentDepth);
}

Expand All @@ -200,6 +214,25 @@ public Options inputValueDeprecation(boolean flag) {
this.directiveIsRepeatable,
this.schemaDescription,
flag,
this.directiveDeprecation,
this.typeRefFragmentDepth);
}

/**
* This will allow you to include deprecated directives in the introspection query.
*
* @param flag whether to include them
*
* @return options
*/
public Options directiveDeprecation(boolean flag) {
return new Options(this.descriptions,
this.specifiedByUrl,
this.isOneOf,
this.directiveIsRepeatable,
this.schemaDescription,
this.inputValueDeprecation,
flag,
this.typeRefFragmentDepth);
}

Expand All @@ -217,6 +250,7 @@ public Options typeRefFragmentDepth(int typeRefFragmentDepth) {
this.directiveIsRepeatable,
this.schemaDescription,
this.inputValueDeprecation,
this.directiveDeprecation,
typeRefFragmentDepth);
}
}
Expand Down Expand Up @@ -269,11 +303,14 @@ public static Document buildDocument(Options options) {
.build()
)
.build(),
options.directiveIsRepeatable ? newField("isRepeatable").build() : null
options.directiveIsRepeatable ? newField("isRepeatable").build() : null,
options.directiveDeprecation ? newField("isDeprecated").build() : null,
options.directiveDeprecation ? newField("deprecationReason").build() : null
)).build())
.arguments(filter(
options.directiveDeprecation ? newArgument("includeDeprecated", BooleanValue.of(true)).build() : null
))
.build()
)
.build()
)
).build();

Expand Down Expand Up @@ -420,4 +457,4 @@ public static String build(Options options) {
public static String build() {
return build(Options.defaultOptions());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ private DirectiveDefinition createDirective(Map<String, Object> input) {
List<InputValueDefinition> inputValueDefinitions = createInputValueDefinitions(args);
directiveDefBuilder.inputValueDefinitions(inputValueDefinitions);
Optional.ofNullable((Boolean) input.get("isRepeatable")).ifPresent(value -> directiveDefBuilder.repeatable(value));
createDeprecatedDirective(input, directiveDefBuilder);

return directiveDefBuilder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import static graphql.Assert.assertNotNull;
import static graphql.Assert.assertShouldNeverHappen;
import static graphql.Scalars.GraphQLString;
import static graphql.introspection.Introspection.__Directive;
import static graphql.introspection.Introspection.__EnumValue;
import static graphql.introspection.Introspection.__Field;
import static graphql.introspection.Introspection.__InputValue;
Expand Down Expand Up @@ -82,7 +83,7 @@ public class IntrospectionWithDirectivesSupport {
private final String typePrefix;

private final Set<String> INTROSPECTION_ELEMENTS = ImmutableSet.of(
__Schema.getName(), __Type.getName(), __Field.getName(), __EnumValue.getName(), __InputValue.getName()
__Schema.getName(), __Type.getName(), __Field.getName(), __EnumValue.getName(), __InputValue.getName(), __Directive.getName()
);


Expand Down Expand Up @@ -172,8 +173,10 @@ private GraphQLObjectType mkAppliedDirectiveType(String name, GraphQLType direct

private GraphQLSchema addDirectiveDefinitionFilter(GraphQLSchema schema) {
DataFetcher<?> df = env -> {
List<GraphQLDirective> definedDirectives = env.getGraphQLSchema().getDirectives();
return filterDirectives(schema, true, null, definedDirectives);
GraphQLSchema graphQLSchema = env.getGraphQLSchema();
Boolean includeDeprecated = env.getArgument("includeDeprecated");
List<GraphQLDirective> definedDirectives = graphQLSchema.getDirectives();
return filterDirectives(graphQLSchema, true, null, definedDirectives, Boolean.TRUE.equals(includeDeprecated));
};
GraphQLCodeRegistry codeRegistry = schema.getCodeRegistry().transform(bld ->
bld.dataFetcher(coordinates(__Schema, "directives"), df));
Expand Down Expand Up @@ -224,9 +227,12 @@ private GraphQLObjectType addAppliedDirectives(GraphQLObjectType originalType, G
return objectType;
}

private List<GraphQLDirective> filterDirectives(GraphQLSchema schema, boolean isDefinedDirective, GraphQLDirectiveContainer container, List<GraphQLDirective> directives) {
private List<GraphQLDirective> filterDirectives(GraphQLSchema schema, boolean isDefinedDirective, GraphQLDirectiveContainer container, List<GraphQLDirective> directives, boolean includeDeprecated) {
return ImmutableKit.filter(directives,
directive -> {
if (!includeDeprecated && directive.isDeprecated()) {
return false;
}
DirectivePredicateEnvironment env = buildDirectivePredicateEnv(schema, isDefinedDirective, container, directive.getName());
return directivePredicate.isDirectiveIncluded(env);
});
Expand Down
16 changes: 15 additions & 1 deletion src/main/java/graphql/language/AstPrinter.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ static AstPrinter compact() {
printers.put(BooleanValue.class, value());
printers.put(NullValue.class, value());
printers.put(Directive.class, directive());
printers.put(DirectiveExtensionDefinition.class, directiveExtensionDefinition());
printers.put(DirectiveDefinition.class, directiveDefinition());
printers.put(DirectiveLocation.class, directiveLocation());
printers.put(Document.class, document());
Expand Down Expand Up @@ -137,7 +138,11 @@ private NodePrinter<DirectiveDefinition> directiveDefinition() {
join(out, node.getInputValueDefinitions(), argSep);
out.append(')');
}
out.append(" ");
if (!isEmpty(node.getDirectives())) {
out.append(' ');
directives(out, node.getDirectives());
}
out.append(' ');
if (node.isRepeatable()) {
out.append("repeatable ");
}
Expand All @@ -146,6 +151,15 @@ private NodePrinter<DirectiveDefinition> directiveDefinition() {
};
}

private NodePrinter<DirectiveExtensionDefinition> directiveExtensionDefinition() {
return (out, node) -> {
out.append("extend directive @");
out.append(node.getName());
out.append(' ');
directives(out, node.getDirectives());
};
}

private NodePrinter<DirectiveLocation> directiveLocation() {
return (out, node) -> out.append(node.getName());
}
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/graphql/language/AstSorter.java
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,14 @@ public TraversalControl visitInputValueDefinition(InputValueDefinition node, Tra

@Override
public TraversalControl visitDirectiveDefinition(DirectiveDefinition node, TraverserContext<Node> context) {
if (node instanceof DirectiveExtensionDefinition) {
DirectiveExtensionDefinition extension = (DirectiveExtensionDefinition) node;
DirectiveExtensionDefinition changedExtension = extension.transformExtension(builder ->
builder.directives(sort(node.getDirectives(), comparing(Directive::getName))));
return changeNode(context, changedExtension);
}
DirectiveDefinition changedNode = node.transform(builder -> {
builder.directives(sort(node.getDirectives(), comparing(Directive::getName)));
builder.inputValueDefinitions(sort(node.getInputValueDefinitions(), comparing(InputValueDefinition::getName)));
builder.directiveLocations(sort(node.getDirectiveLocations(), comparing(DirectiveLocation::getName)));
});
Expand Down
Loading
Loading