Skip to content

Commit bab1191

Browse files
committed
Merge remote-tracking branch 'upstream/master' into 377-field-selection-in-data-fetchers
# Conflicts: # src/main/java/graphql/execution/batched/BatchedExecutionStrategy.java
2 parents 80b4fe9 + bad750c commit bab1191

25 files changed

Lines changed: 1186 additions & 304 deletions

README.md

Lines changed: 4 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -518,117 +518,6 @@ public Object executeOperation(@RequestBody Map body) {
518518
}
519519
```
520520
521-
### Schema IDL support
522-
523-
This library allows for "schema driven" development of graphql applications.
524-
525-
It allows you to compile a set of schema files into a executable `GraphqlSchema`.
526-
527-
528-
So given a graphql schema input file like :
529-
530-
```graphql
531-
532-
schema {
533-
query: QueryType
534-
}
535-
536-
type QueryType {
537-
hero(episode: Episode): Character
538-
human(id : String) : Human
539-
droid(id: ID!): Droid
540-
}
541-
542-
543-
enum Episode {
544-
NEWHOPE
545-
EMPIRE
546-
JEDI
547-
}
548-
549-
interface Character {
550-
id: ID!
551-
name: String!
552-
friends: [Character]
553-
appearsIn: [Episode]!
554-
}
555-
556-
type Human implements Character {
557-
id: ID!
558-
name: String!
559-
friends: [Character]
560-
appearsIn: [Episode]!
561-
homePlanet: String
562-
}
563-
564-
type Droid implements Character {
565-
id: ID!
566-
name: String!
567-
friends: [Character]
568-
appearsIn: [Episode]!
569-
primaryFunction: String
570-
}
571-
572-
573-
```
574-
575-
You could compile and generate an executable schema via
576-
577-
```java
578-
SchemaCompiler schemaCompiler = new SchemaCompiler();
579-
SchemaGenerator schemaGenerator = new SchemaGenerator();
580-
581-
File schemaFile = loadSchema("starWarsSchema.graphqls");
582-
583-
TypeDefinitionRegistry typeRegistry = schemaCompiler.compile(schemaFile);
584-
RuntimeWiring wiring = buildRuntimeWiring();
585-
GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, wiring);
586-
587-
```
588-
589-
The static schema definition file has the field and type definitions but you need a runtime wiring to make
590-
it a truly executable schema.
591-
592-
The runtime wiring contains `DataFetchers`, `TypeResolvers` and custom `Scalars` that are needed to make a fully
593-
executable schema.
594-
595-
You wire this together using this builder pattern
596-
597-
```java
598-
599-
RuntimeWiring buildRuntimeWiring() {
600-
return RuntimeWiring.newRuntimeWiring()
601-
.scalar(CustomScalar)
602-
// this uses builder function lambda syntax
603-
.type(typeWiring -> typeWiring.typeName("QueryType")
604-
.dataFetcher("hero", new StaticDataFetcher(StarWarsData.getArtoo()))
605-
.dataFetcher("human", StarWarsData.getHumanDataFetcher())
606-
.dataFetcher("droid", StarWarsData.getDroidDataFetcher())
607-
)
608-
.type(typeWiring -> typeWiring.typeName("Human")
609-
.dataFetcher("friends", StarWarsData.getFriendsDataFetcher())
610-
)
611-
// you can use builder syntax if you don't like the lambda syntax
612-
.type(typeWiring -> typeWiring.typeName("Droid")
613-
.dataFetcher("friends", StarWarsData.getFriendsDataFetcher())
614-
)
615-
// or full builder syntax if that takes your fancy
616-
.type(
617-
newTypeWiring("Character")
618-
.typeResolver(StarWarsData.getCharacterTypeResolver())
619-
.build()
620-
)
621-
.build();
622-
}
623-
624-
625-
```
626-
627-
NOTE: IDL is not currently part of the [formal graphql spec](https://facebook.github.io/graphql/#sec-Appendix-Grammar-Summary.Query-Document).
628-
The implementation in this library is based off the [reference implementation](https://github.com/graphql/graphql-js). However plenty of
629-
code out there is based on this IDL syntax and hence you can be fairly confident that you are building on solid technology ground.
630-
631-
632521
#### Contributions
633522
634523
Every contribution to make this project better is welcome: Thank you!
@@ -737,11 +626,14 @@ Installing in the local Maven repository:
737626

738627
### Details
739628

740-
The implementation is in Java 6, but the tests are in Groovy and [Spock](https://github.com/spockframework/spock).
629+
The implementation is in Java 8, but the tests are in Groovy and [Spock](https://github.com/spockframework/spock).
741630

742631
The query parsing is done with [ANTLR](http://www.antlr.org). The grammar is [here](src/main/antlr/Graphql.g4).
743632

744633
The only runtime dependencies are ANTLR and Slf4J.
634+
635+
This readme shows information on the latest released version of the library. The 'master' branch however contains the
636+
code for the upcoming version. The readme for that upcoming version can be found [here](src/test/groovy/readme/README.next.md)
745637

746638
### Acknowledgment
747639

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package graphql;
2+
3+
import graphql.language.Field;
4+
import graphql.schema.GraphQLSchema;
5+
import graphql.schema.GraphQLType;
6+
7+
import java.util.Map;
8+
9+
/**
10+
* See {@link graphql.schema.TypeResolver#getType(TypeResolutionEnvironment)} for how this is used
11+
*/
12+
public class TypeResolutionEnvironment {
13+
14+
private final Object object;
15+
private final Map<String, Object> arguments;
16+
private final Field field;
17+
private final GraphQLType fieldType;
18+
private final GraphQLSchema schema;
19+
20+
public TypeResolutionEnvironment(Object object, Map<String, Object> arguments, Field field, GraphQLType fieldType, GraphQLSchema schema) {
21+
this.object = object;
22+
this.arguments = arguments;
23+
this.field = field;
24+
this.fieldType = fieldType;
25+
this.schema = schema;
26+
}
27+
28+
public Object getObject() {
29+
return object;
30+
}
31+
32+
public Map<String, Object> getArguments() {
33+
return arguments;
34+
}
35+
36+
public Field getField() {
37+
return field;
38+
}
39+
40+
public GraphQLType getFieldType() {
41+
return fieldType;
42+
}
43+
44+
public GraphQLSchema getSchema() {
45+
return schema;
46+
}
47+
}

src/main/java/graphql/execution/ExecutionParameters.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
public class ExecutionParameters {
1414
private final TypeInfo typeInfo;
1515
private final Object source;
16+
private final Map<String, Object> arguments;
1617
private final Map<String, List<Field>> fields;
1718

18-
private ExecutionParameters(TypeInfo typeInfo, Object source, Map<String, List<Field>> fields) {
19+
private ExecutionParameters(TypeInfo typeInfo, Object source, Map<String, List<Field>> fields, Map<String, Object> arguments) {
1920
this.typeInfo = assertNotNull(typeInfo, "");
2021
this.fields = assertNotNull(fields, "");
2122
this.source = source;
23+
this.arguments = arguments;
2224
}
2325

2426
public TypeInfo typeInfo() {
@@ -33,6 +35,10 @@ public Map<String, List<Field>> fields() {
3335
return fields;
3436
}
3537

38+
public Map<String, Object> arguments() {
39+
return arguments;
40+
}
41+
3642
public static Builder newParameters() {
3743
return new Builder();
3844
}
@@ -47,6 +53,7 @@ public static class Builder {
4753
TypeInfo typeInfo;
4854
Object source;
4955
Map<String, List<Field>> fields;
56+
Map<String, Object> arguments;
5057

5158
public Builder typeInfo(TypeInfo type) {
5259
this.typeInfo = type;
@@ -68,8 +75,13 @@ public Builder source(Object source) {
6875
return this;
6976
}
7077

78+
public Builder arguments(Map<String, Object> arguments) {
79+
this.arguments = arguments;
80+
return this;
81+
}
82+
7183
public ExecutionParameters build() {
72-
return new ExecutionParameters(typeInfo, source, fields);
84+
return new ExecutionParameters(typeInfo, source, fields, arguments);
7385
}
7486
}
7587
}

src/main/java/graphql/execution/ExecutionStrategy.java

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import graphql.ExecutionResult;
55
import graphql.ExecutionResultImpl;
66
import graphql.GraphQLException;
7+
import graphql.TypeResolutionEnvironment;
78
import graphql.execution.instrumentation.Instrumentation;
89
import graphql.execution.instrumentation.InstrumentationContext;
910
import graphql.execution.instrumentation.parameters.FieldFetchParameters;
@@ -105,6 +106,7 @@ protected ExecutionResult resolveField(ExecutionContext executionContext, Execut
105106
ExecutionParameters newParameters = ExecutionParameters.newParameters()
106107
.typeInfo(fieldType)
107108
.fields(parameters.fields())
109+
.arguments(argumentValues)
108110
.source(resolvedValue).build();
109111

110112
ExecutionResult result = completeValue(executionContext, newParameters, fields);
@@ -137,9 +139,22 @@ protected ExecutionResult completeValue(ExecutionContext executionContext, Execu
137139

138140
GraphQLObjectType resolvedType;
139141
if (fieldType instanceof GraphQLInterfaceType) {
140-
resolvedType = resolveType((GraphQLInterfaceType) fieldType, result);
142+
TypeResolutionParameters resolutionParams = TypeResolutionParameters.newParameters()
143+
.graphQLInterfaceType((GraphQLInterfaceType) fieldType)
144+
.field(fields.get(0))
145+
.value(parameters.source())
146+
.argumentValues(parameters.arguments())
147+
.schema(executionContext.getGraphQLSchema()).build();
148+
resolvedType = resolveTypeForInterface(resolutionParams);
149+
141150
} else if (fieldType instanceof GraphQLUnionType) {
142-
resolvedType = resolveType((GraphQLUnionType) fieldType, result);
151+
TypeResolutionParameters resolutionParams = TypeResolutionParameters.newParameters()
152+
.graphQLUnionType((GraphQLUnionType) fieldType)
153+
.field(fields.get(0))
154+
.value(parameters.source())
155+
.argumentValues(parameters.arguments())
156+
.schema(executionContext.getGraphQLSchema()).build();
157+
resolvedType = resolveTypeForUnion(resolutionParams);
143158
} else {
144159
resolvedType = (GraphQLObjectType) fieldType;
145160
}
@@ -169,18 +184,20 @@ private Iterable<Object> toIterable(Object result) {
169184
return (Iterable<Object>) result;
170185
}
171186

172-
protected GraphQLObjectType resolveType(GraphQLInterfaceType graphQLInterfaceType, Object value) {
173-
GraphQLObjectType result = graphQLInterfaceType.getTypeResolver().getType(value);
187+
protected GraphQLObjectType resolveTypeForInterface(TypeResolutionParameters params) {
188+
TypeResolutionEnvironment env = new TypeResolutionEnvironment(params.getValue(), params.getArgumentValues(), params.getField(), params.getGraphQLInterfaceType(), params.getSchema());
189+
GraphQLObjectType result = params.getGraphQLInterfaceType().getTypeResolver().getType(env);
174190
if (result == null) {
175-
throw new GraphQLException("could not determine type");
191+
throw new GraphQLException("Could not determine the exact type of " + params.getGraphQLInterfaceType().getName());
176192
}
177193
return result;
178194
}
179195

180-
protected GraphQLObjectType resolveType(GraphQLUnionType graphQLUnionType, Object value) {
181-
GraphQLObjectType result = graphQLUnionType.getTypeResolver().getType(value);
196+
protected GraphQLObjectType resolveTypeForUnion(TypeResolutionParameters params) {
197+
TypeResolutionEnvironment env = new TypeResolutionEnvironment(params.getValue(), params.getArgumentValues(), params.getField(), params.getGraphQLUnionType(), params.getSchema());
198+
GraphQLObjectType result = params.getGraphQLUnionType().getTypeResolver().getType(env);
182199
if (result == null) {
183-
throw new GraphQLException("could not determine type");
200+
throw new GraphQLException("Could not determine the exact type of " + params.getGraphQLUnionType().getName());
184201
}
185202
return result;
186203
}
@@ -230,10 +247,8 @@ protected GraphQLFieldDefinition getFieldDef(GraphQLSchema schema, GraphQLObject
230247

231248
GraphQLFieldDefinition fieldDefinition = parentType.getFieldDefinition(field.getName());
232249
if (fieldDefinition == null) {
233-
throw new GraphQLException("unknown field " + field.getName());
250+
throw new GraphQLException("Unknown field " + field.getName());
234251
}
235252
return fieldDefinition;
236253
}
237-
238-
239254
}

0 commit comments

Comments
 (0)