Skip to content

Commit 5806a95

Browse files
authored
fix: stop throwing NotImplementedError for nullable fields in generated resolver methods (#157)
1 parent 2ae97c1 commit 5806a95

File tree

4 files changed

+66
-28
lines changed

4 files changed

+66
-28
lines changed

src/definitions/field.ts

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export function buildObjectFieldDefinition({
5454
node,
5555
fieldNode,
5656
typeInResolverInterfacesConfig,
57+
typeMetadata,
5758
);
5859
const defaultFunctionValue = `${typeMetadata.isNullable ? "?" : ""} = ${defaultImplementation}`;
5960
const shouldGenerateFunctions = shouldGenerateFunctionsInClass(
@@ -182,12 +183,14 @@ function buildField(
182183
node,
183184
fieldNode,
184185
typeInResolverInterfacesConfig,
186+
typeMetadata,
185187
);
186188
const isCompletableFuture =
187189
typeInResolverInterfacesConfig?.classMethods === "COMPLETABLE_FUTURE";
190+
const isDataFetcherResult = typeInResolverInterfacesConfig?.dataFetcherResult;
188191
let typeDefinition = `${typeMetadata.typeName}${typeMetadata.isNullable ? "?" : ""}`;
189192
let defaultDefinition = `${typeMetadata.typeName}${defaultDefinitionValue}`;
190-
if (typeInResolverInterfacesConfig?.dataFetcherResult) {
193+
if (isDataFetcherResult) {
191194
typeDefinition = `graphql.execution.DataFetcherResult<${typeDefinition}>`;
192195
defaultDefinition = `${typeDefinition} = ${defaultImplementation}`;
193196
}
@@ -327,14 +330,49 @@ function getDefaultImplementation(
327330
typeInResolverInterfacesConfig: ReturnType<
328331
typeof findTypeInResolverInterfacesConfig
329332
>,
333+
typeMetadata: TypeMetadata,
330334
) {
331335
const notImplementedError = `throw NotImplementedError("${node.name.value}.${fieldNode.name.value} must be implemented.")`;
332-
const atLeastOneFieldHasNoArguments = node.fields?.some(
333-
(fieldNode) => !fieldNode.arguments?.length,
334-
);
335-
return !typeInResolverInterfacesConfig && atLeastOneFieldHasNoArguments
336-
? sanitizeName(fieldNode.name.value)
337-
: notImplementedError;
336+
337+
if (!typeInResolverInterfacesConfig) {
338+
const atLeastOneFieldHasNoArguments = node.fields?.some(
339+
(fieldNode) => !fieldNode.arguments?.length,
340+
);
341+
if (atLeastOneFieldHasNoArguments) {
342+
return sanitizeName(fieldNode.name.value);
343+
}
344+
return notImplementedError;
345+
}
346+
347+
if (typeMetadata.isNullable) {
348+
return getNullableFieldDefaultValue(
349+
typeInResolverInterfacesConfig,
350+
typeMetadata,
351+
);
352+
}
353+
return notImplementedError;
354+
}
355+
356+
function getNullableFieldDefaultValue(
357+
typeInResolverInterfacesConfig: NonNullable<
358+
ReturnType<typeof findTypeInResolverInterfacesConfig>
359+
>,
360+
typeMetadata: TypeMetadata,
361+
) {
362+
const isCompletableFuture =
363+
typeInResolverInterfacesConfig.classMethods === "COMPLETABLE_FUTURE";
364+
const isDataFetcherResult = typeInResolverInterfacesConfig.dataFetcherResult;
365+
366+
if (isCompletableFuture && isDataFetcherResult) {
367+
return `java.util.concurrent.CompletableFuture.completedFuture(graphql.execution.DataFetcherResult.newResult<${typeMetadata.typeName}?>().data(null).build())`;
368+
}
369+
if (isCompletableFuture) {
370+
return `java.util.concurrent.CompletableFuture.completedFuture(null)`;
371+
}
372+
if (isDataFetcherResult) {
373+
return `graphql.execution.DataFetcherResult.newResult<${typeMetadata.typeName}?>().data(null).build()`;
374+
}
375+
return "null";
338376
}
339377

340378
function isLastFieldInType(

test/unit/should_honor_dataFetcherResult_config_completable_future/expected.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import com.expediagroup.graphql.generator.annotations.*
44

55
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
66
open class DataFetcherResultCompletableFutureType {
7-
open fun stringField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<String?>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.stringField1 must be implemented.")
7+
open fun stringField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<String?>> = java.util.concurrent.CompletableFuture.completedFuture(graphql.execution.DataFetcherResult.newResult<String?>().data(null).build())
88
open fun stringField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<String>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.stringField2 must be implemented.")
9-
open fun booleanField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<Boolean?>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.booleanField1 must be implemented.")
9+
open fun booleanField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<Boolean?>> = java.util.concurrent.CompletableFuture.completedFuture(graphql.execution.DataFetcherResult.newResult<Boolean?>().data(null).build())
1010
open fun booleanField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<Boolean>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.booleanField2 must be implemented.")
11-
open fun integerField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<Int?>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.integerField1 must be implemented.")
11+
open fun integerField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<Int?>> = java.util.concurrent.CompletableFuture.completedFuture(graphql.execution.DataFetcherResult.newResult<Int?>().data(null).build())
1212
open fun integerField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<Int>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.integerField2 must be implemented.")
1313
open fun listField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<List<String>>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.listField must be implemented.")
1414
open fun listField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<List<String?>>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.listField2 must be implemented.")
15-
open fun listField3(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<List<String>?>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.listField3 must be implemented.")
16-
open fun listField4(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<List<String?>?>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.listField4 must be implemented.")
15+
open fun listField3(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<List<String>?>> = java.util.concurrent.CompletableFuture.completedFuture(graphql.execution.DataFetcherResult.newResult<List<String>?>().data(null).build())
16+
open fun listField4(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<List<String?>?>> = java.util.concurrent.CompletableFuture.completedFuture(graphql.execution.DataFetcherResult.newResult<List<String?>?>().data(null).build())
1717
}

test/unit/should_honor_dataFetcherResult_config_suspend/expected.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import com.expediagroup.graphql.generator.annotations.*
44

55
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
66
open class DataFetcherResultSuspendType {
7-
open suspend fun stringField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<String?> = throw NotImplementedError("DataFetcherResultSuspendType.stringField1 must be implemented.")
7+
open suspend fun stringField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<String?> = graphql.execution.DataFetcherResult.newResult<String?>().data(null).build()
88
open suspend fun stringField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<String> = throw NotImplementedError("DataFetcherResultSuspendType.stringField2 must be implemented.")
9-
open suspend fun booleanField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<Boolean?> = throw NotImplementedError("DataFetcherResultSuspendType.booleanField1 must be implemented.")
9+
open suspend fun booleanField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<Boolean?> = graphql.execution.DataFetcherResult.newResult<Boolean?>().data(null).build()
1010
open suspend fun booleanField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<Boolean> = throw NotImplementedError("DataFetcherResultSuspendType.booleanField2 must be implemented.")
11-
open suspend fun integerField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<Int?> = throw NotImplementedError("DataFetcherResultSuspendType.integerField1 must be implemented.")
11+
open suspend fun integerField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<Int?> = graphql.execution.DataFetcherResult.newResult<Int?>().data(null).build()
1212
open suspend fun integerField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<Int> = throw NotImplementedError("DataFetcherResultSuspendType.integerField2 must be implemented.")
1313
open suspend fun listField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<List<String>> = throw NotImplementedError("DataFetcherResultSuspendType.listField must be implemented.")
1414
open suspend fun listField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<List<String?>> = throw NotImplementedError("DataFetcherResultSuspendType.listField2 must be implemented.")
15-
open suspend fun listField3(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<List<String>?> = throw NotImplementedError("DataFetcherResultSuspendType.listField3 must be implemented.")
16-
open suspend fun listField4(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<List<String?>?> = throw NotImplementedError("DataFetcherResultSuspendType.listField4 must be implemented.")
15+
open suspend fun listField3(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<List<String>?> = graphql.execution.DataFetcherResult.newResult<List<String>?>().data(null).build()
16+
open suspend fun listField4(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<List<String?>?> = graphql.execution.DataFetcherResult.newResult<List<String?>?>().data(null).build()
1717
}

test/unit/should_honor_resolverInterfaces_config/expected.kt

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import com.expediagroup.graphql.generator.annotations.*
44

55
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
66
open class MyIncludedResolverType {
7-
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): MyChildType? = throw NotImplementedError("MyIncludedResolverType.nullableField must be implemented.")
7+
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): MyChildType? = null
88
open fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("MyIncludedResolverType.nonNullableField must be implemented.")
9-
open fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("MyIncludedResolverType.nullableResolver must be implemented.")
9+
open fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = null
1010
open fun nonNullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("MyIncludedResolverType.nonNullableResolver must be implemented.")
11-
open fun nullableListResolver(arg1: Int? = null, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String?>? = throw NotImplementedError("MyIncludedResolverType.nullableListResolver must be implemented.")
11+
open fun nullableListResolver(arg1: Int? = null, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String?>? = null
1212
open fun nonNullableListResolver(arg1: Int, arg2: Int? = null, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String> = throw NotImplementedError("MyIncludedResolverType.nonNullableListResolver must be implemented.")
1313
}
1414

@@ -22,27 +22,27 @@ open class MyChildType(
2222

2323
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
2424
open class MyIncludedResolverTypeWithNoFieldArgs {
25-
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("MyIncludedResolverTypeWithNoFieldArgs.nullableField must be implemented.")
25+
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = null
2626
open fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("MyIncludedResolverTypeWithNoFieldArgs.nonNullableField must be implemented.")
2727
}
2828

2929
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
3030
open class MySuspendResolverType {
31-
open suspend fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("MySuspendResolverType.nullableField must be implemented.")
31+
open suspend fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = null
3232
open suspend fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("MySuspendResolverType.nonNullableField must be implemented.")
33-
open suspend fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("MySuspendResolverType.nullableResolver must be implemented.")
33+
open suspend fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = null
3434
open suspend fun nonNullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("MySuspendResolverType.nonNullableResolver must be implemented.")
35-
open suspend fun nullableListResolver(arg1: Int? = null, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String?>? = throw NotImplementedError("MySuspendResolverType.nullableListResolver must be implemented.")
35+
open suspend fun nullableListResolver(arg1: Int? = null, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String?>? = null
3636
open suspend fun nonNullableListResolver(arg1: Int, arg2: Int? = null, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String> = throw NotImplementedError("MySuspendResolverType.nonNullableListResolver must be implemented.")
3737
}
3838

3939
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
4040
open class MyCompletableFutureResolverType {
41-
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String?> = throw NotImplementedError("MyCompletableFutureResolverType.nullableField must be implemented.")
41+
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String?> = java.util.concurrent.CompletableFuture.completedFuture(null)
4242
open fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String> = throw NotImplementedError("MyCompletableFutureResolverType.nonNullableField must be implemented.")
43-
open fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String?> = throw NotImplementedError("MyCompletableFutureResolverType.nullableResolver must be implemented.")
43+
open fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String?> = java.util.concurrent.CompletableFuture.completedFuture(null)
4444
open fun nonNullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String> = throw NotImplementedError("MyCompletableFutureResolverType.nonNullableResolver must be implemented.")
45-
open fun nullableListResolver(arg1: Int? = null, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<List<String?>?> = throw NotImplementedError("MyCompletableFutureResolverType.nullableListResolver must be implemented.")
45+
open fun nullableListResolver(arg1: Int? = null, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<List<String?>?> = java.util.concurrent.CompletableFuture.completedFuture(null)
4646
open fun nonNullableListResolver(arg1: Int, arg2: Int? = null, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<List<String>> = throw NotImplementedError("MyCompletableFutureResolverType.nonNullableListResolver must be implemented.")
4747
}
4848

@@ -66,6 +66,6 @@ interface MyExcludedInterface {
6666

6767
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
6868
open class MyIncludedResolverTypeWithNullDataFetchingEnvironment {
69-
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment? = null): String? = throw NotImplementedError("MyIncludedResolverTypeWithNullDataFetchingEnvironment.nullableField must be implemented.")
69+
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment? = null): String? = null
7070
open fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment? = null): String = throw NotImplementedError("MyIncludedResolverTypeWithNullDataFetchingEnvironment.nonNullableField must be implemented.")
7171
}

0 commit comments

Comments
 (0)