From 7694618622f06d4a8bee81abe3684c5736838d71 Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Thu, 21 Dec 2023 09:19:22 +1100 Subject: [PATCH 1/9] WIP: Created execution result classes for incremental delivery --- src/main/java/graphql/defer/DeferredItem.java | 56 +++++++++ .../defer/IncrementalExecutionResult.java | 14 +++ .../defer/IncrementalExecutionResultImpl.java | 60 ++++++++++ .../java/graphql/defer/IncrementalItem.java | 113 ++++++++++++++++++ .../InitialIncrementalExecutionResult.java | 12 ++ ...InitialIncrementalExecutionResultImpl.java | 70 +++++++++++ src/main/java/graphql/defer/StreamedItem.java | 57 +++++++++ 7 files changed, 382 insertions(+) create mode 100644 src/main/java/graphql/defer/DeferredItem.java create mode 100644 src/main/java/graphql/defer/IncrementalExecutionResult.java create mode 100644 src/main/java/graphql/defer/IncrementalExecutionResultImpl.java create mode 100644 src/main/java/graphql/defer/IncrementalItem.java create mode 100644 src/main/java/graphql/defer/InitialIncrementalExecutionResult.java create mode 100644 src/main/java/graphql/defer/InitialIncrementalExecutionResultImpl.java create mode 100644 src/main/java/graphql/defer/StreamedItem.java diff --git a/src/main/java/graphql/defer/DeferredItem.java b/src/main/java/graphql/defer/DeferredItem.java new file mode 100644 index 0000000000..248977d3c9 --- /dev/null +++ b/src/main/java/graphql/defer/DeferredItem.java @@ -0,0 +1,56 @@ +package graphql.defer; + +import graphql.ExperimentalApi; + +import java.util.LinkedHashMap; +import java.util.Map; + +@ExperimentalApi +public class DeferredItem extends IncrementalItem { + private final Object data; + + private DeferredItem(Object data, IncrementalItem incrementalExecutionResult) { + super(incrementalExecutionResult); + this.data = data; + } + + public T getData() { + //noinspection unchecked + return (T) this.data; + } + + @Override + public Map toSpecification() { + Map map = new LinkedHashMap<>(super.toSpecification()); + + if (data != null) { + map.put("data", data); + } + + return map; + } + + public static DeferredItem.Builder newDeferredItem() { + return new DeferredItem.Builder(); + } + + public static class Builder extends IncrementalItem.Builder { + private Object data = null; + private final IncrementalItem.Builder builder = IncrementalItem.newIncrementalExecutionResult(); + + public Builder data(Object data) { + this.data = data; + return this; + } + + public Builder from(IncrementalItem incrementalExecutionResult) { + builder.from(incrementalExecutionResult); + return this; + } + + public IncrementalItem build() { + IncrementalItem build = builder.build(); + return new DeferredItem(data, build); + } + } +} diff --git a/src/main/java/graphql/defer/IncrementalExecutionResult.java b/src/main/java/graphql/defer/IncrementalExecutionResult.java new file mode 100644 index 0000000000..7590c2b978 --- /dev/null +++ b/src/main/java/graphql/defer/IncrementalExecutionResult.java @@ -0,0 +1,14 @@ +package graphql.defer; + +import graphql.ExperimentalApi; + +import java.util.List; + +@ExperimentalApi +public interface IncrementalExecutionResult { + List getIncremental(); + + String getLabel(); + + boolean hasNext(); +} diff --git a/src/main/java/graphql/defer/IncrementalExecutionResultImpl.java b/src/main/java/graphql/defer/IncrementalExecutionResultImpl.java new file mode 100644 index 0000000000..1b66345a28 --- /dev/null +++ b/src/main/java/graphql/defer/IncrementalExecutionResultImpl.java @@ -0,0 +1,60 @@ +package graphql.defer; + +import java.util.Collections; +import java.util.List; + +public class IncrementalExecutionResultImpl implements IncrementalExecutionResult { + private final List incrementalItems; + private final String label; + private final boolean hasNext; + + private IncrementalExecutionResultImpl(List incrementalItems, String label, boolean hasNext) { + this.incrementalItems = incrementalItems; + this.label = label; + this.hasNext = hasNext; + } + + @Override + public List getIncremental() { + return this.incrementalItems; + } + + @Override + public String getLabel() { + return this.label; + } + + @Override + public boolean hasNext() { + return this.hasNext; + } + + public static Builder newIncrementalExecutionResult() { + return new Builder(); + } + + public static class Builder { + private boolean hasNext = false; + private List incrementalItems = Collections.emptyList(); + private String label = null; + + public IncrementalExecutionResultImpl.Builder hasNext(boolean hasNext) { + this.hasNext = hasNext; + return this; + } + + public IncrementalExecutionResultImpl.Builder incrementalItems(List incrementalItems) { + this.incrementalItems = incrementalItems; + return this; + } + + public IncrementalExecutionResultImpl.Builder label(String label) { + this.label = label; + return this; + } + + public IncrementalExecutionResultImpl build() { + return new IncrementalExecutionResultImpl(this.incrementalItems, this.label, this.hasNext); + } + } +} diff --git a/src/main/java/graphql/defer/IncrementalItem.java b/src/main/java/graphql/defer/IncrementalItem.java new file mode 100644 index 0000000000..9f315916d2 --- /dev/null +++ b/src/main/java/graphql/defer/IncrementalItem.java @@ -0,0 +1,113 @@ +package graphql.defer; + +import graphql.ExperimentalApi; +import graphql.GraphQLError; +import graphql.execution.ResultPath; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static java.util.stream.Collectors.toList; + +@ExperimentalApi +public class IncrementalItem { + private final List path; + private final List errors; + private final transient Map extensions; + + private IncrementalItem(List path, List errors, Map extensions) { + this.path = path; + this.errors = errors; + this.extensions = extensions; + } + + IncrementalItem(IncrementalItem incrementalItem) { + this(incrementalItem.getPath(), incrementalItem.getErrors(), incrementalItem.getExtensions()); + } + + public List getPath() { + return null; + } + + public List getErrors() { + return null; + } + + public Map getExtensions() { + return null; + } + + public Map toSpecification() { + Map result = new LinkedHashMap<>(); + if (errors != null && !errors.isEmpty()) { + result.put("errors", errorsToSpec(errors)); + } + if (extensions != null) { + result.put("extensions", extensions); + } + if (path != null) { + result.put("path", path); + } + return result; + } + + private Object errorsToSpec(List errors) { + return errors.stream().map(GraphQLError::toSpecification).collect(toList()); + } + + static IncrementalItem.Builder newIncrementalExecutionResult() { + return new IncrementalItem.Builder(); + } + + public static class Builder { + private List path; + private List errors = new ArrayList<>(); + private Map extensions; + + public IncrementalItem.Builder from(IncrementalItem incrementalExecutionResult) { + path = incrementalExecutionResult.getPath(); + errors = new ArrayList<>(incrementalExecutionResult.getErrors()); + extensions = incrementalExecutionResult.getExtensions(); + return this; + } + + public IncrementalItem.Builder path(ResultPath path) { + if (path != null) { + this.path = path.toList(); + } + return this; + } + + public IncrementalItem.Builder errors(List errors) { + this.errors = errors; + return this; + } + + public IncrementalItem.Builder addErrors(List errors) { + this.errors.addAll(errors); + return this; + } + + public IncrementalItem.Builder addError(GraphQLError error) { + this.errors.add(error); + return this; + } + + public IncrementalItem.Builder extensions(Map extensions) { + this.extensions = extensions; + return this; + } + + public IncrementalItem.Builder addExtension(String key, Object value) { + this.extensions = (this.extensions == null ? new LinkedHashMap<>() : this.extensions); + this.extensions.put(key, value); + return this; + } + + public IncrementalItem build() { + return new IncrementalItem(path, errors, extensions); + } + } +} diff --git a/src/main/java/graphql/defer/InitialIncrementalExecutionResult.java b/src/main/java/graphql/defer/InitialIncrementalExecutionResult.java new file mode 100644 index 0000000000..f38910e9b3 --- /dev/null +++ b/src/main/java/graphql/defer/InitialIncrementalExecutionResult.java @@ -0,0 +1,12 @@ +package graphql.defer; + +import graphql.ExecutionResult; +import graphql.ExperimentalApi; +import org.reactivestreams.Publisher; + +@ExperimentalApi +public interface InitialIncrementalExecutionResult extends ExecutionResult { + boolean hasNext(); + + Publisher getIncrementalItemPublisher(); +} diff --git a/src/main/java/graphql/defer/InitialIncrementalExecutionResultImpl.java b/src/main/java/graphql/defer/InitialIncrementalExecutionResultImpl.java new file mode 100644 index 0000000000..e90420c6b3 --- /dev/null +++ b/src/main/java/graphql/defer/InitialIncrementalExecutionResultImpl.java @@ -0,0 +1,70 @@ +package graphql.defer; + +import graphql.ExecutionResult; +import graphql.ExecutionResultImpl; +import org.reactivestreams.Publisher; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class InitialIncrementalExecutionResultImpl extends ExecutionResultImpl implements InitialIncrementalExecutionResult { + private final boolean hasNext; + private final Publisher incrementalItemPublisher; + + private InitialIncrementalExecutionResultImpl( + boolean hasNext, + Publisher incrementalItemPublisher, + ExecutionResultImpl other + ) { + super(other); + this.hasNext = hasNext; + this.incrementalItemPublisher = incrementalItemPublisher; + } + + @Override + public boolean hasNext() { + return this.hasNext; + } + + @Override + public Publisher getIncrementalItemPublisher() { + return incrementalItemPublisher; + } + + public static Builder newInitialIncrementalExecutionResult() { + return new Builder(); + } + + @Override + public Map toSpecification() { + Map map = new LinkedHashMap<>(super.toSpecification()); + map.put("hasNext", hasNext); + return map; + } + + public static class Builder { + private boolean hasNext = true; + private Publisher incrementalItemPublisher; + private ExecutionResultImpl.Builder builder = ExecutionResultImpl.newExecutionResult(); + + public Builder hasNext(boolean hasNext) { + this.hasNext = hasNext; + return this; + } + + public Builder incrementalItemPublisher(Publisher incrementalItemPublisher) { + this.incrementalItemPublisher = incrementalItemPublisher; + return this; + } + + public Builder from(ExecutionResult executionResult) { + builder.from(executionResult); + return this; + } + + public InitialIncrementalExecutionResult build() { + ExecutionResultImpl build = (ExecutionResultImpl) builder.build(); + return new InitialIncrementalExecutionResultImpl(this.hasNext, this.incrementalItemPublisher, build); + } + } +} diff --git a/src/main/java/graphql/defer/StreamedItem.java b/src/main/java/graphql/defer/StreamedItem.java new file mode 100644 index 0000000000..e8adfd254a --- /dev/null +++ b/src/main/java/graphql/defer/StreamedItem.java @@ -0,0 +1,57 @@ +package graphql.defer; + +import graphql.ExperimentalApi; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@ExperimentalApi +public class StreamedItem extends IncrementalItem { + private final List items; + + private StreamedItem(List items, IncrementalItem incrementalExecutionResult) { + super(incrementalExecutionResult); + this.items = items; + } + + public List getItems() { + //noinspection unchecked + return (List) this.items; + } + + @Override + public Map toSpecification() { + Map map = new LinkedHashMap<>(super.toSpecification()); + + if (items != null) { + map.put("items", items); + } + + return map; + } + + public static StreamedItem.Builder newStreamedItem() { + return new StreamedItem.Builder(); + } + + public static class Builder extends IncrementalItem.Builder { + private List items = null; + private final IncrementalItem.Builder builder = IncrementalItem.newIncrementalExecutionResult(); + + public Builder items(List items) { + this.items = items; + return this; + } + + public Builder from(IncrementalItem incrementalExecutionResult) { + builder.from(incrementalExecutionResult); + return this; + } + + public IncrementalItem build() { + IncrementalItem build = builder.build(); + return new StreamedItem(items, build); + } + } +} From 7aa8c23aae88646701a98ef30dde42894f029309 Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Tue, 2 Jan 2024 14:47:34 +1100 Subject: [PATCH 2/9] WIP --- .../java/graphql/ExecutionResultImpl.java | 38 +++++----- .../InitialIncrementalExecutionResult.java | 12 ---- ...InitialIncrementalExecutionResultImpl.java | 70 ------------------- .../{defer => incremental}/DeferredItem.java | 2 +- .../DelayedIncrementalExecutionResult.java} | 4 +- ...elayedIncrementalExecutionResultImpl.java} | 16 ++--- .../IncrementalExecutionResult.java | 12 ++++ .../IncrementalExecutionResultImpl.java | 65 +++++++++++++++++ .../IncrementalItem.java | 7 +- .../{defer => incremental}/StreamedItem.java | 2 +- 10 files changed, 116 insertions(+), 112 deletions(-) delete mode 100644 src/main/java/graphql/defer/InitialIncrementalExecutionResult.java delete mode 100644 src/main/java/graphql/defer/InitialIncrementalExecutionResultImpl.java rename src/main/java/graphql/{defer => incremental}/DeferredItem.java (98%) rename src/main/java/graphql/{defer/IncrementalExecutionResult.java => incremental/DelayedIncrementalExecutionResult.java} (67%) rename src/main/java/graphql/{defer/IncrementalExecutionResultImpl.java => incremental/DelayedIncrementalExecutionResultImpl.java} (60%) create mode 100644 src/main/java/graphql/incremental/IncrementalExecutionResult.java create mode 100644 src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java rename src/main/java/graphql/{defer => incremental}/IncrementalItem.java (95%) rename src/main/java/graphql/{defer => incremental}/StreamedItem.java (98%) diff --git a/src/main/java/graphql/ExecutionResultImpl.java b/src/main/java/graphql/ExecutionResultImpl.java index 33ddd67e21..62419a63a7 100644 --- a/src/main/java/graphql/ExecutionResultImpl.java +++ b/src/main/java/graphql/ExecutionResultImpl.java @@ -40,6 +40,10 @@ public ExecutionResultImpl(ExecutionResultImpl other) { this(other.dataPresent, other.data, other.errors, other.extensions); } + public > ExecutionResultImpl(Builder builder) { + this(builder.dataPresent, builder.data, builder.errors, builder.extensions); + } + private ExecutionResultImpl(boolean dataPresent, Object data, List errors, Map extensions) { this.dataPresent = dataPresent; this.data = data; @@ -103,61 +107,61 @@ public String toString() { '}'; } - public static Builder newExecutionResult() { - return new Builder(); + public static > Builder newExecutionResult() { + return new Builder<>(); } - public static class Builder implements ExecutionResult.Builder { + public static class Builder> implements ExecutionResult.Builder { private boolean dataPresent; private Object data; private List errors = new ArrayList<>(); private Map extensions; @Override - public Builder from(ExecutionResult executionResult) { + public T from(ExecutionResult executionResult) { dataPresent = executionResult.isDataPresent(); data = executionResult.getData(); errors = new ArrayList<>(executionResult.getErrors()); extensions = executionResult.getExtensions(); - return this; + return (T) this; } @Override - public Builder data(Object data) { + public T data(Object data) { dataPresent = true; this.data = data; - return this; + return (T) this; } @Override - public Builder errors(List errors) { + public T errors(List errors) { this.errors = errors; - return this; + return (T) this; } @Override - public Builder addErrors(List errors) { + public T addErrors(List errors) { this.errors.addAll(errors); - return this; + return (T) this; } @Override - public Builder addError(GraphQLError error) { + public T addError(GraphQLError error) { this.errors.add(error); - return this; + return (T) this; } @Override - public Builder extensions(Map extensions) { + public T extensions(Map extensions) { this.extensions = extensions; - return this; + return (T) this; } @Override - public Builder addExtension(String key, Object value) { + public T addExtension(String key, Object value) { this.extensions = (this.extensions == null ? new LinkedHashMap<>() : this.extensions); this.extensions.put(key, value); - return this; + return (T) this; } @Override diff --git a/src/main/java/graphql/defer/InitialIncrementalExecutionResult.java b/src/main/java/graphql/defer/InitialIncrementalExecutionResult.java deleted file mode 100644 index f38910e9b3..0000000000 --- a/src/main/java/graphql/defer/InitialIncrementalExecutionResult.java +++ /dev/null @@ -1,12 +0,0 @@ -package graphql.defer; - -import graphql.ExecutionResult; -import graphql.ExperimentalApi; -import org.reactivestreams.Publisher; - -@ExperimentalApi -public interface InitialIncrementalExecutionResult extends ExecutionResult { - boolean hasNext(); - - Publisher getIncrementalItemPublisher(); -} diff --git a/src/main/java/graphql/defer/InitialIncrementalExecutionResultImpl.java b/src/main/java/graphql/defer/InitialIncrementalExecutionResultImpl.java deleted file mode 100644 index e90420c6b3..0000000000 --- a/src/main/java/graphql/defer/InitialIncrementalExecutionResultImpl.java +++ /dev/null @@ -1,70 +0,0 @@ -package graphql.defer; - -import graphql.ExecutionResult; -import graphql.ExecutionResultImpl; -import org.reactivestreams.Publisher; - -import java.util.LinkedHashMap; -import java.util.Map; - -public class InitialIncrementalExecutionResultImpl extends ExecutionResultImpl implements InitialIncrementalExecutionResult { - private final boolean hasNext; - private final Publisher incrementalItemPublisher; - - private InitialIncrementalExecutionResultImpl( - boolean hasNext, - Publisher incrementalItemPublisher, - ExecutionResultImpl other - ) { - super(other); - this.hasNext = hasNext; - this.incrementalItemPublisher = incrementalItemPublisher; - } - - @Override - public boolean hasNext() { - return this.hasNext; - } - - @Override - public Publisher getIncrementalItemPublisher() { - return incrementalItemPublisher; - } - - public static Builder newInitialIncrementalExecutionResult() { - return new Builder(); - } - - @Override - public Map toSpecification() { - Map map = new LinkedHashMap<>(super.toSpecification()); - map.put("hasNext", hasNext); - return map; - } - - public static class Builder { - private boolean hasNext = true; - private Publisher incrementalItemPublisher; - private ExecutionResultImpl.Builder builder = ExecutionResultImpl.newExecutionResult(); - - public Builder hasNext(boolean hasNext) { - this.hasNext = hasNext; - return this; - } - - public Builder incrementalItemPublisher(Publisher incrementalItemPublisher) { - this.incrementalItemPublisher = incrementalItemPublisher; - return this; - } - - public Builder from(ExecutionResult executionResult) { - builder.from(executionResult); - return this; - } - - public InitialIncrementalExecutionResult build() { - ExecutionResultImpl build = (ExecutionResultImpl) builder.build(); - return new InitialIncrementalExecutionResultImpl(this.hasNext, this.incrementalItemPublisher, build); - } - } -} diff --git a/src/main/java/graphql/defer/DeferredItem.java b/src/main/java/graphql/incremental/DeferredItem.java similarity index 98% rename from src/main/java/graphql/defer/DeferredItem.java rename to src/main/java/graphql/incremental/DeferredItem.java index 248977d3c9..fcdbb65a9f 100644 --- a/src/main/java/graphql/defer/DeferredItem.java +++ b/src/main/java/graphql/incremental/DeferredItem.java @@ -1,4 +1,4 @@ -package graphql.defer; +package graphql.incremental; import graphql.ExperimentalApi; diff --git a/src/main/java/graphql/defer/IncrementalExecutionResult.java b/src/main/java/graphql/incremental/DelayedIncrementalExecutionResult.java similarity index 67% rename from src/main/java/graphql/defer/IncrementalExecutionResult.java rename to src/main/java/graphql/incremental/DelayedIncrementalExecutionResult.java index 7590c2b978..03650be1b2 100644 --- a/src/main/java/graphql/defer/IncrementalExecutionResult.java +++ b/src/main/java/graphql/incremental/DelayedIncrementalExecutionResult.java @@ -1,11 +1,11 @@ -package graphql.defer; +package graphql.incremental; import graphql.ExperimentalApi; import java.util.List; @ExperimentalApi -public interface IncrementalExecutionResult { +public interface DelayedIncrementalExecutionResult { List getIncremental(); String getLabel(); diff --git a/src/main/java/graphql/defer/IncrementalExecutionResultImpl.java b/src/main/java/graphql/incremental/DelayedIncrementalExecutionResultImpl.java similarity index 60% rename from src/main/java/graphql/defer/IncrementalExecutionResultImpl.java rename to src/main/java/graphql/incremental/DelayedIncrementalExecutionResultImpl.java index 1b66345a28..54645b24f0 100644 --- a/src/main/java/graphql/defer/IncrementalExecutionResultImpl.java +++ b/src/main/java/graphql/incremental/DelayedIncrementalExecutionResultImpl.java @@ -1,14 +1,14 @@ -package graphql.defer; +package graphql.incremental; import java.util.Collections; import java.util.List; -public class IncrementalExecutionResultImpl implements IncrementalExecutionResult { +public class DelayedIncrementalExecutionResultImpl implements DelayedIncrementalExecutionResult { private final List incrementalItems; private final String label; private final boolean hasNext; - private IncrementalExecutionResultImpl(List incrementalItems, String label, boolean hasNext) { + private DelayedIncrementalExecutionResultImpl(List incrementalItems, String label, boolean hasNext) { this.incrementalItems = incrementalItems; this.label = label; this.hasNext = hasNext; @@ -38,23 +38,23 @@ public static class Builder { private List incrementalItems = Collections.emptyList(); private String label = null; - public IncrementalExecutionResultImpl.Builder hasNext(boolean hasNext) { + public DelayedIncrementalExecutionResultImpl.Builder hasNext(boolean hasNext) { this.hasNext = hasNext; return this; } - public IncrementalExecutionResultImpl.Builder incrementalItems(List incrementalItems) { + public DelayedIncrementalExecutionResultImpl.Builder incrementalItems(List incrementalItems) { this.incrementalItems = incrementalItems; return this; } - public IncrementalExecutionResultImpl.Builder label(String label) { + public DelayedIncrementalExecutionResultImpl.Builder label(String label) { this.label = label; return this; } - public IncrementalExecutionResultImpl build() { - return new IncrementalExecutionResultImpl(this.incrementalItems, this.label, this.hasNext); + public DelayedIncrementalExecutionResultImpl build() { + return new DelayedIncrementalExecutionResultImpl(this.incrementalItems, this.label, this.hasNext); } } } diff --git a/src/main/java/graphql/incremental/IncrementalExecutionResult.java b/src/main/java/graphql/incremental/IncrementalExecutionResult.java new file mode 100644 index 0000000000..d0178092b7 --- /dev/null +++ b/src/main/java/graphql/incremental/IncrementalExecutionResult.java @@ -0,0 +1,12 @@ +package graphql.incremental; + +import graphql.ExecutionResult; +import graphql.ExperimentalApi; +import org.reactivestreams.Publisher; + +@ExperimentalApi +public interface IncrementalExecutionResult extends ExecutionResult { + boolean hasNext(); + + Publisher getIncrementalItemPublisher(); +} diff --git a/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java b/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java new file mode 100644 index 0000000000..c12b4d40d4 --- /dev/null +++ b/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java @@ -0,0 +1,65 @@ +package graphql.incremental; + +import graphql.ExecutionResultImpl; +import org.reactivestreams.Publisher; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class IncrementalExecutionResultImpl extends ExecutionResultImpl implements IncrementalExecutionResult { + private final boolean hasNext; + private final Publisher incrementalItemPublisher; + + private IncrementalExecutionResultImpl( + Builder builder + ) { + super(builder); + this.hasNext = builder.hasNext; + this.incrementalItemPublisher = builder.incrementalItemPublisher; + } + + @Override + public boolean hasNext() { + return this.hasNext; + } + + @Override + public Publisher getIncrementalItemPublisher() { + return incrementalItemPublisher; + } + + public static Builder newIncrementalExecutionResult() { + return new Builder(); + } + + @Override + public Map toSpecification() { + Map map = new LinkedHashMap<>(super.toSpecification()); + map.put("hasNext", hasNext); + return map; + } + + public static class Builder extends ExecutionResultImpl.Builder { + private boolean hasNext = true; + private Publisher incrementalItemPublisher; + + public Builder hasNext(boolean hasNext) { + this.hasNext = hasNext; + return this; + } + + public Builder incrementalItemPublisher(Publisher incrementalItemPublisher) { + this.incrementalItemPublisher = incrementalItemPublisher; + return this; + } + +// public Builder from(ExecutionResult executionResult) { +// builder.from(executionResult); +// return this; +// } + + public IncrementalExecutionResult build() { + return new IncrementalExecutionResultImpl(this); + } + } +} diff --git a/src/main/java/graphql/defer/IncrementalItem.java b/src/main/java/graphql/incremental/IncrementalItem.java similarity index 95% rename from src/main/java/graphql/defer/IncrementalItem.java rename to src/main/java/graphql/incremental/IncrementalItem.java index 9f315916d2..9639c168e8 100644 --- a/src/main/java/graphql/defer/IncrementalItem.java +++ b/src/main/java/graphql/incremental/IncrementalItem.java @@ -1,4 +1,4 @@ -package graphql.defer; +package graphql.incremental; import graphql.ExperimentalApi; import graphql.GraphQLError; @@ -80,6 +80,11 @@ public IncrementalItem.Builder path(ResultPath path) { return this; } + public IncrementalItem.Builder path(List path) { + this.path = path; + return this; + } + public IncrementalItem.Builder errors(List errors) { this.errors = errors; return this; diff --git a/src/main/java/graphql/defer/StreamedItem.java b/src/main/java/graphql/incremental/StreamedItem.java similarity index 98% rename from src/main/java/graphql/defer/StreamedItem.java rename to src/main/java/graphql/incremental/StreamedItem.java index e8adfd254a..b07b259f8b 100644 --- a/src/main/java/graphql/defer/StreamedItem.java +++ b/src/main/java/graphql/incremental/StreamedItem.java @@ -1,4 +1,4 @@ -package graphql.defer; +package graphql.incremental; import graphql.ExperimentalApi; From 0025495b5f0437a5de9b2dc875da826f7ebcfb19 Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Mon, 8 Jan 2024 18:18:29 +1100 Subject: [PATCH 3/9] WIP --- .../ExecutableNormalizedFieldTest.groovy | 3 +- ...NormalizedOperationFactoryDeferTest.groovy | 35 +++++++- ...tableNormalizedOperationFactoryTest.groovy | 88 ++++++++----------- ...izedOperationToAstCompilerDeferTest.groovy | 3 +- ...ormalizedOperationToAstCompilerTest.groovy | 3 +- 5 files changed, 71 insertions(+), 61 deletions(-) diff --git a/src/test/groovy/graphql/normalized/ExecutableNormalizedFieldTest.groovy b/src/test/groovy/graphql/normalized/ExecutableNormalizedFieldTest.groovy index dc3db5daa4..6debbb2ff2 100644 --- a/src/test/groovy/graphql/normalized/ExecutableNormalizedFieldTest.groovy +++ b/src/test/groovy/graphql/normalized/ExecutableNormalizedFieldTest.groovy @@ -48,8 +48,7 @@ class ExecutableNormalizedFieldTest extends Specification { """ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory normalizedOperationFactory = new ExecutableNormalizedOperationFactory() - def normalizedOperation = normalizedOperationFactory.createExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) + def normalizedOperation = ExecutableNormalizedOperationFactory.createExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def pets = normalizedOperation.getTopLevelFields()[0] def allChildren = pets.getChildren() diff --git a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryDeferTest.groovy b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryDeferTest.groovy index eb2260ee11..85a4fc85f6 100644 --- a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryDeferTest.groovy +++ b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryDeferTest.groovy @@ -143,6 +143,35 @@ class ExecutableNormalizedOperationFactoryDeferTest extends Specification { ] } + def "fragments on non-conditional fields - andi"() { + given: + + String query = ''' + query q { + dog { + ... @defer { + name + age + } + ... @defer { + age + } + } + } + ''' +// This should result in age being on its own deferBlock + Map variables = [:] + + when: + List printedTree = executeQueryAndPrintTree(query, variables) + + then: + printedTree == ['Query.dog', + "Dog.name defer{[label=null;types=[Dog]]}", + "Dog.age defer{[label=null;types=[Dog]],[label=null;types=[Dog]]}", + ] + } + def "fragments on subset of non-conditional fields"() { given: @@ -839,9 +868,8 @@ class ExecutableNormalizedOperationFactoryDeferTest extends Specification { private ExecutableNormalizedOperation createExecutableNormalizedOperations(String query, Map variables) { assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() - return dependencyGraph.createExecutableNormalizedOperationWithRawVariables( + return ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables( graphQLSchema, document, null, @@ -853,9 +881,8 @@ class ExecutableNormalizedOperationFactoryDeferTest extends Specification { private List executeQueryAndPrintTree(String query, Map variables) { assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() - def tree = dependencyGraph.createExecutableNormalizedOperationWithRawVariables( + def tree = ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables( graphQLSchema, document, null, diff --git a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryTest.groovy b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryTest.groovy index 432075a363..9a45a413db 100644 --- a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryTest.groovy +++ b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryTest.groovy @@ -200,7 +200,6 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -280,7 +279,6 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -331,7 +329,6 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -374,7 +371,6 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -424,7 +420,6 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -487,7 +482,6 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -533,7 +527,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -577,7 +571,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -621,7 +615,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -653,7 +647,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -704,7 +698,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -754,7 +748,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -793,7 +787,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -837,7 +831,6 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - def dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -877,7 +870,6 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - def dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -925,7 +917,6 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - def dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -1028,7 +1019,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) def subFooField = (document.getDefinitions()[1] as FragmentDefinition).getSelectionSet().getSelections()[0] as Field - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def fieldToNormalizedField = tree.getFieldToNormalizedField() @@ -1071,7 +1062,7 @@ type Dog implements Animal{ def petsField = (document.getDefinitions()[0] as OperationDefinition).getSelectionSet().getSelections()[0] as Field def idField = petsField.getSelectionSet().getSelections()[0] as Field - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def fieldToNormalizedField = tree.getFieldToNormalizedField() @@ -1120,7 +1111,7 @@ type Dog implements Animal{ def schemaField = selections[2] as Field def typeField = selections[3] as Field - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def fieldToNormalizedField = tree.getFieldToNormalizedField() @@ -1177,7 +1168,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -1220,7 +1211,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -1248,7 +1239,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def normalizedFieldToMergedField = tree.getNormalizedFieldToMergedField() Traverser traverser = Traverser.depthFirst({ it.getChildren() }) @@ -1286,7 +1277,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) @@ -1387,7 +1378,7 @@ schema { Document document = TestUtil.parseQuery(mutation) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -1437,7 +1428,7 @@ schema { assertValidQuery(graphQLSchema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def variables = [ var1: [bar: 123], var2: [foo: "foo", input2: [bar: 123]] @@ -1484,7 +1475,6 @@ schema { assertValidQuery(graphQLSchema, query) def document = TestUtil.parseQuery(query) - def dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.emptyVariables()) @@ -1519,7 +1509,6 @@ schema { assertValidQuery(graphQLSchema, query) def document = TestUtil.parseQuery(query) - def dependencyGraph = new ExecutableNormalizedOperationFactory() def variables = [ varIds : null, otherVar: null, @@ -1575,7 +1564,7 @@ schema { ] assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.of(variables)) def topLevelField = tree.getTopLevelFields().get(0) @@ -1628,7 +1617,7 @@ schema { ] assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.of(variables)) def topLevelField = tree.getTopLevelFields().get(0) @@ -1683,7 +1672,7 @@ schema { ''' assertValidQuery(graphQLSchema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.emptyVariables()) @@ -1741,7 +1730,7 @@ schema { ''' assertValidQuery(graphQLSchema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -1789,7 +1778,7 @@ schema { ''' assertValidQuery(graphQLSchema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -1865,7 +1854,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -1929,7 +1918,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -1986,7 +1975,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2061,7 +2050,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2123,7 +2112,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2165,7 +2154,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2208,7 +2197,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2251,7 +2240,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2326,7 +2315,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2402,7 +2391,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2464,7 +2453,7 @@ schema { def variables = ["true": Boolean.TRUE, "false": Boolean.FALSE] assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.of(variables)) println String.join("\n", printTree(tree)) @@ -2521,7 +2510,7 @@ schema { def variables = [:] assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.of(variables)) def printedTree = printTreeAndDirectives(tree) @@ -2586,7 +2575,7 @@ fragment personName on Person { Document document = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -2639,7 +2628,6 @@ fragment personName on Person { Document document = TestUtil.parseQuery(query) - def dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -2686,7 +2674,6 @@ fragment personName on Person { Document document = TestUtil.parseQuery(query) - def dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -2884,10 +2871,9 @@ fragment personName on Person { String operationName, CoercedVariables coercedVariableValues ) { - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def options = ExecutableNormalizedOperationFactory.Options.defaultOptions().deferSupport(deferSupport) - return dependencyGraph.createExecutableNormalizedOperation(graphQLSchema, document, operationName, coercedVariableValues, options) + return ExecutableNormalizedOperationFactory.createExecutableNormalizedOperation(graphQLSchema, document, operationName, coercedVariableValues, options) } private static ExecutableNormalizedOperation localCreateExecutableNormalizedOperationWithRawVariables( @@ -2896,10 +2882,10 @@ fragment personName on Person { String operationName, RawVariables rawVariables ) { - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() + def options = ExecutableNormalizedOperationFactory.Options.defaultOptions().deferSupport(deferSupport) - return dependencyGraph.createExecutableNormalizedOperationWithRawVariables( + return ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables( graphQLSchema, document, operationName, diff --git a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerDeferTest.groovy b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerDeferTest.groovy index 8d7f9e91a3..dab369b974 100644 --- a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerDeferTest.groovy +++ b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerDeferTest.groovy @@ -491,9 +491,8 @@ class ExecutableNormalizedOperationToAstCompilerDeferTest extends Specification assertValidQuery(schema, query, variables) Document originalDocument = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def options = ExecutableNormalizedOperationFactory.Options.defaultOptions().deferSupport(true) - return dependencyGraph.createExecutableNormalizedOperationWithRawVariables( + return ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables( schema, originalDocument, null, diff --git a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerTest.groovy b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerTest.groovy index 8b35c67b09..27c4c89a6d 100644 --- a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerTest.groovy +++ b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerTest.groovy @@ -2145,9 +2145,8 @@ abstract class ExecutableNormalizedOperationToAstCompilerTest extends Specificat assertValidQuery(schema, query, variables) Document originalDocument = TestUtil.parseQuery(query) - ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def options = ExecutableNormalizedOperationFactory.Options.defaultOptions().deferSupport(deferSupport) - return dependencyGraph.createExecutableNormalizedOperationWithRawVariables(schema, originalDocument, null, RawVariables.of(variables), options) + return ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables(schema, originalDocument, null, RawVariables.of(variables), options) } private List createNormalizedFields(GraphQLSchema schema, String query, Map variables = [:]) { From b02efd85bae49d9fa94c62a4e43b5ccead7e2c3d Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Wed, 10 Jan 2024 09:20:50 +1100 Subject: [PATCH 4/9] Revert "WIP" This reverts commit 0025495b5f0437a5de9b2dc875da826f7ebcfb19. --- .../ExecutableNormalizedFieldTest.groovy | 3 +- ...NormalizedOperationFactoryDeferTest.groovy | 35 +------- ...tableNormalizedOperationFactoryTest.groovy | 88 +++++++++++-------- ...izedOperationToAstCompilerDeferTest.groovy | 3 +- ...ormalizedOperationToAstCompilerTest.groovy | 3 +- 5 files changed, 61 insertions(+), 71 deletions(-) diff --git a/src/test/groovy/graphql/normalized/ExecutableNormalizedFieldTest.groovy b/src/test/groovy/graphql/normalized/ExecutableNormalizedFieldTest.groovy index 6debbb2ff2..dc3db5daa4 100644 --- a/src/test/groovy/graphql/normalized/ExecutableNormalizedFieldTest.groovy +++ b/src/test/groovy/graphql/normalized/ExecutableNormalizedFieldTest.groovy @@ -48,7 +48,8 @@ class ExecutableNormalizedFieldTest extends Specification { """ Document document = TestUtil.parseQuery(query) - def normalizedOperation = ExecutableNormalizedOperationFactory.createExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) + ExecutableNormalizedOperationFactory normalizedOperationFactory = new ExecutableNormalizedOperationFactory() + def normalizedOperation = normalizedOperationFactory.createExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def pets = normalizedOperation.getTopLevelFields()[0] def allChildren = pets.getChildren() diff --git a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryDeferTest.groovy b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryDeferTest.groovy index 85a4fc85f6..eb2260ee11 100644 --- a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryDeferTest.groovy +++ b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryDeferTest.groovy @@ -143,35 +143,6 @@ class ExecutableNormalizedOperationFactoryDeferTest extends Specification { ] } - def "fragments on non-conditional fields - andi"() { - given: - - String query = ''' - query q { - dog { - ... @defer { - name - age - } - ... @defer { - age - } - } - } - ''' -// This should result in age being on its own deferBlock - Map variables = [:] - - when: - List printedTree = executeQueryAndPrintTree(query, variables) - - then: - printedTree == ['Query.dog', - "Dog.name defer{[label=null;types=[Dog]]}", - "Dog.age defer{[label=null;types=[Dog]],[label=null;types=[Dog]]}", - ] - } - def "fragments on subset of non-conditional fields"() { given: @@ -868,8 +839,9 @@ class ExecutableNormalizedOperationFactoryDeferTest extends Specification { private ExecutableNormalizedOperation createExecutableNormalizedOperations(String query, Map variables) { assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() - return ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables( + return dependencyGraph.createExecutableNormalizedOperationWithRawVariables( graphQLSchema, document, null, @@ -881,8 +853,9 @@ class ExecutableNormalizedOperationFactoryDeferTest extends Specification { private List executeQueryAndPrintTree(String query, Map variables) { assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() - def tree = ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables( + def tree = dependencyGraph.createExecutableNormalizedOperationWithRawVariables( graphQLSchema, document, null, diff --git a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryTest.groovy b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryTest.groovy index 9a45a413db..432075a363 100644 --- a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryTest.groovy +++ b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationFactoryTest.groovy @@ -200,6 +200,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -279,6 +280,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -329,6 +331,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -371,6 +374,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -420,6 +424,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -482,6 +487,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -527,7 +533,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -571,7 +577,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -615,7 +621,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -647,7 +653,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -698,7 +704,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -748,7 +754,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -787,7 +793,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -831,6 +837,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) + def dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -870,6 +877,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) + def dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -917,6 +925,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) + def dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -1019,7 +1028,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) def subFooField = (document.getDefinitions()[1] as FragmentDefinition).getSelectionSet().getSelections()[0] as Field - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def fieldToNormalizedField = tree.getFieldToNormalizedField() @@ -1062,7 +1071,7 @@ type Dog implements Animal{ def petsField = (document.getDefinitions()[0] as OperationDefinition).getSelectionSet().getSelections()[0] as Field def idField = petsField.getSelectionSet().getSelections()[0] as Field - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def fieldToNormalizedField = tree.getFieldToNormalizedField() @@ -1111,7 +1120,7 @@ type Dog implements Animal{ def schemaField = selections[2] as Field def typeField = selections[3] as Field - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def fieldToNormalizedField = tree.getFieldToNormalizedField() @@ -1168,7 +1177,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -1211,7 +1220,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTree(tree) @@ -1239,7 +1248,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def normalizedFieldToMergedField = tree.getNormalizedFieldToMergedField() Traverser traverser = Traverser.depthFirst({ it.getChildren() }) @@ -1277,7 +1286,7 @@ type Dog implements Animal{ Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) @@ -1378,7 +1387,7 @@ schema { Document document = TestUtil.parseQuery(mutation) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -1428,7 +1437,7 @@ schema { assertValidQuery(graphQLSchema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def variables = [ var1: [bar: 123], var2: [foo: "foo", input2: [bar: 123]] @@ -1475,6 +1484,7 @@ schema { assertValidQuery(graphQLSchema, query) def document = TestUtil.parseQuery(query) + def dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.emptyVariables()) @@ -1509,6 +1519,7 @@ schema { assertValidQuery(graphQLSchema, query) def document = TestUtil.parseQuery(query) + def dependencyGraph = new ExecutableNormalizedOperationFactory() def variables = [ varIds : null, otherVar: null, @@ -1564,7 +1575,7 @@ schema { ] assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.of(variables)) def topLevelField = tree.getTopLevelFields().get(0) @@ -1617,7 +1628,7 @@ schema { ] assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.of(variables)) def topLevelField = tree.getTopLevelFields().get(0) @@ -1672,7 +1683,7 @@ schema { ''' assertValidQuery(graphQLSchema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.emptyVariables()) @@ -1730,7 +1741,7 @@ schema { ''' assertValidQuery(graphQLSchema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -1778,7 +1789,7 @@ schema { ''' assertValidQuery(graphQLSchema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -1854,7 +1865,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -1918,7 +1929,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -1975,7 +1986,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2050,7 +2061,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2112,7 +2123,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2154,7 +2165,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2197,7 +2208,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2240,7 +2251,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2315,7 +2326,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2391,7 +2402,7 @@ schema { ''' assertValidQuery(schema, query) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(schema, document, null, RawVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, schema) @@ -2453,7 +2464,7 @@ schema { def variables = ["true": Boolean.TRUE, "false": Boolean.FALSE] assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.of(variables)) println String.join("\n", printTree(tree)) @@ -2510,7 +2521,7 @@ schema { def variables = [:] assertValidQuery(graphQLSchema, query, variables) Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() when: def tree = localCreateExecutableNormalizedOperationWithRawVariables(graphQLSchema, document, null, RawVariables.of(variables)) def printedTree = printTreeAndDirectives(tree) @@ -2575,7 +2586,7 @@ fragment personName on Person { Document document = TestUtil.parseQuery(query) - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -2628,6 +2639,7 @@ fragment personName on Person { Document document = TestUtil.parseQuery(query) + def dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -2674,6 +2686,7 @@ fragment personName on Person { Document document = TestUtil.parseQuery(query) + def dependencyGraph = new ExecutableNormalizedOperationFactory() def tree = localCreateExecutableNormalizedOperation(graphQLSchema, document, null, CoercedVariables.emptyVariables()) def printedTree = printTreeWithLevelInfo(tree, graphQLSchema) @@ -2871,9 +2884,10 @@ fragment personName on Person { String operationName, CoercedVariables coercedVariableValues ) { + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def options = ExecutableNormalizedOperationFactory.Options.defaultOptions().deferSupport(deferSupport) - return ExecutableNormalizedOperationFactory.createExecutableNormalizedOperation(graphQLSchema, document, operationName, coercedVariableValues, options) + return dependencyGraph.createExecutableNormalizedOperation(graphQLSchema, document, operationName, coercedVariableValues, options) } private static ExecutableNormalizedOperation localCreateExecutableNormalizedOperationWithRawVariables( @@ -2882,10 +2896,10 @@ fragment personName on Person { String operationName, RawVariables rawVariables ) { - + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def options = ExecutableNormalizedOperationFactory.Options.defaultOptions().deferSupport(deferSupport) - return ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables( + return dependencyGraph.createExecutableNormalizedOperationWithRawVariables( graphQLSchema, document, operationName, diff --git a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerDeferTest.groovy b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerDeferTest.groovy index dab369b974..8d7f9e91a3 100644 --- a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerDeferTest.groovy +++ b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerDeferTest.groovy @@ -491,8 +491,9 @@ class ExecutableNormalizedOperationToAstCompilerDeferTest extends Specification assertValidQuery(schema, query, variables) Document originalDocument = TestUtil.parseQuery(query) + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def options = ExecutableNormalizedOperationFactory.Options.defaultOptions().deferSupport(true) - return ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables( + return dependencyGraph.createExecutableNormalizedOperationWithRawVariables( schema, originalDocument, null, diff --git a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerTest.groovy b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerTest.groovy index 27c4c89a6d..8b35c67b09 100644 --- a/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerTest.groovy +++ b/src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerTest.groovy @@ -2145,8 +2145,9 @@ abstract class ExecutableNormalizedOperationToAstCompilerTest extends Specificat assertValidQuery(schema, query, variables) Document originalDocument = TestUtil.parseQuery(query) + ExecutableNormalizedOperationFactory dependencyGraph = new ExecutableNormalizedOperationFactory() def options = ExecutableNormalizedOperationFactory.Options.defaultOptions().deferSupport(deferSupport) - return ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables(schema, originalDocument, null, RawVariables.of(variables), options) + return dependencyGraph.createExecutableNormalizedOperationWithRawVariables(schema, originalDocument, null, RawVariables.of(variables), options) } private List createNormalizedFields(GraphQLSchema schema, String query, Map variables = [:]) { From cbd9b634d34fd81e91cde2ca24c356a479e635d5 Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Wed, 10 Jan 2024 13:42:55 +1100 Subject: [PATCH 5/9] Fixes on IncrementalItem hierarchy --- .../graphql/incremental/DeferredItem.java | 20 ++++--- .../graphql/incremental/IncrementalItem.java | 56 ++++++++----------- .../graphql/incremental/StreamedItem.java | 19 ++++--- 3 files changed, 44 insertions(+), 51 deletions(-) diff --git a/src/main/java/graphql/incremental/DeferredItem.java b/src/main/java/graphql/incremental/DeferredItem.java index fcdbb65a9f..b3b3f42e87 100644 --- a/src/main/java/graphql/incremental/DeferredItem.java +++ b/src/main/java/graphql/incremental/DeferredItem.java @@ -1,16 +1,18 @@ package graphql.incremental; import graphql.ExperimentalApi; +import graphql.GraphQLError; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; @ExperimentalApi public class DeferredItem extends IncrementalItem { private final Object data; - private DeferredItem(Object data, IncrementalItem incrementalExecutionResult) { - super(incrementalExecutionResult); + private DeferredItem(Object data, List path, List errors, Map extensions) { + super(path, errors, extensions); this.data = data; } @@ -34,23 +36,23 @@ public static DeferredItem.Builder newDeferredItem() { return new DeferredItem.Builder(); } - public static class Builder extends IncrementalItem.Builder { + public static class Builder extends IncrementalItem.Builder { private Object data = null; - private final IncrementalItem.Builder builder = IncrementalItem.newIncrementalExecutionResult(); public Builder data(Object data) { this.data = data; return this; } - public Builder from(IncrementalItem incrementalExecutionResult) { - builder.from(incrementalExecutionResult); + public Builder from(DeferredItem deferredItem) { + super.from(deferredItem); + this.data = deferredItem.data; return this; } - public IncrementalItem build() { - IncrementalItem build = builder.build(); - return new DeferredItem(data, build); + @Override + public DeferredItem build() { + return new DeferredItem(data, this.path, this.errors, this.extensions); } } } diff --git a/src/main/java/graphql/incremental/IncrementalItem.java b/src/main/java/graphql/incremental/IncrementalItem.java index 9639c168e8..b504143486 100644 --- a/src/main/java/graphql/incremental/IncrementalItem.java +++ b/src/main/java/graphql/incremental/IncrementalItem.java @@ -12,34 +12,30 @@ import static java.util.stream.Collectors.toList; @ExperimentalApi -public class IncrementalItem { +public abstract class IncrementalItem { private final List path; private final List errors; private final transient Map extensions; - private IncrementalItem(List path, List errors, Map extensions) { + protected IncrementalItem(List path, List errors, Map extensions) { this.path = path; this.errors = errors; this.extensions = extensions; } - IncrementalItem(IncrementalItem incrementalItem) { - this(incrementalItem.getPath(), incrementalItem.getErrors(), incrementalItem.getExtensions()); - } - public List getPath() { - return null; + return this.path; } public List getErrors() { - return null; + return this.errors; } public Map getExtensions() { - return null; + return this.extensions; } - public Map toSpecification() { + protected Map toSpecification() { Map result = new LinkedHashMap<>(); if (errors != null && !errors.isEmpty()) { result.put("errors", errorsToSpec(errors)); @@ -53,66 +49,60 @@ public Map toSpecification() { return result; } - private Object errorsToSpec(List errors) { + protected Object errorsToSpec(List errors) { return errors.stream().map(GraphQLError::toSpecification).collect(toList()); } - static IncrementalItem.Builder newIncrementalExecutionResult() { - return new IncrementalItem.Builder(); - } + protected static abstract class Builder { + protected List path; + protected List errors = new ArrayList<>(); + protected Map extensions; - public static class Builder { - private List path; - private List errors = new ArrayList<>(); - private Map extensions; - - public IncrementalItem.Builder from(IncrementalItem incrementalExecutionResult) { - path = incrementalExecutionResult.getPath(); - errors = new ArrayList<>(incrementalExecutionResult.getErrors()); - extensions = incrementalExecutionResult.getExtensions(); + public Builder from(T incrementalExecutionResult) { + this.path = incrementalExecutionResult.getPath(); + this.errors = new ArrayList<>(incrementalExecutionResult.getErrors()); + this.extensions = incrementalExecutionResult.getExtensions(); return this; } - public IncrementalItem.Builder path(ResultPath path) { + public Builder path(ResultPath path) { if (path != null) { this.path = path.toList(); } return this; } - public IncrementalItem.Builder path(List path) { + public Builder path(List path) { this.path = path; return this; } - public IncrementalItem.Builder errors(List errors) { + public Builder errors(List errors) { this.errors = errors; return this; } - public IncrementalItem.Builder addErrors(List errors) { + public Builder addErrors(List errors) { this.errors.addAll(errors); return this; } - public IncrementalItem.Builder addError(GraphQLError error) { + public Builder addError(GraphQLError error) { this.errors.add(error); return this; } - public IncrementalItem.Builder extensions(Map extensions) { + public Builder extensions(Map extensions) { this.extensions = extensions; return this; } - public IncrementalItem.Builder addExtension(String key, Object value) { + public Builder addExtension(String key, Object value) { this.extensions = (this.extensions == null ? new LinkedHashMap<>() : this.extensions); this.extensions.put(key, value); return this; } - public IncrementalItem build() { - return new IncrementalItem(path, errors, extensions); - } + public abstract T build(); } } diff --git a/src/main/java/graphql/incremental/StreamedItem.java b/src/main/java/graphql/incremental/StreamedItem.java index b07b259f8b..269695d55d 100644 --- a/src/main/java/graphql/incremental/StreamedItem.java +++ b/src/main/java/graphql/incremental/StreamedItem.java @@ -1,6 +1,7 @@ package graphql.incremental; import graphql.ExperimentalApi; +import graphql.GraphQLError; import java.util.LinkedHashMap; import java.util.List; @@ -10,8 +11,8 @@ public class StreamedItem extends IncrementalItem { private final List items; - private StreamedItem(List items, IncrementalItem incrementalExecutionResult) { - super(incrementalExecutionResult); + private StreamedItem(List items, List path, List errors, Map extensions) { + super(path, errors, extensions); this.items = items; } @@ -35,23 +36,23 @@ public static StreamedItem.Builder newStreamedItem() { return new StreamedItem.Builder(); } - public static class Builder extends IncrementalItem.Builder { + public static class Builder extends IncrementalItem.Builder { private List items = null; - private final IncrementalItem.Builder builder = IncrementalItem.newIncrementalExecutionResult(); public Builder items(List items) { this.items = items; return this; } - public Builder from(IncrementalItem incrementalExecutionResult) { - builder.from(incrementalExecutionResult); + public Builder from(StreamedItem streamedItem) { + super.from(streamedItem); + this.items = streamedItem.items; return this; } - public IncrementalItem build() { - IncrementalItem build = builder.build(); - return new StreamedItem(items, build); + @Override + public StreamedItem build() { + return new StreamedItem(items, this.path, this.errors, this.extensions); } } } From ceac689b682eee7a212e97a14be78ade64a6820f Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Thu, 11 Jan 2024 15:08:31 +1100 Subject: [PATCH 6/9] Adjustments and plenty of Javadoc --- .../graphql/incremental/DeferPayload.java | 73 ++++++++++++++ .../graphql/incremental/DeferredItem.java | 58 ----------- .../DelayedIncrementalExecutionResult.java | 30 +++++- ...DelayedIncrementalExecutionResultImpl.java | 43 ++++---- .../IncrementalExecutionResult.java | 99 +++++++++++++++++++ .../IncrementalExecutionResultImpl.java | 34 +++++-- ...entalItem.java => IncrementalPayload.java} | 39 +++++++- .../graphql/incremental/StreamPayload.java | 73 ++++++++++++++ .../graphql/incremental/StreamedItem.java | 58 ----------- 9 files changed, 360 insertions(+), 147 deletions(-) create mode 100644 src/main/java/graphql/incremental/DeferPayload.java delete mode 100644 src/main/java/graphql/incremental/DeferredItem.java rename src/main/java/graphql/incremental/{IncrementalItem.java => IncrementalPayload.java} (73%) create mode 100644 src/main/java/graphql/incremental/StreamPayload.java delete mode 100644 src/main/java/graphql/incremental/StreamedItem.java diff --git a/src/main/java/graphql/incremental/DeferPayload.java b/src/main/java/graphql/incremental/DeferPayload.java new file mode 100644 index 0000000000..2d8d3e3594 --- /dev/null +++ b/src/main/java/graphql/incremental/DeferPayload.java @@ -0,0 +1,73 @@ +package graphql.incremental; + +import graphql.ExperimentalApi; +import graphql.GraphQLError; + +import javax.annotation.Nullable; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents a defer payload + */ +@ExperimentalApi +public class DeferPayload extends IncrementalPayload { + private final Object data; + + private DeferPayload(Object data, List path, String label, List errors, Map extensions) { + super(path, label, errors, extensions); + this.data = data; + } + + /** + * @return the resolved data + * @param the type to cast the result to + */ + @Nullable + public T getData() { + //noinspection unchecked + return (T) this.data; + } + + /** + * @return a map of this payload that strictly follows the spec + */ + @Override + public Map toSpecification() { + Map map = new LinkedHashMap<>(super.toSpecification()); + + if (data != null) { + map.put("data", data); + } + + return map; + } + + /** + * @return a {@link DeferPayload.Builder} that can be used to create an instance of {@link DeferPayload} + */ + public static DeferPayload.Builder newDeferredItem() { + return new DeferPayload.Builder(); + } + + public static class Builder extends IncrementalPayload.Builder { + private Object data = null; + + public Builder data(Object data) { + this.data = data; + return this; + } + + public Builder from(DeferPayload deferredItem) { + super.from(deferredItem); + this.data = deferredItem.data; + return this; + } + + @Override + public DeferPayload build() { + return new DeferPayload(data, this.path, this.label, this.errors, this.extensions); + } + } +} diff --git a/src/main/java/graphql/incremental/DeferredItem.java b/src/main/java/graphql/incremental/DeferredItem.java deleted file mode 100644 index b3b3f42e87..0000000000 --- a/src/main/java/graphql/incremental/DeferredItem.java +++ /dev/null @@ -1,58 +0,0 @@ -package graphql.incremental; - -import graphql.ExperimentalApi; -import graphql.GraphQLError; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -@ExperimentalApi -public class DeferredItem extends IncrementalItem { - private final Object data; - - private DeferredItem(Object data, List path, List errors, Map extensions) { - super(path, errors, extensions); - this.data = data; - } - - public T getData() { - //noinspection unchecked - return (T) this.data; - } - - @Override - public Map toSpecification() { - Map map = new LinkedHashMap<>(super.toSpecification()); - - if (data != null) { - map.put("data", data); - } - - return map; - } - - public static DeferredItem.Builder newDeferredItem() { - return new DeferredItem.Builder(); - } - - public static class Builder extends IncrementalItem.Builder { - private Object data = null; - - public Builder data(Object data) { - this.data = data; - return this; - } - - public Builder from(DeferredItem deferredItem) { - super.from(deferredItem); - this.data = deferredItem.data; - return this; - } - - @Override - public DeferredItem build() { - return new DeferredItem(data, this.path, this.errors, this.extensions); - } - } -} diff --git a/src/main/java/graphql/incremental/DelayedIncrementalExecutionResult.java b/src/main/java/graphql/incremental/DelayedIncrementalExecutionResult.java index 03650be1b2..3ba520dab7 100644 --- a/src/main/java/graphql/incremental/DelayedIncrementalExecutionResult.java +++ b/src/main/java/graphql/incremental/DelayedIncrementalExecutionResult.java @@ -2,13 +2,37 @@ import graphql.ExperimentalApi; +import javax.annotation.Nullable; import java.util.List; +import java.util.Map; +/** + * Represents a result that is delivered asynchronously, after the initial {@link IncrementalExecutionResult}. + *

+ * Multiple defer and/or stream payloads (represented by {@link IncrementalPayload}) can be part of the same + * {@link DelayedIncrementalExecutionResult} + */ @ExperimentalApi public interface DelayedIncrementalExecutionResult { - List getIncremental(); - - String getLabel(); + /** + * @return a list of defer and/or stream payloads. + */ + @Nullable + List getIncremental(); + /** + * Indicates whether the stream will continue emitting {@link DelayedIncrementalExecutionResult}s after this one. + *

+ * The value returned by this method should be "true" for all but the last response in the stream. The value of this + * entry is `false` for the last response of the stream. + * + * @return "true" if there are more responses in the stream, "false" otherwise. + */ boolean hasNext(); + + /** + * @return a map of extensions or null if there are none + */ + @Nullable + Map getExtensions(); } diff --git a/src/main/java/graphql/incremental/DelayedIncrementalExecutionResultImpl.java b/src/main/java/graphql/incremental/DelayedIncrementalExecutionResultImpl.java index 54645b24f0..5434db8798 100644 --- a/src/main/java/graphql/incremental/DelayedIncrementalExecutionResultImpl.java +++ b/src/main/java/graphql/incremental/DelayedIncrementalExecutionResultImpl.java @@ -1,60 +1,67 @@ package graphql.incremental; +import graphql.ExperimentalApi; + import java.util.Collections; import java.util.List; +import java.util.Map; +@ExperimentalApi public class DelayedIncrementalExecutionResultImpl implements DelayedIncrementalExecutionResult { - private final List incrementalItems; - private final String label; + private final List incrementalItems; private final boolean hasNext; + private final Map extensions; - private DelayedIncrementalExecutionResultImpl(List incrementalItems, String label, boolean hasNext) { - this.incrementalItems = incrementalItems; - this.label = label; - this.hasNext = hasNext; + private DelayedIncrementalExecutionResultImpl(Builder builder) { + this.incrementalItems = builder.incrementalItems; + this.hasNext = builder.hasNext; + this.extensions = builder.extensions; } @Override - public List getIncremental() { + public List getIncremental() { return this.incrementalItems; } @Override - public String getLabel() { - return this.label; + public boolean hasNext() { + return this.hasNext; } @Override - public boolean hasNext() { - return this.hasNext; + public Map getExtensions() { + return this.extensions; } + /** + * @return a {@link Builder} that can be used to create an instance of {@link DelayedIncrementalExecutionResultImpl} + */ public static Builder newIncrementalExecutionResult() { return new Builder(); } public static class Builder { private boolean hasNext = false; - private List incrementalItems = Collections.emptyList(); - private String label = null; + private List incrementalItems = Collections.emptyList(); + private Map extensions; - public DelayedIncrementalExecutionResultImpl.Builder hasNext(boolean hasNext) { + public Builder hasNext(boolean hasNext) { this.hasNext = hasNext; return this; } - public DelayedIncrementalExecutionResultImpl.Builder incrementalItems(List incrementalItems) { + public Builder incrementalItems(List incrementalItems) { this.incrementalItems = incrementalItems; return this; } - public DelayedIncrementalExecutionResultImpl.Builder label(String label) { - this.label = label; + public Builder extensions(boolean hasNext) { + this.hasNext = hasNext; return this; } public DelayedIncrementalExecutionResultImpl build() { - return new DelayedIncrementalExecutionResultImpl(this.incrementalItems, this.label, this.hasNext); + return new DelayedIncrementalExecutionResultImpl(this); } } } diff --git a/src/main/java/graphql/incremental/IncrementalExecutionResult.java b/src/main/java/graphql/incremental/IncrementalExecutionResult.java index d0178092b7..32fc2539ba 100644 --- a/src/main/java/graphql/incremental/IncrementalExecutionResult.java +++ b/src/main/java/graphql/incremental/IncrementalExecutionResult.java @@ -4,9 +4,108 @@ import graphql.ExperimentalApi; import org.reactivestreams.Publisher; +import javax.annotation.Nullable; +import java.util.List; + +/** + * A result that is part of an execution that includes incrementally delivered data (data has been deferred of streamed). + *

+ * For example, this query + *

+ * query {
+ *   person(id: "cGVvcGxlOjE=") {
+ *     ...HomeWorldFragment @defer(label: "homeWorldDefer")
+ *     name
+ *     films @stream(initialCount: 1, label: "filmsStream") {
+ *       title
+ *     }
+ *   }
+ * }
+ * fragment HomeWorldFragment on Person {
+ *   homeWorld {
+ *     name
+ *   }
+ * }
+ * 
+ * Could result on an incremental response with the following payloads (in JSON format here for simplicity). + *

+ * Response 1, the initial response does not contain any deferred or streamed results. + *

+ * {
+ *   "data": {
+ *     "person": {
+ *       "name": "Luke Skywalker",
+ *       "films": [{ "title": "A New Hope" }]
+ *     }
+ *   },
+ *   "hasNext": true
+ * }
+ * 
+ * + * Response 2, contains the defer payload and the first stream payload. + *
+ * {
+ *   "incremental": [
+ *     {
+ *       "label": "homeWorldDefer",
+ *       "path": ["person"],
+ *       "data": { "homeWorld": { "name": "Tatooine" } }
+ *     },
+ *     {
+ *       "label": "filmsStream",
+ *       "path": ["person", "films", 1],
+ *       "items": [{ "title": "The Empire Strikes Back" }]
+ *     }
+ *   ],
+ *   "hasNext": true
+ * }
+ * 
+ * + * Response 3, contains the final stream payload. Note how "hasNext" is "false", indicating this is the final response. + *
+ * {
+ *   "incremental": [
+ *     {
+ *       "label": "filmsStream",
+ *       "path": ["person", "films", 2],
+ *       "items": [{ "title": "Return of the Jedi" }]
+ *     }
+ *   ],
+ *   "hasNext": false
+ * }
+ * 
+ * + *

+ * This implementation is based on the state of Defer/Stream PR + * More specifically at the state of this + * commit + *

+ * The execution behaviour should match what we get from running Apollo Server 4.9.5 with graphql-js v17.0.0-alpha.2 + */ @ExperimentalApi public interface IncrementalExecutionResult extends ExecutionResult { + /** + * Indicates whether there are pending incremental data. + * @return "true" if there are incremental data, "false" otherwise. + */ boolean hasNext(); + /** + * Returns a list of defer and/or stream payloads that the execution engine decided (for whatever reason) to resolve at the same time as the initial payload. + *

+ * (...)this field may appear on both the initial and subsequent values. + *

+ * source + * + * @return a list of Stream and/or Defer payloads that were resolved at the same time as the initial payload. + */ + @Nullable + List getIncremental(); + + /** + * This {@link Publisher} will asynchronously emit events containing defer and/or stream payloads. + * + * @return a {@link Publisher} that clients can subscribe to receive incremental payloads. + */ Publisher getIncrementalItemPublisher(); } diff --git a/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java b/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java index c12b4d40d4..9478e72e7a 100644 --- a/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java +++ b/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java @@ -1,20 +1,24 @@ package graphql.incremental; import graphql.ExecutionResultImpl; +import graphql.ExperimentalApi; import org.reactivestreams.Publisher; +import javax.annotation.Nullable; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +@ExperimentalApi public class IncrementalExecutionResultImpl extends ExecutionResultImpl implements IncrementalExecutionResult { private final boolean hasNext; + private final List incremental; private final Publisher incrementalItemPublisher; - private IncrementalExecutionResultImpl( - Builder builder - ) { + private IncrementalExecutionResultImpl(Builder builder) { super(builder); this.hasNext = builder.hasNext; + this.incremental = builder.incremental; this.incrementalItemPublisher = builder.incrementalItemPublisher; } @@ -23,11 +27,20 @@ public boolean hasNext() { return this.hasNext; } + @Nullable + @Override + public List getIncremental() { + return this.incremental; + } + @Override public Publisher getIncrementalItemPublisher() { return incrementalItemPublisher; } + /** + * @return a {@link Builder} that can be used to create an instance of {@link IncrementalExecutionResultImpl} + */ public static Builder newIncrementalExecutionResult() { return new Builder(); } @@ -41,6 +54,7 @@ public Map toSpecification() { public static class Builder extends ExecutionResultImpl.Builder { private boolean hasNext = true; + public List incremental; private Publisher incrementalItemPublisher; public Builder hasNext(boolean hasNext) { @@ -48,15 +62,21 @@ public Builder hasNext(boolean hasNext) { return this; } + public Builder incremental(List incremental) { + this.incremental = incremental; + return this; + } + public Builder incrementalItemPublisher(Publisher incrementalItemPublisher) { this.incrementalItemPublisher = incrementalItemPublisher; return this; } -// public Builder from(ExecutionResult executionResult) { -// builder.from(executionResult); -// return this; -// } + public Builder from(IncrementalExecutionResult incrementalExecutionResult) { + super.from(incrementalExecutionResult); + this.hasNext = incrementalExecutionResult.hasNext(); + return this; + } public IncrementalExecutionResult build() { return new IncrementalExecutionResultImpl(this); diff --git a/src/main/java/graphql/incremental/IncrementalItem.java b/src/main/java/graphql/incremental/IncrementalPayload.java similarity index 73% rename from src/main/java/graphql/incremental/IncrementalItem.java rename to src/main/java/graphql/incremental/IncrementalPayload.java index b504143486..74c9980912 100644 --- a/src/main/java/graphql/incremental/IncrementalItem.java +++ b/src/main/java/graphql/incremental/IncrementalPayload.java @@ -4,6 +4,8 @@ import graphql.GraphQLError; import graphql.execution.ResultPath; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -11,26 +13,50 @@ import static java.util.stream.Collectors.toList; +/** + * Represents a payload that can be resolved after the initial response. + */ @ExperimentalApi -public abstract class IncrementalItem { +public abstract class IncrementalPayload { private final List path; + private final String label; private final List errors; private final transient Map extensions; - protected IncrementalItem(List path, List errors, Map extensions) { + protected IncrementalPayload(List path, String label, List errors, Map extensions) { this.path = path; this.errors = errors; + this.label = label; this.extensions = extensions; } + /** + * @return list of field names and indices from root to the location of the corresponding `@defer` or `@stream` directive. + */ public List getPath() { return this.path; } + /** + * @return value derived from the corresponding `@defer` or `@stream` directive. + */ + @Nullable + public String getLabel() { + return label; + } + + /** + * @return a list of field errors encountered during execution. + */ + @Nullable public List getErrors() { return this.errors; } + /** + * @return a map of extensions or null if there are none + */ + @Nullable public Map getExtensions() { return this.extensions; } @@ -53,13 +79,15 @@ protected Object errorsToSpec(List errors) { return errors.stream().map(GraphQLError::toSpecification).collect(toList()); } - protected static abstract class Builder { + protected static abstract class Builder { protected List path; + protected String label; protected List errors = new ArrayList<>(); protected Map extensions; public Builder from(T incrementalExecutionResult) { this.path = incrementalExecutionResult.getPath(); + this.label = incrementalExecutionResult.getLabel(); this.errors = new ArrayList<>(incrementalExecutionResult.getErrors()); this.extensions = incrementalExecutionResult.getExtensions(); return this; @@ -77,6 +105,11 @@ public Builder path(List path) { return this; } + public Builder label(String label) { + this.label = label; + return this; + } + public Builder errors(List errors) { this.errors = errors; return this; diff --git a/src/main/java/graphql/incremental/StreamPayload.java b/src/main/java/graphql/incremental/StreamPayload.java new file mode 100644 index 0000000000..adb1581ac9 --- /dev/null +++ b/src/main/java/graphql/incremental/StreamPayload.java @@ -0,0 +1,73 @@ +package graphql.incremental; + +import graphql.ExperimentalApi; +import graphql.GraphQLError; + +import javax.annotation.Nullable; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents a stream payload + */ +@ExperimentalApi +public class StreamPayload extends IncrementalPayload { + private final List items; + + private StreamPayload(List items, List path, String label, List errors, Map extensions) { + super(path, label, errors, extensions); + this.items = items; + } + + /** + * @return the resolved list of items + * @param the type to cast the result to + */ + @Nullable + public List getItems() { + //noinspection unchecked + return (List) this.items; + } + + /** + * @return a map of this payload that strictly follows the spec + */ + @Override + public Map toSpecification() { + Map map = new LinkedHashMap<>(super.toSpecification()); + + if (items != null) { + map.put("items", items); + } + + return map; + } + + /** + * @return a {@link Builder} that can be used to create an instance of {@link StreamPayload} + */ + public static StreamPayload.Builder newStreamedItem() { + return new StreamPayload.Builder(); + } + + public static class Builder extends IncrementalPayload.Builder { + private List items = null; + + public Builder items(List items) { + this.items = items; + return this; + } + + public Builder from(StreamPayload streamedItem) { + super.from(streamedItem); + this.items = streamedItem.items; + return this; + } + + @Override + public StreamPayload build() { + return new StreamPayload(items, this.path, this.label, this.errors, this.extensions); + } + } +} diff --git a/src/main/java/graphql/incremental/StreamedItem.java b/src/main/java/graphql/incremental/StreamedItem.java deleted file mode 100644 index 269695d55d..0000000000 --- a/src/main/java/graphql/incremental/StreamedItem.java +++ /dev/null @@ -1,58 +0,0 @@ -package graphql.incremental; - -import graphql.ExperimentalApi; -import graphql.GraphQLError; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -@ExperimentalApi -public class StreamedItem extends IncrementalItem { - private final List items; - - private StreamedItem(List items, List path, List errors, Map extensions) { - super(path, errors, extensions); - this.items = items; - } - - public List getItems() { - //noinspection unchecked - return (List) this.items; - } - - @Override - public Map toSpecification() { - Map map = new LinkedHashMap<>(super.toSpecification()); - - if (items != null) { - map.put("items", items); - } - - return map; - } - - public static StreamedItem.Builder newStreamedItem() { - return new StreamedItem.Builder(); - } - - public static class Builder extends IncrementalItem.Builder { - private List items = null; - - public Builder items(List items) { - this.items = items; - return this; - } - - public Builder from(StreamedItem streamedItem) { - super.from(streamedItem); - this.items = streamedItem.items; - return this; - } - - @Override - public StreamedItem build() { - return new StreamedItem(items, this.path, this.errors, this.extensions); - } - } -} From a8f790641026eb5be249c8b72e14b3e14a935a50 Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Thu, 11 Jan 2024 17:41:19 +1100 Subject: [PATCH 7/9] Add unit test for sanity check --- .../graphql/incremental/DeferPayload.java | 3 +- .../IncrementalExecutionResultImpl.java | 13 ++++ .../incremental/IncrementalPayload.java | 45 +++++++------- .../graphql/incremental/StreamPayload.java | 3 +- .../IncrementalExecutionResultTest.groovy | 59 +++++++++++++++++++ 5 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 src/test/groovy/graphql/incremental/IncrementalExecutionResultTest.groovy diff --git a/src/main/java/graphql/incremental/DeferPayload.java b/src/main/java/graphql/incremental/DeferPayload.java index 2d8d3e3594..2327493ef5 100644 --- a/src/main/java/graphql/incremental/DeferPayload.java +++ b/src/main/java/graphql/incremental/DeferPayload.java @@ -51,7 +51,7 @@ public static DeferPayload.Builder newDeferredItem() { return new DeferPayload.Builder(); } - public static class Builder extends IncrementalPayload.Builder { + public static class Builder extends IncrementalPayload.Builder { private Object data = null; public Builder data(Object data) { @@ -65,7 +65,6 @@ public Builder from(DeferPayload deferredItem) { return this; } - @Override public DeferPayload build() { return new DeferPayload(data, this.path, this.label, this.errors, this.extensions); } diff --git a/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java b/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java index 9478e72e7a..5b16cdaf50 100644 --- a/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java +++ b/src/main/java/graphql/incremental/IncrementalExecutionResultImpl.java @@ -6,8 +6,12 @@ import javax.annotation.Nullable; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.toList; @ExperimentalApi public class IncrementalExecutionResultImpl extends ExecutionResultImpl implements IncrementalExecutionResult { @@ -49,6 +53,15 @@ public static Builder newIncrementalExecutionResult() { public Map toSpecification() { Map map = new LinkedHashMap<>(super.toSpecification()); map.put("hasNext", hasNext); + + if (this.incremental != null) { + map.put("incremental", + this.incremental.stream() + .map(IncrementalPayload::toSpecification) + .collect(Collectors.toCollection(LinkedList::new)) + ); + } + return map; } diff --git a/src/main/java/graphql/incremental/IncrementalPayload.java b/src/main/java/graphql/incremental/IncrementalPayload.java index 74c9980912..a3ddd55826 100644 --- a/src/main/java/graphql/incremental/IncrementalPayload.java +++ b/src/main/java/graphql/incremental/IncrementalPayload.java @@ -4,7 +4,6 @@ import graphql.GraphQLError; import graphql.execution.ResultPath; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -63,15 +62,19 @@ public Map getExtensions() { protected Map toSpecification() { Map result = new LinkedHashMap<>(); + + result.put("path", path); + + if (label != null) { + result.put("label", label); + } + if (errors != null && !errors.isEmpty()) { result.put("errors", errorsToSpec(errors)); } if (extensions != null) { result.put("extensions", extensions); } - if (path != null) { - result.put("path", path); - } return result; } @@ -79,40 +82,42 @@ protected Object errorsToSpec(List errors) { return errors.stream().map(GraphQLError::toSpecification).collect(toList()); } - protected static abstract class Builder { + protected static abstract class Builder> { protected List path; protected String label; protected List errors = new ArrayList<>(); protected Map extensions; - public Builder from(T incrementalExecutionResult) { - this.path = incrementalExecutionResult.getPath(); - this.label = incrementalExecutionResult.getLabel(); - this.errors = new ArrayList<>(incrementalExecutionResult.getErrors()); - this.extensions = incrementalExecutionResult.getExtensions(); - return this; + public T from(IncrementalPayload incrementalPayload) { + this.path = incrementalPayload.getPath(); + this.label = incrementalPayload.getLabel(); + if (incrementalPayload.getErrors() != null) { + this.errors = new ArrayList<>(incrementalPayload.getErrors()); + } + this.extensions = incrementalPayload.getExtensions(); + return (T) this; } - public Builder path(ResultPath path) { + public T path(ResultPath path) { if (path != null) { this.path = path.toList(); } - return this; + return (T) this; } - public Builder path(List path) { + public T path(List path) { this.path = path; - return this; + return (T) this; } - public Builder label(String label) { + public T label(String label) { this.label = label; - return this; + return (T) this; } - public Builder errors(List errors) { + public T errors(List errors) { this.errors = errors; - return this; + return (T) this; } public Builder addErrors(List errors) { @@ -135,7 +140,5 @@ public Builder addExtension(String key, Object value) { this.extensions.put(key, value); return this; } - - public abstract T build(); } } diff --git a/src/main/java/graphql/incremental/StreamPayload.java b/src/main/java/graphql/incremental/StreamPayload.java index adb1581ac9..e8bdfcf85c 100644 --- a/src/main/java/graphql/incremental/StreamPayload.java +++ b/src/main/java/graphql/incremental/StreamPayload.java @@ -51,7 +51,7 @@ public static StreamPayload.Builder newStreamedItem() { return new StreamPayload.Builder(); } - public static class Builder extends IncrementalPayload.Builder { + public static class Builder extends IncrementalPayload.Builder { private List items = null; public Builder items(List items) { @@ -65,7 +65,6 @@ public Builder from(StreamPayload streamedItem) { return this; } - @Override public StreamPayload build() { return new StreamPayload(items, this.path, this.label, this.errors, this.extensions); } diff --git a/src/test/groovy/graphql/incremental/IncrementalExecutionResultTest.groovy b/src/test/groovy/graphql/incremental/IncrementalExecutionResultTest.groovy new file mode 100644 index 0000000000..02e8d03898 --- /dev/null +++ b/src/test/groovy/graphql/incremental/IncrementalExecutionResultTest.groovy @@ -0,0 +1,59 @@ +package graphql.incremental + +import graphql.execution.ResultPath +import spock.lang.Specification + +import static graphql.incremental.DeferPayload.newDeferredItem +import static graphql.incremental.StreamPayload.newStreamedItem + +class IncrementalExecutionResultTest extends Specification { + + def "sanity test to check builders work"() { + when: + def defer1 = newDeferredItem() + .label("homeWorldDefer") + .path(ResultPath.parse("/person")) + .data([homeWorld: "Tatooine"]) + .build() + + def stream1 = newStreamedItem() + .label("filmsStream") + .path(ResultPath.parse("/person/films[1]")) + .items([[title: "The Empire Strikes Back"]]) + .build() + + def stream2 = newStreamedItem() + .label("filmsStream") + .path(ResultPath.parse("/person/films[2]")) + .items([[title: "Return of the Jedi"]]) + .build() + + def result = IncrementalExecutionResultImpl + .newIncrementalExecutionResult() + .data([ + person: [ + name : "Luke Skywalker", + films: [ + [title: "A New Hope"] + ] + ] + ]) + .hasNext(true) + .incremental([defer1, stream1, stream2]) + .build() + + def toSpec = result.toSpecification() + + then: + toSpec == [ + data : [person: [name: "Luke Skywalker", films: [[title: "A New Hope"]]]], + hasNext : true, + incremental: [ + [path: ["person"], label: "homeWorldDefer", data: [homeWorld: "Tatooine"]], + [path: ["person", "films", 1], label: "filmsStream", items: [[title: "The Empire Strikes Back"]]], + [path: ["person", "films", 2], label: "filmsStream", items: [[title: "Return of the Jedi"]]], + ] + ] + + } +} From 6b52b0247c6167b7461a3652b1e32a2098f2d114 Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Thu, 11 Jan 2024 17:46:12 +1100 Subject: [PATCH 8/9] Fix Javadoc --- .../java/graphql/incremental/IncrementalExecutionResult.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/incremental/IncrementalExecutionResult.java b/src/main/java/graphql/incremental/IncrementalExecutionResult.java index 32fc2539ba..6794f01185 100644 --- a/src/main/java/graphql/incremental/IncrementalExecutionResult.java +++ b/src/main/java/graphql/incremental/IncrementalExecutionResult.java @@ -61,7 +61,7 @@ * } * * - * Response 3, contains the final stream payload. Note how "hasNext" is "false", indicating this is the final response. + * Response 3, contains the final stream payload. Note how "hasNext" is "false", indicating this is the final response. *
  * {
  *   "incremental": [
@@ -93,7 +93,7 @@ public interface IncrementalExecutionResult extends ExecutionResult {
     /**
      * Returns a list of defer and/or stream payloads that the execution engine decided (for whatever reason) to resolve at the same time as the initial payload.
      * 

- * (...)this field may appear on both the initial and subsequent values. + * (...)this field may appear on both the initial and subsequent values. *

* source * From d13b50999e54130361b4d0499815c33196321218 Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Fri, 12 Jan 2024 08:57:19 +1100 Subject: [PATCH 9/9] Minor adjustment in test class --- .../graphql/incremental/IncrementalExecutionResultTest.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/graphql/incremental/IncrementalExecutionResultTest.groovy b/src/test/groovy/graphql/incremental/IncrementalExecutionResultTest.groovy index 02e8d03898..d30747fccc 100644 --- a/src/test/groovy/graphql/incremental/IncrementalExecutionResultTest.groovy +++ b/src/test/groovy/graphql/incremental/IncrementalExecutionResultTest.groovy @@ -4,6 +4,7 @@ import graphql.execution.ResultPath import spock.lang.Specification import static graphql.incremental.DeferPayload.newDeferredItem +import static graphql.incremental.IncrementalExecutionResultImpl.newIncrementalExecutionResult import static graphql.incremental.StreamPayload.newStreamedItem class IncrementalExecutionResultTest extends Specification { @@ -28,8 +29,7 @@ class IncrementalExecutionResultTest extends Specification { .items([[title: "Return of the Jedi"]]) .build() - def result = IncrementalExecutionResultImpl - .newIncrementalExecutionResult() + def result = newIncrementalExecutionResult() .data([ person: [ name : "Luke Skywalker",