Skip to content

Commit c000df7

Browse files
committed
Allows creating mock schemas where there are default values on custom schemas
1 parent 2cac173 commit c000df7

File tree

3 files changed

+138
-11
lines changed

3 files changed

+138
-11
lines changed

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

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

3+
import graphql.Assert;
4+
import graphql.GraphQLContext;
35
import graphql.PublicApi;
6+
import graphql.execution.CoercedVariables;
7+
import graphql.language.ArrayValue;
8+
import graphql.language.BooleanValue;
9+
import graphql.language.EnumValue;
10+
import graphql.language.FloatValue;
11+
import graphql.language.IntValue;
12+
import graphql.language.NullValue;
13+
import graphql.language.ObjectField;
14+
import graphql.language.ObjectValue;
15+
import graphql.language.StringValue;
16+
import graphql.language.Value;
17+
import graphql.language.VariableReference;
418
import graphql.schema.Coercing;
519
import graphql.schema.CoercingParseLiteralException;
620
import graphql.schema.CoercingParseValueException;
@@ -9,8 +23,26 @@
923
import graphql.schema.GraphQLScalarType;
1024
import graphql.schema.SingletonPropertyDataFetcher;
1125
import graphql.schema.TypeResolver;
26+
import org.jspecify.annotations.NonNull;
27+
import org.jspecify.annotations.NullMarked;
28+
import org.jspecify.annotations.Nullable;
1229

