Skip to content

Commit

Permalink
Merge pull request #3579 from graphql-java/dont-overwrite-default-dat…
Browse files Browse the repository at this point in the history
…a-fetchers-if-they-are-null

Now does not overwrite a types default data fetcher unless its nonnull
  • Loading branch information
bbakerman committed May 21, 2024
2 parents f3253b4 + 70c7963 commit 53f22c5
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 2 deletions.
26 changes: 25 additions & 1 deletion src/main/java/graphql/schema/idl/RuntimeWiring.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,31 @@ public Map<String, Map<String, DataFetcher>> getDataFetchers() {
return dataFetchers;
}

/**
* This is deprecated because the name has the wrong plural case.
*
* @param typeName the type for fetch a map of per field data fetchers for
*
* @return a map of field data fetchers for a type
*
* @deprecated See {@link #getDataFetchersForType(String)}
*/
@Deprecated(since = "2024-04-28")
public Map<String, DataFetcher> getDataFetcherForType(String typeName) {
return dataFetchers.computeIfAbsent(typeName, k -> new LinkedHashMap<>());
}

/**
* This returns a map of the data fetchers per field on that named type.
*
* @param typeName the type for fetch a map of per field data fetchers for
*
* @return a map of field data fetchers for a type
*/
public Map<String, DataFetcher> getDataFetchersForType(String typeName) {
return dataFetchers.computeIfAbsent(typeName, k -> new LinkedHashMap<>());
}

public DataFetcher getDefaultDataFetcherForType(String typeName) {
return defaultDataFetchers.get(typeName);
}
Expand Down Expand Up @@ -284,7 +305,10 @@ public Builder type(TypeRuntimeWiring typeRuntimeWiring) {
}
typeDataFetchers.putAll(typeRuntimeWiring.getFieldDataFetchers());

defaultDataFetchers.put(typeName, typeRuntimeWiring.getDefaultDataFetcher());
DataFetcher<?> defaultDataFetcher = typeRuntimeWiring.getDefaultDataFetcher();
if (defaultDataFetcher != null) {
defaultDataFetchers.put(typeName, defaultDataFetcher);
}

TypeResolver typeResolver = typeRuntimeWiring.getTypeResolver();
if (typeResolver != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ private DataFetcherFactory<?> buildDataFetcherFactory(BuildContext buildCtx,
dataFetcher = wiringFactory.getDataFetcher(wiringEnvironment);
assertNotNull(dataFetcher, () -> "The WiringFactory indicated it provides a data fetcher but then returned null");
} else {
dataFetcher = runtimeWiring.getDataFetcherForType(parentTypeName).get(fieldName);
dataFetcher = runtimeWiring.getDataFetchersForType(parentTypeName).get(fieldName);
if (dataFetcher == null) {
dataFetcher = runtimeWiring.getDefaultDataFetcherForType(parentTypeName);
if (dataFetcher == null) {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/graphql/schema/idl/TypeRuntimeWiring.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@ private void assertFieldStrictly(String fieldName) {
*/
public Builder defaultDataFetcher(DataFetcher dataFetcher) {
assertNotNull(dataFetcher);
if (strictMode && defaultDataFetcher != null) {
throw new StrictModeWiringException(format("The type %s has already has a default data fetcher defined", typeName));
}
defaultDataFetcher = dataFetcher;
return this;
}
Expand Down
41 changes: 41 additions & 0 deletions src/test/groovy/graphql/schema/idl/RuntimeWiringTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ class RuntimeWiringTest extends Specification {

def "strict mode can stop certain redefinitions"() {
DataFetcher DF1 = env -> "x"
DataFetcher DF2 = env -> "x"
TypeResolver TR1 = env -> null
EnumValuesProvider EVP1 = name -> null

Expand Down Expand Up @@ -236,5 +237,45 @@ class RuntimeWiringTest extends Specification {
def e4 = thrown(StrictModeWiringException)
e4.message == "The scalar String is already defined"

when:
TypeRuntimeWiring.newTypeWiring("Foo")
.strictMode()
.defaultDataFetcher(DF1)
.defaultDataFetcher(DF2)

then:
def e5 = thrown(StrictModeWiringException)
e5.message == "The type Foo has already has a default data fetcher defined"
}

def "overwrite default data fetchers if they are null"() {

DataFetcher DF1 = env -> "x"
DataFetcher DF2 = env -> "x"
DataFetcher DEFAULT_DF = env -> null
DataFetcher DEFAULT_DF2 = env -> null

when:
def runtimeWiring = RuntimeWiring.newRuntimeWiring()
.type(TypeRuntimeWiring.newTypeWiring("Foo").defaultDataFetcher(DEFAULT_DF))
.type(TypeRuntimeWiring.newTypeWiring("Foo").dataFetcher("foo", DF1))
.type(TypeRuntimeWiring.newTypeWiring("Foo").dataFetcher("bar", DF2))
.build()

then:
runtimeWiring.getDefaultDataFetcherForType("Foo") == DEFAULT_DF

when:
runtimeWiring = RuntimeWiring.newRuntimeWiring()
.type(TypeRuntimeWiring.newTypeWiring("Foo").defaultDataFetcher(DEFAULT_DF))
.type(TypeRuntimeWiring.newTypeWiring("Foo").dataFetcher("foo", DF1))
.type(TypeRuntimeWiring.newTypeWiring("Foo").dataFetcher("bar", DF2))
// we can specifically overwrite it later
.type(TypeRuntimeWiring.newTypeWiring("Foo").defaultDataFetcher(DEFAULT_DF2))
.build()

then:
runtimeWiring.getDefaultDataFetcherForType("Foo") == DEFAULT_DF2

}
}

0 comments on commit 53f22c5

Please sign in to comment.