Skip to content

Commit f9e9e13

Browse files
bbakermanandimarek
authored andcommitted
Fixes the copying of schemas and also the fact you cant set field visibility on IDL schema creation runtime wiring (graphql-java#702)
(cherry picked from commit 12120e9)
1 parent 2681711 commit f9e9e13

File tree

5 files changed

+141
-15
lines changed

5 files changed

+141
-15
lines changed

src/main/java/graphql/schema/GraphQLSchema.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,18 @@ public static Builder newSchema(GraphQLSchema existingSchema) {
125125
.query(existingSchema.getQueryType())
126126
.mutation(existingSchema.getMutationType())
127127
.subscription(existingSchema.getSubscriptionType())
128-
.fieldVisibility(existingSchema.getFieldVisibility());
128+
.fieldVisibility(existingSchema.getFieldVisibility())
129+
.additionalDirectives(existingSchema.directives)
130+
.additionalTypes(existingSchema.additionalTypes);
129131
}
130132

131133
public static class Builder {
132134
private GraphQLObjectType queryType;
133135
private GraphQLObjectType mutationType;
134136
private GraphQLObjectType subscriptionType;
135137
private GraphqlFieldVisibility fieldVisibility = DEFAULT_FIELD_VISIBILITY;
138+
private Set<GraphQLType> additionalTypes = Collections.emptySet();
139+
private Set<GraphQLDirective> additionalDirectives = Collections.emptySet();
136140

137141
public Builder query(GraphQLObjectType.Builder builder) {
138142
return query(builder.build());
@@ -166,8 +170,18 @@ public Builder fieldVisibility(GraphqlFieldVisibility fieldVisibility) {
166170
return this;
167171
}
168172

173+
public Builder additionalTypes(Set<GraphQLType> additionalTypes) {
174+
this.additionalTypes = additionalTypes;
175+
return this;
176+
}
177+
178+
public Builder additionalDirectives(Set<GraphQLDirective> additionalDirectives) {
179+
this.additionalDirectives = additionalDirectives;
180+
return this;
181+
}
182+
169183
public GraphQLSchema build() {
170-
return build(Collections.emptySet(), Collections.emptySet());
184+
return build(additionalTypes, additionalDirectives);
171185
}
172186

173187
public GraphQLSchema build(Set<GraphQLType> additionalTypes) {

src/main/java/graphql/schema/idl/RuntimeWiring.java

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
package graphql.schema.idl;
22

3-
import graphql.Assert;
43
import graphql.PublicApi;
54
import graphql.schema.DataFetcher;
65
import graphql.schema.GraphQLScalarType;
76
import graphql.schema.GraphQLSchema;
87
import graphql.schema.TypeResolver;
8+
import graphql.schema.visibility.GraphqlFieldVisibility;
99

1010
import java.util.LinkedHashMap;
1111
import java.util.Map;
1212
import java.util.function.UnaryOperator;
1313

14+
import static graphql.Assert.assertNotNull;
15+
import static graphql.schema.visibility.DefaultGraphqlFieldVisibility.DEFAULT_FIELD_VISIBILITY;
16+
1417
/**
1518
* A runtime wiring is a specification of data fetchers, type resolves and custom scalars that are needed
1619
* to wire together a functional {@link GraphQLSchema}
@@ -24,14 +27,16 @@ public class RuntimeWiring {
2427
private final Map<String, TypeResolver> typeResolvers;
2528
private final WiringFactory wiringFactory;
2629
private final Map<String, EnumValuesProvider> enumValuesProviders;
30+
private final GraphqlFieldVisibility fieldVisibility;
2731

28-
private RuntimeWiring(Map<String, Map<String, DataFetcher>> dataFetchers, Map<String, DataFetcher> defaultDataFetchers, Map<String, GraphQLScalarType> scalars, Map<String, TypeResolver> typeResolvers, Map<String, EnumValuesProvider> enumValuesProviders, WiringFactory wiringFactory) {
32+
private RuntimeWiring(Map<String, Map<String, DataFetcher>> dataFetchers, Map<String, DataFetcher> defaultDataFetchers, Map<String, GraphQLScalarType> scalars, Map<String, TypeResolver> typeResolvers, Map<String, EnumValuesProvider> enumValuesProviders, WiringFactory wiringFactory, GraphqlFieldVisibility fieldVisibility) {
2933
this.dataFetchers = dataFetchers;
3034
this.defaultDataFetchers = defaultDataFetchers;
3135
this.scalars = scalars;
3236
this.typeResolvers = typeResolvers;
3337
this.wiringFactory = wiringFactory;
3438
this.enumValuesProviders = enumValuesProviders;
39+
this.fieldVisibility = fieldVisibility;
3540
}
3641

3742
/**
@@ -69,6 +74,10 @@ public WiringFactory getWiringFactory() {
6974
return wiringFactory;
7075
}
7176

77+
public GraphqlFieldVisibility getFieldVisibility() {
78+
return fieldVisibility;
79+
}
80+
7281
@PublicApi
7382
public static class Builder {
7483
private final Map<String, Map<String, DataFetcher>> dataFetchers = new LinkedHashMap<>();
@@ -77,6 +86,7 @@ public static class Builder {
7786
private final Map<String, TypeResolver> typeResolvers = new LinkedHashMap<>();
7887
private final Map<String, EnumValuesProvider> enumValuesProviders = new LinkedHashMap<>();
7988
private WiringFactory wiringFactory = new NoopWiringFactory();
89+
private GraphqlFieldVisibility fieldVisibility = DEFAULT_FIELD_VISIBILITY;
8090

8191
private Builder() {
8292
ScalarInfo.STANDARD_SCALARS.forEach(this::scalar);
@@ -90,7 +100,7 @@ private Builder() {
90100
* @return this outer builder
91101
*/
92102
public Builder wiringFactory(WiringFactory wiringFactory) {
93-
Assert.assertNotNull(wiringFactory, "You must provide a wiring factory");
103+
assertNotNull(wiringFactory, "You must provide a wiring factory");
94104
this.wiringFactory = wiringFactory;
95105
return this;
96106
}
@@ -107,6 +117,18 @@ public Builder scalar(GraphQLScalarType scalarType) {
107117
return this;
108118
}
109119

120+
/**
121+
* This allows you to add a field visibility that will be associated with the schema
122+
*
123+
* @param fieldVisibility the new field visibility
124+
*
125+
* @return the runtime wiring builder
126+
*/
127+
public Builder fieldVisibility(GraphqlFieldVisibility fieldVisibility) {
128+
this.fieldVisibility = assertNotNull(fieldVisibility);
129+
return this;
130+
}
131+
110132
/**
111133
* This allows you to add a new type wiring via a builder
112134
*
@@ -161,7 +183,7 @@ public Builder type(TypeRuntimeWiring typeRuntimeWiring) {
161183
* @return the built runtime wiring
162184
*/
163185
public RuntimeWiring build() {
164-
return new RuntimeWiring(dataFetchers, defaultDataFetchers, scalars, typeResolvers, enumValuesProviders, wiringFactory);
186+
return new RuntimeWiring(dataFetchers, defaultDataFetchers, scalars, typeResolvers, enumValuesProviders, wiringFactory, fieldVisibility);
165187
}
166188

167189
}

src/main/java/graphql/schema/idl/SchemaGenerator.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
package graphql.schema.idl;
22

33
import graphql.Assert;
4-
import graphql.GraphQL;
54
import graphql.GraphQLError;
65
import graphql.language.Argument;
76
import graphql.language.ArrayValue;
8-
import graphql.language.BooleanValue;
97
import graphql.language.Comment;
108
import graphql.language.Directive;
119
import graphql.language.EnumTypeDefinition;
1210
import graphql.language.EnumValue;
1311
import graphql.language.FieldDefinition;
14-
import graphql.language.FloatValue;
1512
import graphql.language.InputObjectTypeDefinition;
1613
import graphql.language.InputValueDefinition;
17-
import graphql.language.IntValue;
1814
import graphql.language.InterfaceTypeDefinition;
1915
import graphql.language.Node;
2016
import graphql.language.NullValue;
@@ -219,6 +215,7 @@ private GraphQLSchema makeExecutableSchemaImpl(BuildContext buildCtx) {
219215

220216
Set<GraphQLType> additionalTypes = buildAdditionalTypes(buildCtx);
221217

218+
schemaBuilder.fieldVisibility(buildCtx.getWiring().getFieldVisibility());
222219
return schemaBuilder.build(additionalTypes);
223220
}
224221

@@ -540,30 +537,30 @@ private GraphQLArgument buildArgument(BuildContext buildCtx, InputValueDefinitio
540537
private Object buildValue(Value value, GraphQLType requiredType) {
541538
Object result = null;
542539
if (requiredType instanceof GraphQLNonNull) {
543-
requiredType = ((GraphQLNonNull)requiredType).getWrappedType();
540+
requiredType = ((GraphQLNonNull) requiredType).getWrappedType();
544541
}
545542
if (requiredType instanceof GraphQLScalarType) {
546-
result = ((GraphQLScalarType)requiredType).getCoercing().parseLiteral(value);
543+
result = ((GraphQLScalarType) requiredType).getCoercing().parseLiteral(value);
547544
} else if (value instanceof EnumValue && requiredType instanceof GraphQLEnumType) {
548545
result = ((EnumValue) value).getName();
549546
} else if (value instanceof ArrayValue && requiredType instanceof GraphQLList) {
550547
ArrayValue arrayValue = (ArrayValue) value;
551548
GraphQLType wrappedType = ((GraphQLList) requiredType).getWrappedType();
552549
result = arrayValue.getValues().stream()
553-
.map(item -> this.buildValue(item, wrappedType)).collect(Collectors.toList());
550+
.map(item -> this.buildValue(item, wrappedType)).collect(Collectors.toList());
554551
} else if (value instanceof ObjectValue && requiredType instanceof GraphQLInputObjectType) {
555552
result = buildObjectValue((ObjectValue) value, (GraphQLInputObjectType) requiredType);
556553
} else if (value != null && !(value instanceof NullValue)) {
557554
Assert.assertShouldNeverHappen(
558-
"cannot build value of " + requiredType.getName() + " from " + String.valueOf(value));
555+
"cannot build value of " + requiredType.getName() + " from " + String.valueOf(value));
559556
}
560557
return result;
561558
}
562559

563560
private Object buildObjectValue(ObjectValue defaultValue, GraphQLInputObjectType objectType) {
564561
HashMap<String, Object> map = new LinkedHashMap<>();
565562
defaultValue.getObjectFields().forEach(of -> map.put(of.getName(),
566-
buildValue(of.getValue(), objectType.getField(of.getName()).getType())));
563+
buildValue(of.getValue(), objectType.getField(of.getName()).getType())));
567564
return map;
568565
}
569566

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package graphql.schema
2+
3+
import graphql.ExecutionInput
4+
import graphql.GraphQL
5+
import graphql.TestUtil
6+
import graphql.schema.idl.RuntimeWiring
7+
import spock.lang.Specification
8+
9+
class GraphQLSchemaTest extends Specification {
10+
11+
def "#698 interfaces copied as expected"() {
12+
13+
def idl = """
14+
type Query {
15+
foo: Node
16+
}
17+
18+
interface Node {
19+
id: String
20+
}
21+
22+
type Foo implements Node {
23+
id: String
24+
}
25+
"""
26+
27+
RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()
28+
.type("Query", { wiring ->
29+
wiring.dataFetcher("foo", { env ->
30+
Map<String, Object> map = new HashMap<>()
31+
map.put("id", "abc")
32+
return map
33+
})
34+
})
35+
.type("Node", { wiring ->
36+
wiring.typeResolver({ env -> (GraphQLObjectType) env.getSchema().getType("Foo") })
37+
})
38+
.build()
39+
40+
def existingSchema = TestUtil.schema(idl, runtimeWiring)
41+
42+
43+
GraphQLSchema schema = GraphQLSchema.newSchema(existingSchema).build()
44+
45+
expect:
46+
assert 0 == runQuery(existingSchema).getErrors().size()
47+
assert 0 == runQuery(schema).getErrors().size()
48+
}
49+
50+
51+
def runQuery(GraphQLSchema schema) {
52+
GraphQL graphQL = GraphQL.newGraphQL(schema)
53+
.build()
54+
55+
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
56+
.query("{foo {id}}")
57+
.build()
58+
59+
return graphQL
60+
.executeAsync(executionInput)
61+
.join()
62+
}
63+
}

src/test/groovy/graphql/schema/idl/SchemaGeneratorTest.groovy

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package graphql.schema.idl
22

33
import graphql.schema.GraphQLEnumType
4+
import graphql.schema.GraphQLFieldDefinition
5+
import graphql.schema.GraphQLFieldsContainer
46
import graphql.schema.GraphQLInputObjectType
57
import graphql.schema.GraphQLInterfaceType
68
import graphql.schema.GraphQLList
@@ -11,6 +13,7 @@ import graphql.schema.GraphQLType
1113
import graphql.schema.GraphQLUnionType
1214
import graphql.schema.idl.errors.NotAnInputTypeError
1315
import graphql.schema.idl.errors.NotAnOutputTypeError
16+
import graphql.schema.visibility.GraphqlFieldVisibility
1417
import spock.lang.Specification
1518

1619
import java.util.function.UnaryOperator
@@ -1005,4 +1008,31 @@ class SchemaGeneratorTest extends Specification {
10051008
arg["str"] instanceof String
10061009
arg["num"] instanceof Integer
10071010
}
1011+
1012+
def "field visibility is used"() {
1013+
def spec = """
1014+
type Query {
1015+
field : String
1016+
}
1017+
"""
1018+
1019+
GraphqlFieldVisibility fieldVisibility = new GraphqlFieldVisibility() {
1020+
@Override
1021+
List<GraphQLFieldDefinition> getFieldDefinitions(GraphQLFieldsContainer fieldsContainer) {
1022+
return null
1023+
}
1024+
1025+
@Override
1026+
GraphQLFieldDefinition getFieldDefinition(GraphQLFieldsContainer fieldsContainer, String fieldName) {
1027+
return null
1028+
}
1029+
}
1030+
1031+
def schema = schema(spec, RuntimeWiring.newRuntimeWiring().fieldVisibility(fieldVisibility).build())
1032+
1033+
expect:
1034+
1035+
schema.getFieldVisibility() == fieldVisibility
1036+
1037+
}
10081038
}

0 commit comments

Comments
 (0)