Skip to content

Commit 9856678

Browse files
WIP: Implement support for defer in ExecutableNormalizedOperationFactory
1 parent 5cc96a0 commit 9856678

9 files changed

Lines changed: 766 additions & 22 deletions

‎src/main/java/graphql/Directives.java‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package graphql;
22

33

4+
import graphql.language.BooleanValue;
45
import graphql.language.Description;
56
import graphql.language.DirectiveDefinition;
67
import graphql.language.StringValue;
@@ -33,13 +34,21 @@ public class Directives {
3334
private static final String SPECIFIED_BY = "specifiedBy";
3435
private static final String DEPRECATED = "deprecated";
3536
private static final String ONE_OF = "oneOf";
37+
private static final String DEFER = "defer";
3638

3739
public static final String NO_LONGER_SUPPORTED = "No longer supported";
3840
public static final DirectiveDefinition DEPRECATED_DIRECTIVE_DEFINITION;
3941
public static final DirectiveDefinition SPECIFIED_BY_DIRECTIVE_DEFINITION;
4042
@ExperimentalApi
4143
public static final DirectiveDefinition ONE_OF_DIRECTIVE_DEFINITION;
4244

45+
/**
46+
* The @defer directive can be used to defer sending data for a field till later in the query. This is an opt-in
47+
* directive that is not available unless it is explicitly put into the schema.
48+
*/
49+
// @ExperimentalApi
50+
// public static final DirectiveDefinition DEFER_DIRECTIVE_DEFINITION;
51+
4352

4453
static {
4554
DEPRECATED_DIRECTIVE_DEFINITION = DirectiveDefinition.newDirectiveDefinition()
@@ -75,8 +84,56 @@ public class Directives {
7584
.directiveLocation(newDirectiveLocation().name(INPUT_OBJECT.name()).build())
7685
.description(createDescription("Indicates an Input Object is a OneOf Input Object."))
7786
.build();
87+
88+
// DEFER_DIRECTIVE_DEFINITION = DirectiveDefinition.newDirectiveDefinition()
89+
// .name(DEFER)
90+
// .description(createDescription("This directive allows results to be deferred during execution"))
91+
// .directiveLocation(newDirectiveLocation().name(FRAGMENT_SPREAD.name()).build())
92+
// .directiveLocation(newDirectiveLocation().name(INLINE_FRAGMENT.name()).build())
93+
// .inputValueDefinition(
94+
// newInputValueDefinition()
95+
// .name("if")
96+
// .description(createDescription("Deferred behaviour is controlled by this argument"))
97+
// .type(newTypeName().name("Boolean").build())
98+
// .defaultValue(BooleanValue.newBooleanValue(true).build())
99+
// .build())
100+
// .inputValueDefinition(
101+
// newInputValueDefinition()
102+
// // NOTE: as per the spec draft [https://github.com/graphql/graphql-spec/pull/742/files]:
103+
// // > `label` must not be provided as a variable.
104+
// // VALIDATION: the value of "label" MUST be unique across @defer and @stream in a query
105+
// .name("label")
106+
// .description(createDescription("A unique label that represents the fragment being deferred"))
107+
// .type(newTypeName().name("Boolean").build())
108+
// .defaultValue(BooleanValue.newBooleanValue(true).build())
109+
// .build())
110+
// .build();
78111
}
79112

113+
/**
114+
* The @defer directive can be used to defer sending data for a field till later in the query. This is an opt-in
115+
* directive that is not available unless it is explicitly put into the schema.
116+
*/
117+
public static final GraphQLDirective DeferDirective = GraphQLDirective.newDirective()
118+
.name("defer")
119+
.description("This directive allows results to be deferred during execution")
120+
.validLocations(FRAGMENT_SPREAD, INLINE_FRAGMENT)
121+
.argument(newArgument()
122+
.name("if")
123+
.type(nonNull(GraphQLBoolean))
124+
.description("Deferred behaviour is controlled by this argument")
125+
.defaultValueLiteral(BooleanValue.newBooleanValue(true).build())
126+
)
127+
.argument(newArgument()
128+
// NOTE: as per the spec draft [https://github.com/graphql/graphql-spec/pull/742/files]:
129+
// > `label` must not be provided as a variable.
130+
// VALIDATION: the value of "label" MUST be unique across @defer and @stream in a query
131+
.name("label")
132+
.type(GraphQLString)
133+
.description("A unique label that represents the fragment being deferred")
134+
)
135+
.build();
136+
80137
public static final GraphQLDirective IncludeDirective = GraphQLDirective.newDirective()
81138
.name("include")
82139
.description("Directs the executor to include this field or fragment only when the `if` argument is true")

‎src/main/java/graphql/normalized/ExecutableNormalizedField.java‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import graphql.collect.ImmutableKit;
1010
import graphql.introspection.Introspection;
1111
import graphql.language.Argument;
12+
import graphql.normalized.incremental.DeferExecution;
1213
import graphql.schema.GraphQLFieldDefinition;
1314
import graphql.schema.GraphQLInterfaceType;
1415
import graphql.schema.GraphQLNamedOutputType;
@@ -63,6 +64,7 @@ public class ExecutableNormalizedField {
6364
private final String fieldName;
6465
private final int level;
6566

67+
private final DeferExecution deferExecution;
6668

6769
private ExecutableNormalizedField(Builder builder) {
6870
this.alias = builder.alias;
@@ -74,6 +76,7 @@ private ExecutableNormalizedField(Builder builder) {
7476
this.children = builder.children;
7577
this.level = builder.level;
7678
this.parent = builder.parent;
79+
this.deferExecution = builder.deferExecution;
7780
}
7881

7982
/**
@@ -365,6 +368,14 @@ public String getSingleObjectTypeName() {
365368
}
366369

367370

371+
/**
372+
* TODO Javadoc
373+
* @return
374+
*/
375+
public DeferExecution getDeferExecution() {
376+
return deferExecution;
377+
}
378+
368379
/**
369380
* @return a helper method show field details
370381
*/
@@ -588,6 +599,8 @@ public static class Builder {
588599
private LinkedHashMap<String, Object> resolvedArguments = new LinkedHashMap<>();
589600
private ImmutableList<Argument> astArguments = ImmutableKit.emptyList();
590601

602+
private DeferExecution deferExecution;
603+
591604
private Builder() {
592605
}
593606

@@ -596,6 +609,7 @@ private Builder(ExecutableNormalizedField existing) {
596609
this.normalizedArguments = existing.normalizedArguments;
597610
this.astArguments = existing.astArguments;
598611
this.resolvedArguments = existing.resolvedArguments;
612+
this.deferExecution = existing.deferExecution;
599613
this.objectTypeNames = new LinkedHashSet<>(existing.getObjectTypeNames());
600614
this.fieldName = existing.getFieldName();
601615
this.children = new ArrayList<>(existing.children);
@@ -656,6 +670,11 @@ public Builder parent(ExecutableNormalizedField parent) {
656670
return this;
657671
}
658672

673+
public Builder deferExecution(DeferExecution deferExecution) {
674+
this.deferExecution = deferExecution;
675+
return this;
676+
}
677+
659678
public ExecutableNormalizedField build() {
660679
return new ExecutableNormalizedField(this);
661680
}

0 commit comments

Comments
 (0)