Skip to content
Merged
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
74 changes: 67 additions & 7 deletions src/main/java/graphql/Directives.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,25 @@
@PublicApi
public class Directives {

private static final String SPECIFIED_BY = "specifiedBy";
private static final String DEPRECATED = "deprecated";
private static final String INCLUDE = "include";
private static final String SKIP = "skip";
private static final String SPECIFIED_BY = "specifiedBy";
private static final String ONE_OF = "oneOf";
private static final String DEFER = "defer";

public static final String NO_LONGER_SUPPORTED = "No longer supported";
public static final DirectiveDefinition DEPRECATED_DIRECTIVE_DEFINITION;
public static final DirectiveDefinition INCLUDE_DIRECTIVE_DEFINITION;
public static final DirectiveDefinition SKIP_DIRECTIVE_DEFINITION;
public static final DirectiveDefinition SPECIFIED_BY_DIRECTIVE_DEFINITION;
@ExperimentalApi
public static final DirectiveDefinition ONE_OF_DIRECTIVE_DEFINITION;
@ExperimentalApi
public static final DirectiveDefinition DEFER_DIRECTIVE_DEFINITION;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to declare the defer one as experimental?

@andimarek it is declared here, did you also want the annotation to appear elsewhere?

Elsewhere all the defer codepaths have been annotated with @ExperimentalApi

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perfect, didn't see that


public static final String BOOLEAN = "Boolean";
public static final String STRING = "String";
public static final String NO_LONGER_SUPPORTED = "No longer supported";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In more recent code, as a general rule we prefer to not have random strings hanging about. Some parts of this class haven't been changed in a long while and still have strings. If you prefer I can give the public static final String treatment to all the strings in this class


static {
DEPRECATED_DIRECTIVE_DEFINITION = DirectiveDefinition.newDirectiveDefinition()
Expand All @@ -54,11 +63,39 @@ public class Directives {
newInputValueDefinition()
.name("reason")
.description(createDescription("The reason for the deprecation"))
.type(newTypeName().name("String").build())
.type(newTypeName().name(STRING).build())
.defaultValue(StringValue.newStringValue().value(NO_LONGER_SUPPORTED).build())
.build())
.build();

INCLUDE_DIRECTIVE_DEFINITION = DirectiveDefinition.newDirectiveDefinition()
.name(INCLUDE)
.directiveLocation(newDirectiveLocation().name(FRAGMENT_SPREAD.name()).build())
.directiveLocation(newDirectiveLocation().name(INLINE_FRAGMENT.name()).build())
.directiveLocation(newDirectiveLocation().name(FIELD.name()).build())
.description(createDescription("Directs the executor to include this field or fragment only when the `if` argument is true"))
.inputValueDefinition(
newInputValueDefinition()
.name("if")
.description(createDescription("Included when true."))
.type(newNonNullType(newTypeName().name(BOOLEAN).build()).build())
.build())
Copy link
Member Author

@dondonz dondonz Jul 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment for myself: in AST land, DirectiveDefinitions ONLY have "inputValueDefinition", this is the AST type used to model "arguments". Confusingly there is another graphql.language/AST class called "Argument". It is meant to be inputValueDefinition here.

.build();

SKIP_DIRECTIVE_DEFINITION = DirectiveDefinition.newDirectiveDefinition()
.name(SKIP)
.directiveLocation(newDirectiveLocation().name(FRAGMENT_SPREAD.name()).build())
.directiveLocation(newDirectiveLocation().name(INLINE_FRAGMENT.name()).build())
.directiveLocation(newDirectiveLocation().name(FIELD.name()).build())
.description(createDescription("Directs the executor to skip this field or fragment when the `if` argument is true."))
.inputValueDefinition(
newInputValueDefinition()
.name("if")
.description(createDescription("Skipped when true."))
.type(newNonNullType(newTypeName().name(BOOLEAN).build()).build())
.build())
.build();

SPECIFIED_BY_DIRECTIVE_DEFINITION = DirectiveDefinition.newDirectiveDefinition()
.name(SPECIFIED_BY)
.directiveLocation(newDirectiveLocation().name(SCALAR.name()).build())
Expand All @@ -67,7 +104,7 @@ public class Directives {
newInputValueDefinition()
.name("url")
.description(createDescription("The URL that specifies the behaviour of this scalar."))
.type(newNonNullType(newTypeName().name("String").build()).build())
.type(newNonNullType(newTypeName().name(STRING).build()).build())
.build())
.build();

Expand All @@ -76,6 +113,26 @@ public class Directives {
.directiveLocation(newDirectiveLocation().name(INPUT_OBJECT.name()).build())
.description(createDescription("Indicates an Input Object is a OneOf Input Object."))
.build();

DEFER_DIRECTIVE_DEFINITION = DirectiveDefinition.newDirectiveDefinition()
.name(DEFER)
.directiveLocation(newDirectiveLocation().name(FRAGMENT_SPREAD.name()).build())
.directiveLocation(newDirectiveLocation().name(INLINE_FRAGMENT.name()).build())
.description(createDescription("This directive allows results to be deferred during execution"))
.inputValueDefinition(
newInputValueDefinition()
.name("if")
.description(createDescription("Deferred behaviour is controlled by this argument"))
.type(newNonNullType(newTypeName().name(BOOLEAN).build()).build())
.defaultValue(BooleanValue.newBooleanValue(true).build())
.build())
.inputValueDefinition(
newInputValueDefinition()
.name("label")
.description(createDescription("A unique label that represents the fragment being deferred"))
.type(newTypeName().name(STRING).build())
.build())
.build();
}

/**
Expand Down Expand Up @@ -104,33 +161,36 @@ public class Directives {
.type(GraphQLString)
.description("A unique label that represents the fragment being deferred")
)
.definition(DEFER_DIRECTIVE_DEFINITION)
.build();

public static final GraphQLDirective IncludeDirective = GraphQLDirective.newDirective()
.name("include")
.name(INCLUDE)
.description("Directs the executor to include this field or fragment only when the `if` argument is true")
.argument(newArgument()
.name("if")
.type(nonNull(GraphQLBoolean))
.description("Included when true."))
.validLocations(FRAGMENT_SPREAD, INLINE_FRAGMENT, FIELD)
.definition(INCLUDE_DIRECTIVE_DEFINITION)
.build();

public static final GraphQLDirective SkipDirective = GraphQLDirective.newDirective()
.name("skip")
.name(SKIP)
.description("Directs the executor to skip this field or fragment when the `if` argument is true.")
.argument(newArgument()
.name("if")
.type(nonNull(GraphQLBoolean))
.description("Skipped when true."))
.validLocations(FRAGMENT_SPREAD, INLINE_FRAGMENT, FIELD)
.definition(SKIP_DIRECTIVE_DEFINITION)
.build();


/**
* The "deprecated" directive is special and is always available in a graphql schema
* <p>
* See https://graphql.github.io/graphql-spec/June2018/#sec--deprecated
* See <a href="https://spec.graphql.org/draft/#sec--deprecated">the GraphQL specification for @deprecated</a>
*/
public static final GraphQLDirective DeprecatedDirective = GraphQLDirective.newDirective()
.name(DEPRECATED)
Expand Down