diff --git a/src/config/schema.ts b/src/config/schema.ts index af8764b..c8189ba 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -121,7 +121,8 @@ export const configSchema = object({ * * Type names can be optionally passed with the classMethods config to generate the interface with `suspend` functions or * `java.util.concurrent.CompletableFuture` functions. Pass `nullableDataFetchingEnvironment: true` to make the - * `DataFetchingEnvironment` argument nullable in each resolver function for that class. + * `DataFetchingEnvironment` argument nullable in each resolver function for that class. Pass `dataFetcherResult: true` + * to make functions return `DataFetcherResult` to hold both data and errors. * @example * [ * { @@ -138,6 +139,10 @@ export const configSchema = object({ * { * typeName: "MyTypeWithNullableDataFetchingEnvironment", * nullableDataFetchingEnvironment: true, + * }, + * { + * typeName: "MyTypeWithPartialData", + * dataFetcherResult: true, * } * ] * @link https://opensource.expediagroup.com/graphql-kotlin-codegen/docs/recommended-usage @@ -150,6 +155,7 @@ export const configSchema = object({ union([literal("SUSPEND"), literal("COMPLETABLE_FUTURE")]), ), nullableDataFetchingEnvironment: optional(boolean()), + dataFetcherResult: optional(boolean()), }), ), ), diff --git a/src/definitions/field.ts b/src/definitions/field.ts index 702e1cc..260c6f0 100644 --- a/src/definitions/field.ts +++ b/src/definitions/field.ts @@ -183,8 +183,13 @@ function buildField( ); const isCompletableFuture = typeInResolverInterfacesConfig?.classMethods === "COMPLETABLE_FUTURE"; - const completableFutureDefinition = `java.util.concurrent.CompletableFuture<${typeMetadata.typeName}${typeMetadata.isNullable ? "?" : ""}> = ${defaultImplementation}`; - const defaultDefinition = `${typeMetadata.typeName}${defaultDefinitionValue}`; + let typeDefinition = `${typeMetadata.typeName}${typeMetadata.isNullable ? "?" : ""}`; + let defaultDefinition = `${typeMetadata.typeName}${defaultDefinitionValue}`; + if (typeInResolverInterfacesConfig?.dataFetcherResult) { + typeDefinition = `graphql.execution.DataFetcherResult<${typeDefinition}>`; + defaultDefinition = `${typeDefinition} = ${defaultImplementation}`; + } + const completableFutureDefinition = `java.util.concurrent.CompletableFuture<${typeDefinition}> = ${defaultImplementation}`; return indent( `${functionDefinition}: ${isCompletableFuture ? completableFutureDefinition : defaultDefinition}`, 2, diff --git a/test/unit/should_honor_dataFetcherResult_config_completable_future/codegen.config.ts b/test/unit/should_honor_dataFetcherResult_config_completable_future/codegen.config.ts new file mode 100644 index 0000000..37e30ab --- /dev/null +++ b/test/unit/should_honor_dataFetcherResult_config_completable_future/codegen.config.ts @@ -0,0 +1,11 @@ +import { GraphQLKotlinCodegenConfig } from "../../../src/plugin"; + +export default { + resolverInterfaces: [ + { + typeName: "DataFetcherResultCompletableFutureType", + classMethods: "COMPLETABLE_FUTURE", + dataFetcherResult: true, + }, + ], +} satisfies GraphQLKotlinCodegenConfig; diff --git a/test/unit/should_honor_dataFetcherResult_config_completable_future/expected.kt b/test/unit/should_honor_dataFetcherResult_config_completable_future/expected.kt new file mode 100644 index 0000000..d993efa --- /dev/null +++ b/test/unit/should_honor_dataFetcherResult_config_completable_future/expected.kt @@ -0,0 +1,17 @@ +package com.kotlin.generated + +import com.expediagroup.graphql.generator.annotations.* + +@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT]) +open class DataFetcherResultCompletableFutureType { + open fun stringField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture> = throw NotImplementedError("DataFetcherResultCompletableFutureType.stringField1 must be implemented.") + open fun stringField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture> = throw NotImplementedError("DataFetcherResultCompletableFutureType.stringField2 must be implemented.") + open fun booleanField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture> = throw NotImplementedError("DataFetcherResultCompletableFutureType.booleanField1 must be implemented.") + open fun booleanField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture> = throw NotImplementedError("DataFetcherResultCompletableFutureType.booleanField2 must be implemented.") + open fun integerField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture> = throw NotImplementedError("DataFetcherResultCompletableFutureType.integerField1 must be implemented.") + open fun integerField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture> = throw NotImplementedError("DataFetcherResultCompletableFutureType.integerField2 must be implemented.") + open fun listField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.listField must be implemented.") + open fun listField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.listField2 must be implemented.") + open fun listField3(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture?>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.listField3 must be implemented.") + open fun listField4(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture?>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.listField4 must be implemented.") +} diff --git a/test/unit/should_honor_dataFetcherResult_config_completable_future/schema.graphql b/test/unit/should_honor_dataFetcherResult_config_completable_future/schema.graphql new file mode 100644 index 0000000..4788bb8 --- /dev/null +++ b/test/unit/should_honor_dataFetcherResult_config_completable_future/schema.graphql @@ -0,0 +1,12 @@ +type DataFetcherResultCompletableFutureType { + stringField1: String + stringField2: String! + booleanField1: Boolean + booleanField2: Boolean! + integerField1: Int + integerField2: Int! + listField: [String!]! + listField2: [String]! + listField3: [String!] + listField4: [String] +} diff --git a/test/unit/should_honor_dataFetcherResult_config_suspend/codegen.config.ts b/test/unit/should_honor_dataFetcherResult_config_suspend/codegen.config.ts new file mode 100644 index 0000000..5283f07 --- /dev/null +++ b/test/unit/should_honor_dataFetcherResult_config_suspend/codegen.config.ts @@ -0,0 +1,11 @@ +import { GraphQLKotlinCodegenConfig } from "../../../src/plugin"; + +export default { + resolverInterfaces: [ + { + typeName: "DataFetcherResultSuspendType", + classMethods: "SUSPEND", + dataFetcherResult: true, + }, + ], +} satisfies GraphQLKotlinCodegenConfig; diff --git a/test/unit/should_honor_dataFetcherResult_config_suspend/expected.kt b/test/unit/should_honor_dataFetcherResult_config_suspend/expected.kt new file mode 100644 index 0000000..dd3864f --- /dev/null +++ b/test/unit/should_honor_dataFetcherResult_config_suspend/expected.kt @@ -0,0 +1,17 @@ +package com.kotlin.generated + +import com.expediagroup.graphql.generator.annotations.* + +@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT]) +open class DataFetcherResultSuspendType { + open suspend fun stringField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult = throw NotImplementedError("DataFetcherResultSuspendType.stringField1 must be implemented.") + open suspend fun stringField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult = throw NotImplementedError("DataFetcherResultSuspendType.stringField2 must be implemented.") + open suspend fun booleanField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult = throw NotImplementedError("DataFetcherResultSuspendType.booleanField1 must be implemented.") + open suspend fun booleanField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult = throw NotImplementedError("DataFetcherResultSuspendType.booleanField2 must be implemented.") + open suspend fun integerField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult = throw NotImplementedError("DataFetcherResultSuspendType.integerField1 must be implemented.") + open suspend fun integerField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult = throw NotImplementedError("DataFetcherResultSuspendType.integerField2 must be implemented.") + open suspend fun listField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult> = throw NotImplementedError("DataFetcherResultSuspendType.listField must be implemented.") + open suspend fun listField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult> = throw NotImplementedError("DataFetcherResultSuspendType.listField2 must be implemented.") + open suspend fun listField3(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult?> = throw NotImplementedError("DataFetcherResultSuspendType.listField3 must be implemented.") + open suspend fun listField4(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult?> = throw NotImplementedError("DataFetcherResultSuspendType.listField4 must be implemented.") +} diff --git a/test/unit/should_honor_dataFetcherResult_config_suspend/schema.graphql b/test/unit/should_honor_dataFetcherResult_config_suspend/schema.graphql new file mode 100644 index 0000000..da30a94 --- /dev/null +++ b/test/unit/should_honor_dataFetcherResult_config_suspend/schema.graphql @@ -0,0 +1,12 @@ +type DataFetcherResultSuspendType { + stringField1: String + stringField2: String! + booleanField1: Boolean + booleanField2: Boolean! + integerField1: Int + integerField2: Int! + listField: [String!]! + listField2: [String]! + listField3: [String!] + listField4: [String] +} diff --git a/test/unit/should_honor_resolverInterfaces_config/codegen.config.ts b/test/unit/should_honor_resolverInterfaces_config/codegen.config.ts index 2a12eb9..1c44e8e 100644 --- a/test/unit/should_honor_resolverInterfaces_config/codegen.config.ts +++ b/test/unit/should_honor_resolverInterfaces_config/codegen.config.ts @@ -27,5 +27,9 @@ export default { typeName: "MyIncludedResolverTypeWithNullDataFetchingEnvironment", nullableDataFetchingEnvironment: true, }, + { + typeName: "MyTypeWithPartialData", + dataFetcherResult: true, + }, ], } satisfies GraphQLKotlinCodegenConfig;