Skip to content

Commit 12120e9

Browse files
authored
Fixes the copying of schemas and also the fact you cant set field visibility on IDL schema creation runtime wiring (graphql-java#702)
1 parent 69dab6b commit 12120e9

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)