30+
import java.util.LinkedHashMap;
31+
import java.util.List;
32+
import java.util.Locale;
33+
import java.util.Map;
34+
import java.util.stream.Collectors;
35+
36+
/**
37+
* This is a {@link WiringFactory} which provides mocked types resolver
38+
* and scalars. It is useful for testing only, for example for creating schemas
39+
* that can be inspected but not executed on.
40+
* <p>
41+
* See {@link RuntimeWiring#MOCKED_WIRING} for example usage
42+
*/
1343
@PublicApi
44+
@NullMarked
45+
@SuppressWarnings("rawtypes")
1446
public class MockedWiringFactory implements WiringFactory {
1547

1648
@Override
@@ -43,34 +75,79 @@ public boolean providesDataFetcher(FieldWiringEnvironment environment) {
4375
}
4476

4577
@Override
46-
public DataFetcher getDataFetcher(FieldWiringEnvironment environment) {
78+
public DataFetcher<?> getDataFetcher(FieldWiringEnvironment environment) {
4779
return SingletonPropertyDataFetcher.singleton();
4880
}
4981

5082
@Override
5183
public boolean providesScalar(ScalarWiringEnvironment environment) {
52-
if (ScalarInfo.isGraphqlSpecifiedScalar(environment.getScalarTypeDefinition().getName())) {
53-
return false;
54-
}
55-
return true;
84+
return !ScalarInfo.isGraphqlSpecifiedScalar(environment.getScalarTypeDefinition().getName());
5685
}
5786

5887
public GraphQLScalarType getScalar(ScalarWiringEnvironment environment) {
59-
return GraphQLScalarType.newScalar().name(environment.getScalarTypeDefinition().getName()).coercing(new Coercing() {
88+
return GraphQLScalarType.newScalar().name(environment.getScalarTypeDefinition().getName()).coercing(new Coercing<>() {
89+
@Nullable
6090
@Override
61-
public Object serialize(Object dataFetcherResult) throws CoercingSerializeException {
91+
public Object serialize(@NonNull Object dataFetcherResult, @NonNull GraphQLContext graphQLContext, @NonNull Locale locale) throws CoercingSerializeException {
6292
throw new UnsupportedOperationException("Not implemented...this is only a mocked wiring");
6393
}
6494

95+
@Nullable
6596
@Override
66-
public Object parseValue(Object input) throws CoercingParseValueException {
97+
public Object parseValue(@NonNull Object input, @NonNull GraphQLContext graphQLContext, @NonNull Locale locale) throws CoercingParseValueException {
6798
throw new UnsupportedOperationException("Not implemented...this is only a mocked wiring");
6899
}
69100

101+
@Nullable
70102
@Override
71-
public Object parseLiteral(Object input) throws CoercingParseLiteralException {
72-
throw new UnsupportedOperationException("Not implemented...this is only a mocked wiring");
103+
public Object parseLiteral(@NonNull Value input, @NonNull CoercedVariables variables, @NonNull GraphQLContext graphQLContext, @NonNull Locale locale) throws CoercingParseLiteralException {
104+
return parseLiteralImpl(input, variables, graphQLContext, locale);
73105
}
106+
107+
@Nullable
108+
private Object parseLiteralImpl(Value<?> input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) {
109+
if (input instanceof NullValue) {
110+
return null;
111+
}
112+
if (input instanceof FloatValue) {
113+
return ((FloatValue) input).getValue();
114+
}
115+
if (input instanceof StringValue) {
116+
return ((StringValue) input).getValue();
117+
}
118+
if (input instanceof IntValue) {
119+
return ((IntValue) input).getValue();
120+
}
121+
if (input instanceof BooleanValue) {
122+
return ((BooleanValue) input).isValue();
123+
}
124+
if (input instanceof EnumValue) {
125+
return ((EnumValue) input).getName();
126+
}
127+
if (input instanceof VariableReference) {
128+
String varName = ((VariableReference) input).getName();
129+
return variables.get(varName);
130+
}
131+
if (input instanceof ArrayValue) {
132+
List<Value> values = ((ArrayValue) input).getValues();
133+
return values.stream()
134+
.map(v -> parseLiteral(v, variables, graphQLContext, locale))
135+
.collect(Collectors.toList());
136+
}
137+
if (input instanceof ObjectValue) {
138+
List<ObjectField> values = ((ObjectValue) input).getObjectFields();
139+
Map<String, Object> parsedValues = new LinkedHashMap<>();
140+
values.forEach(fld -> {
141+
Object parsedValue = parseLiteral(fld.getValue(), variables, graphQLContext, locale);
142+
if (parsedValue != null) {
143+
parsedValues.put(fld.getName(), parsedValue);
144+
}
145+
});
146+
return parsedValues;
147+
}
148+
return Assert.assertShouldNeverHappen("We have covered all Value types");
149+
}
150+
74151
}).build();
75152
}
76153
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ public class RuntimeWiring {
4242

4343
/**
4444
* This is a Runtime wiring which provides mocked types resolver
45-
* and scalars. Useful for testing only.
45+
* and scalars. It is useful for testing only, for example for creating schemas
46+
* that can be inspected but not executed on.
4647
*/
4748
public static final RuntimeWiring MOCKED_WIRING = RuntimeWiring
4849
.newRuntimeWiring()
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package graphql.schema.idl
2+
3+
4+
import spock.lang.Specification
5+
6+
class MockedWiringFactoryTest extends Specification {
7+
8+
def "mock wiring factory can be used for any schema"() {
9+
def sdl = """
10+
type Query {
11+
foo : Foo
12+
}
13+
14+
scalar SomeScalar
15+
scalar SomeOtherScalar
16+
17+
type Foo {
18+
bar(
19+
arg1 : SomeScalar! = 666,
20+
arg2 : Int! = 777,
21+
arg3 : SomeOtherScalar = { x : [{ y : 1, z : "s"}] } ) : Bar
22+
}
23+
24+
interface Bar {
25+
baz : String
26+
}
27+
28+
type BarBar implements Bar {
29+
baz : String
30+
}
31+
32+
type BlackSheep implements Bar {
33+
baz : String
34+
}
35+
"""
36+
37+
when:
38+
def registry = new SchemaParser().parse(sdl)
39+
def schema = new SchemaGenerator().makeExecutableSchema(registry, RuntimeWiring.MOCKED_WIRING)
40+
41+
then:
42+
schema != null
43+
schema.getType("Query") != null
44+
schema.getType("Foo") != null
45+
schema.getType("Bar") != null
46+
schema.getType("BarBar") != null
47+
schema.getType("BlackSheep") != null
48+
}
49+
}

0 commit comments

Comments
 (0)