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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 96 additions & 1 deletion src/main/java/graphql/ExecutionResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
* This simple value class represents the result of performing a graphql query.
Expand Down Expand Up @@ -34,7 +35,7 @@ public interface ExecutionResult {
* See : <a href="https://graphql.github.io/graphql-spec/June2018/#sec-Data">https://graphql.github.io/graphql-spec/June2018/#sec-Data</a>
*
* @return <code>true</code> if the entry "data" should be present in the result
* <code>false</code> otherwise
* <code>false</code> otherwise
*/
boolean isDataPresent();

Expand All @@ -54,4 +55,98 @@ public interface ExecutionResult {
* @return a map of the result that strictly follows the spec
*/
Map<String, Object> toSpecification();


/**
* This helps you transform the current {@link ExecutionResult} object into another one by starting a builder with all
* the current values and allows you to transform it how you want.
*
* @param builderConsumer the consumer code that will be given a builder to transform
*
* @return a new {@link ExecutionResult} object based on calling build on that builder
*/
default ExecutionResult transform(Consumer<Builder<?>> builderConsumer) {
Builder<?> builder = newExecutionResult().from(this);
builderConsumer.accept(builder);
return builder.build();
}

/**
* @return a builder that allows you to build a new execution result
*/
static Builder<?> newExecutionResult() {
return ExecutionResultImpl.newExecutionResult();
}

interface Builder<B extends Builder<B>> {

/**
* Sets values into the builder based on a previous {@link ExecutionResult}
*
* @param executionResult the previous {@link ExecutionResult}
*
* @return the builder
*/
B from(ExecutionResult executionResult);

/**
* Sets new data into the builder
*
* @param data the data to use
*
* @return the builder
*/
B data(Object data);

/**
* Sets error list as the errors for this builder
*
* @param errors the errors to use
*
* @return the builder
*/
B errors(List<GraphQLError> errors);

/**
* Adds the error list to any existing the errors for this builder
*
* @param errors the errors to add
*
* @return the builder
*/
B addErrors(List<GraphQLError> errors);

/**
* Adds the error to any existing the errors for this builder
*
* @param error the error to add
*
* @return the builder
*/
B addError(GraphQLError error);

/**
* Sets the extension map for this builder
*
* @param extensions the extensions to use
*
* @return the builder
*/
B extensions(Map<Object, Object> extensions);

/**
* Adds a new entry into the extensions map for this builder
*
* @param key the key of the extension entry
* @param value the value of the extension entry
*
* @return the builder
*/
B addExtension(String key, Object value);

/**
* @return a newly built {@link ExecutionResult}
*/
ExecutionResult build();
}
}
18 changes: 10 additions & 8 deletions src/main/java/graphql/ExecutionResultImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,22 +104,17 @@ public String toString() {
'}';
}

public ExecutionResultImpl transform(Consumer<Builder> builderConsumer) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Now in as a default method in the interface

Builder builder = newExecutionResult().from(this);
builderConsumer.accept(builder);
return builder.build();
}

public static Builder newExecutionResult() {
return new Builder();
}

