Skip to content

Commit 5d7d265

Browse files
authored
graphql.execute can accept a builder (graphql-java#551)
* This allows the standard pattern of allowing a builder to be passed to the `graphql.execute()` method * Fixed in async code call * Updated to have async versions of the builder methods removed some Idea warnings
1 parent 0fdbf32 commit 5d7d265

2 files changed

Lines changed: 173 additions & 23 deletions

File tree

src/main/java/graphql/GraphQL.java

Lines changed: 103 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.List;
2828
import java.util.Map;
2929
import java.util.concurrent.CompletableFuture;
30+
import java.util.function.UnaryOperator;
3031

3132
import static graphql.Assert.assertNotNull;
3233

@@ -50,6 +51,7 @@ public class GraphQL {
5051
* A GraphQL object ready to execute queries
5152
*
5253
* @param graphQLSchema the schema to use
54+
*
5355
* @deprecated use the {@link #newGraphQL(GraphQLSchema)} builder instead. This will be removed in a future version.
5456
*/
5557
@Internal
@@ -63,6 +65,7 @@ public GraphQL(GraphQLSchema graphQLSchema) {
6365
*
6466
* @param graphQLSchema the schema to use
6567
* @param queryStrategy the query execution strategy to use
68+
*
6669
* @deprecated use the {@link #newGraphQL(GraphQLSchema)} builder instead. This will be removed in a future version.
6770
*/
6871
@Internal
@@ -77,6 +80,7 @@ public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy) {
7780
* @param graphQLSchema the schema to use
7881
* @param queryStrategy the query execution strategy to use
7982
* @param mutationStrategy the mutation execution strategy to use
83+
*
8084
* @deprecated use the {@link #newGraphQL(GraphQLSchema)} builder instead. This will be removed in a future version.
8185
*/
8286
@Internal
@@ -91,6 +95,7 @@ public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, Exe
9195
* @param queryStrategy the query execution strategy to use
9296
* @param mutationStrategy the mutation execution strategy to use
9397
* @param subscriptionStrategy the subscription execution strategy to use
98+
*
9499
* @deprecated use the {@link #newGraphQL(GraphQLSchema)} builder instead. This will be removed in a future version.
95100
*/
96101
@Internal
@@ -112,6 +117,7 @@ private GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, Ex
112117
* Helps you build a GraphQL object ready to execute queries
113118
*
114119
* @param graphQLSchema the schema to use
120+
*
115121
* @return a builder of GraphQL objects
116122
*/
117123
public static Builder newGraphQL(GraphQLSchema graphQLSchema) {
@@ -178,11 +184,12 @@ public GraphQL build() {
178184
}
179185

180186
/**
187+
* Executes the specified graphql query/mutation/subscription
188+
*
181189
* @param query the query/mutation/subscription
182-
* @return result including errors
183-
* @deprecated Use {@link #execute(ExecutionInput)}
190+
*
191+
* @return an {@link ExecutionResult} which can include errors
184192
*/
185-
@Deprecated
186193
public ExecutionResult execute(String query) {
187194
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
188195
.query(query)
@@ -195,7 +202,9 @@ public ExecutionResult execute(String query) {
195202
*
196203
* @param query the query/mutation/subscription
197204
* @param context custom object provided to each {@link graphql.schema.DataFetcher}
198-
* @return result including errors
205+
*
206+
* @return an {@link ExecutionResult} which can include errors
207+
*
199208
* @deprecated Use {@link #execute(ExecutionInput)}
200209
*/
201210
@Deprecated
@@ -214,7 +223,9 @@ public ExecutionResult execute(String query, Object context) {
214223
* @param query the query/mutation/subscription
215224
* @param operationName the name of the operation to execute
216225
* @param context custom object provided to each {@link graphql.schema.DataFetcher}
217-
* @return result including errors
226+
*
227+
* @return an {@link ExecutionResult} which can include errors
228+
*
218229
* @deprecated Use {@link #execute(ExecutionInput)}
219230
*/
220231
@Deprecated
@@ -234,7 +245,9 @@ public ExecutionResult execute(String query, String operationName, Object contex
234245
* @param query the query/mutation/subscription
235246
* @param context custom object provided to each {@link graphql.schema.DataFetcher}
236247
* @param variables variable values uses as argument
237-
* @return result including errors
248+
*
249+
* @return an {@link ExecutionResult} which can include errors
250+
*
238251
* @deprecated Use {@link #execute(ExecutionInput)}
239252
*/
240253
@Deprecated
@@ -255,7 +268,9 @@ public ExecutionResult execute(String query, Object context, Map<String, Object>
255268
* @param operationName name of the operation to execute
256269
* @param context custom object provided to each {@link graphql.schema.DataFetcher}
257270
* @param variables variable values uses as argument
258-
* @return result including errors
271+
*
272+
* @return an {@link ExecutionResult} which can include errors
273+
*
259274
* @deprecated Use {@link #execute(ExecutionInput)}
260275
*/
261276
@Deprecated
@@ -271,11 +286,91 @@ public ExecutionResult execute(String query, String operationName, Object contex
271286
}
272287

273288
/**
289+
* Executes the graphql query using the provided input object builder
290+
*
291+
* @param executionInputBuilder {@link ExecutionInput.Builder}
292+
*
293+
* @return an {@link ExecutionResult} which can include errors
294+
*/
295+
public ExecutionResult execute(ExecutionInput.Builder executionInputBuilder) {
296+
return execute(executionInputBuilder.build());
297+
}
298+
299+
/**
300+
* Executes the graphql query using calling the builder function and giving it a new builder.
301+
* <p>
302+
* This allows a lambda style like :
303+
*
304+
* <pre>
305+
* {@code
306+
* ExecutionResult result = graphql.execute(input -> input.query("{hello}").root(startingObj).context(contextObj));
307+
* }
308+
* </pre>
309+
*
310+
* @param builderFunction a function that is given a {@link ExecutionInput.Builder}
311+
*
312+
* @return an {@link ExecutionResult} which can include errors
313+
*/
314+
public ExecutionResult execute(UnaryOperator<ExecutionInput.Builder> builderFunction) {
315+
return execute(builderFunction.apply(ExecutionInput.newExecutionInput()).build());
316+
}
317+
318+
/**
319+
* Executes the graphql query using the provided input object
320+
*
321+
* @param executionInput {@link ExecutionInput}
322+
*
323+
* @return an {@link ExecutionResult} which can include errors
324+
*/
325+
public ExecutionResult execute(ExecutionInput executionInput) {
326+
return executeAsync(executionInput).join();
327+
}
328+
329+
/**
330+
* Executes the graphql query using the provided input object builder
331+
*
332+
* This will return a promise (aka {@link CompletableFuture}) to provide a {@link ExecutionResult}
333+
* which is the result of executing the provided query.
334+
*
335+
* @param executionInputBuilder {@link ExecutionInput.Builder}
336+
*
337+
* @return a promise to an {@link ExecutionResult} which can include errors
338+
*/
339+
public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput.Builder executionInputBuilder) {
340+
return executeAsync(executionInputBuilder.build());
341+
}
342+
343+
/**
344+
* Executes the graphql query using the provided input object builder
345+
*
346+
* This will return a promise (aka {@link CompletableFuture}) to provide a {@link ExecutionResult}
347+
* which is the result of executing the provided query.
348+
* <p>
349+
* This allows a lambda style like :
350+
*
351+
* <pre>
352+
* {@code
353+
* ExecutionResult result = graphql.execute(input -> input.query("{hello}").root(startingObj).context(contextObj));
354+
* }
355+
* </pre>
356+
*
357+
* @param builderFunction a function that is given a {@link ExecutionInput.Builder}
358+
*
359+
* @return a promise to an {@link ExecutionResult} which can include errors
360+
*/
361+
public CompletableFuture<ExecutionResult> executeAsync(UnaryOperator<ExecutionInput.Builder> builderFunction) {
362+
return executeAsync(builderFunction.apply(ExecutionInput.newExecutionInput()).build());
363+
}
364+
365+
/**
366+
* Executes the graphql query using the provided input object
367+
*
274368
* This will return a promise (aka {@link CompletableFuture}) to provide a {@link ExecutionResult}
275369
* which is the result of executing the provided query.
276370
*
277371
* @param executionInput {@link ExecutionInput}
278-
* @return a promise to an execution result
372+
*
373+
* @return a promise to an {@link ExecutionResult} which can include errors
279374
*/
280375
public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput executionInput) {
281376
log.debug("Executing request. operation name: {}. query: {}. variables {} ", executionInput.getOperationName(), executionInput.getQuery(), executionInput.getVariables());
@@ -286,13 +381,6 @@ public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput executionI
286381
return executionResult;
287382
}
288383

289-
/**
290-
* @param executionInput {@link ExecutionInput}
291-
* @return result including errors
292-
*/
293-
public ExecutionResult execute(ExecutionInput executionInput) {
294-
return executeAsync(executionInput).join();
295-
}
296384

297385
private CompletableFuture<ExecutionResult> parseValidateAndExecute(ExecutionInput executionInput) {
298386
PreparsedDocumentEntry preparsedDoc = preparsedDocumentProvider.get(executionInput.getQuery(), query -> parseAndValidate(executionInput));

src/test/groovy/graphql/GraphQLTest.groovy

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import graphql.schema.StaticDataFetcher
1313
import graphql.validation.ValidationErrorType
1414
import spock.lang.Specification
1515

16+
import java.util.function.UnaryOperator
17+
18+
import static graphql.ExecutionInput.Builder
19+
import static graphql.ExecutionInput.newExecutionInput
1620
import static graphql.Scalars.GraphQLInt
1721
import static graphql.Scalars.GraphQLString
1822
import static graphql.schema.GraphQLArgument.newArgument
@@ -24,9 +28,7 @@ import static graphql.schema.GraphQLSchema.newSchema
2428

2529
class GraphQLTest extends Specification {
2630

27-
28-
def "simple query"() {
29-
given:
31+
GraphQLSchema simpleSchema() {
3032
GraphQLFieldDefinition.Builder fieldDefinition = newFieldDefinition()
3133
.name("hello")
3234
.type(GraphQLString)
@@ -37,6 +39,12 @@ class GraphQLTest extends Specification {
3739
.field(fieldDefinition)
3840
.build()
3941
).build()
42+
schema
43+
}
44+
45+
def "simple query"() {
46+
given:
47+
GraphQLSchema schema = simpleSchema()
4048

4149
when:
4250
def result = GraphQL.newGraphQL(schema).build().execute('{ hello }').data
@@ -199,7 +207,8 @@ class GraphQLTest extends Specification {
199207
def expected = [field2: 'value2']
200208

201209
when:
202-
def result = GraphQL.newGraphQL(schema).build().execute(query, 'Query2', null, [:])
210+
def executionInput = newExecutionInput().query(query).operationName('Query2').context(null).variables([:])
211+
def result = GraphQL.newGraphQL(schema).build().execute(executionInput)
203212

204213
then:
205214
result.data == expected
@@ -246,7 +255,6 @@ class GraphQLTest extends Specification {
246255
}
247256

248257

249-
250258
def "query with int literal too large"() {
251259
given:
252260
GraphQLSchema schema = newSchema().query(
@@ -269,6 +277,7 @@ class GraphQLTest extends Specification {
269277
result.errors[0].description.contains("has wrong type")
270278
}
271279

280+
@SuppressWarnings("GroovyAssignabilityCheck")
272281
def "query with missing argument results in arguments map with value null"() {
273282
given:
274283
def dataFetcher = Mock(DataFetcher)
@@ -295,6 +304,7 @@ class GraphQLTest extends Specification {
295304
}
296305
}
297306

307+
@SuppressWarnings("GroovyAssignabilityCheck")
298308
def "query with missing key in an input object result in a empty map"() {
299309
given:
300310
def dataFetcher = Mock(DataFetcher)
@@ -336,6 +346,7 @@ class GraphQLTest extends Specification {
336346
result.errors[0].errorType == ErrorType.InvalidSyntax
337347
}
338348

349+
339350
def "wrong argument type: array of enum instead of enum"() {
340351
given:
341352
GraphQLEnumType enumType = GraphQLEnumType.newEnum().name("EnumType").value("Val1").value("Val2").build()
@@ -345,19 +356,70 @@ class GraphQLTest extends Specification {
345356
.field(newFieldDefinition()
346357
.name("query")
347358
.argument(newArgument().name("fooParam").type(enumType))
348-
.type(Scalars.GraphQLInt))
359+
.type(GraphQLInt))
349360
.build()
350361

351362
GraphQLSchema schema = newSchema()
352363
.query(queryType)
353364
.build()
354365
when:
355-
final GraphQL graphQL = GraphQL.newGraphQL(schema).build();
356-
final ExecutionResult result = graphQL.execute("{query (fooParam: [Val1,Val2])}");
366+
final GraphQL graphQL = GraphQL.newGraphQL(schema).build()
367+
final ExecutionResult result = graphQL.execute("{query (fooParam: [Val1,Val2])}")
357368
then:
358369
result.errors.size() == 1
359370
result.errors[0].errorType == ErrorType.ValidationError
360371

361372
}
362373

374+
375+
def "execution input passing builder"() {
376+
given:
377+
GraphQLSchema schema = simpleSchema()
378+
379+
when:
380+
def builder = newExecutionInput().query('{ hello }')
381+
def result = GraphQL.newGraphQL(schema).build().execute(builder).data
382+
383+
then:
384+
result == [hello: 'world']
385+
}
386+
387+
def "execution input using builder function"() {
388+
given:
389+
GraphQLSchema schema = simpleSchema()
390+
391+
when:
392+
393+
def builderFunction = { it.query('{hello}') } as UnaryOperator<Builder>
394+
def result = GraphQL.newGraphQL(schema).build().execute(builderFunction).data
395+
396+
then:
397+
result == [hello: 'world']
398+
}
399+
400+
def "execution input passing builder to async"() {
401+
given:
402+
GraphQLSchema schema = simpleSchema()
403+
404+
when:
405+
def builder = newExecutionInput().query('{ hello }')
406+
def result = GraphQL.newGraphQL(schema).build().executeAsync(builder).join().data
407+
408+
then:
409+
result == [hello: 'world']
410+
}
411+
412+
def "execution input using builder function to async"() {
413+
given:
414+
GraphQLSchema schema = simpleSchema()
415+
416+
when:
417+
418+
def builderFunction = { it.query('{hello}') } as UnaryOperator<Builder>
419+
def result = GraphQL.newGraphQL(schema).build().executeAsync(builderFunction).join().data
420+
421+
then:
422+
result == [hello: 'world']
423+
}
424+
363425
}

0 commit comments

Comments
 (0)