public static class Builder {
public static class Builder implements ExecutionResult.Builder<Builder> {
private boolean dataPresent;
private Object data;
private List<GraphQLError> errors = new ArrayList<>();
private Map<Object, Object> extensions;

@Override
public Builder from(ExecutionResult executionResult) {
dataPresent = executionResult.isDataPresent();
data = executionResult.getData();
Expand All @@ -128,39 +123,46 @@ public Builder from(ExecutionResult executionResult) {
return this;
}

@Override
public Builder data(Object data) {
dataPresent = true;
this.data = data;
return this;
}

@Override
public Builder errors(List<GraphQLError> errors) {
this.errors = errors;
return this;
}

@Override
public Builder addErrors(List<GraphQLError> errors) {
this.errors.addAll(errors);
return this;
}

@Override
public Builder addError(GraphQLError error) {
this.errors.add(error);
return this;
}

@Override
public Builder extensions(Map<Object, Object> extensions) {
this.extensions = extensions;
return this;
}

@Override
public Builder addExtension(String key, Object value) {
this.extensions = (this.extensions == null ? new LinkedHashMap<>() : this.extensions);
this.extensions.put(key, value);
return this;
}

public ExecutionResultImpl build() {
@Override
public ExecutionResult build() {
return new ExecutionResultImpl(dataPresent, data, errors, extensions);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/graphql/cachecontrol/CacheControl.java
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ public static CacheControl newCacheControl() {
@Deprecated
@DeprecatedAt("2022-07-26")
public ExecutionResult addTo(ExecutionResult executionResult) {
return ExecutionResultImpl.newExecutionResult()
return ExecutionResult.newExecutionResult()
.from(executionResult)
.addExtension(CACHE_CONTROL_EXTENSION_KEY, hintsToCacheControlProperties())
.build();
Expand Down
31 changes: 31 additions & 0 deletions src/test/groovy/graphql/ExecutionResultTest.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package graphql

import graphql.language.SourceLocation
import spock.lang.Specification

/**
* Most of the tests are actually in ExecutionResultImplTest since this is the actual impl
*/
class ExecutionResultTest extends Specification {

def error1 = new InvalidSyntaxError(new SourceLocation(966, 964), "Yowza")

def "can use builder to build it"() {
when:
ExecutionResult er = ExecutionResult.newExecutionResult().data([a: "b"]).addError(error1).addExtension("x", "y").build()
then:
er.data == [a: "b"]
er.errors == [error1]
er.extensions == [x: "y"]
}

def "can transform"() {
when:
ExecutionResult er = ExecutionResult.newExecutionResult().data([a: "b"]).addError(error1).addExtension("x", "y").build()
er = er.transform({ bld -> bld.addExtension("foo", "bar") })
then:
er.data == [a: "b"]
er.errors == [error1]
er.extensions == [x: "y", foo: "bar"]
}
}
6 changes: 3 additions & 3 deletions src/test/groovy/graphql/cachecontrol/CacheControlTest.groovy
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package graphql.cachecontrol

import graphql.ExecutionInput
import graphql.ExecutionResultImpl
import graphql.ExecutionResult
import graphql.GraphQLContext
import graphql.TestUtil
import graphql.execution.CoercedVariables
Expand Down Expand Up @@ -29,7 +29,7 @@ class CacheControlTest extends Specification {
cc.hint(ResultPath.parse("/hint/33/private"), 33, CacheControl.Scope.PRIVATE)
cc.hint(ResultPath.parse("/hint/private"), CacheControl.Scope.PRIVATE)

def er = ExecutionResultImpl.newExecutionResult().data("data").build()
def er = ExecutionResult.newExecutionResult().data("data").build()

when:
def newER = cc.addTo(er)
Expand All @@ -56,7 +56,7 @@ class CacheControlTest extends Specification {

def startingExtensions = ["someExistingExt": "data"]

def er = ExecutionResultImpl.newExecutionResult().data("data").extensions(startingExtensions).build()
def er = ExecutionResult.newExecutionResult().data("data").extensions(startingExtensions).build()

when:
def newER = cc.addTo(er)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package graphql.introspection
import com.fasterxml.jackson.databind.ObjectMapper
import graphql.Assert
import graphql.ExecutionInput
import graphql.ExecutionResultImpl
import graphql.ExecutionResult
import graphql.GraphQL
import graphql.TestUtil
import graphql.language.Document
Expand Down Expand Up @@ -700,7 +700,7 @@ input InputType {

def "create schema fail"() {
given:
def failResult = ExecutionResultImpl.newExecutionResult().build()
def failResult = ExecutionResult.newExecutionResult().build()

when:
Document document = introspectionResultToSchema.createSchemaDefinition(failResult)
Expand Down