Skip to content

Commit 5df1e00

Browse files
authored
feat: add dataFetcherResult option to return both errors and partial data (#126)
1 parent f46b5da commit 5df1e00

File tree

9 files changed

+98
-3
lines changed

9 files changed

+98
-3
lines changed

src/config/schema.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ export const configSchema = object({
121121
*
122122
* Type names can be optionally passed with the classMethods config to generate the interface with `suspend` functions or
123123
* `java.util.concurrent.CompletableFuture` functions. Pass `nullableDataFetchingEnvironment: true` to make the
124-
* `DataFetchingEnvironment` argument nullable in each resolver function for that class.
124+
* `DataFetchingEnvironment` argument nullable in each resolver function for that class. Pass `dataFetcherResult: true`
125+
* to make functions return `DataFetcherResult` to hold both data and errors.
125126
* @example
126127
* [
127128
* {
@@ -138,6 +139,10 @@ export const configSchema = object({
138139
* {
139140
* typeName: "MyTypeWithNullableDataFetchingEnvironment",
140141
* nullableDataFetchingEnvironment: true,
142+
* },
143+
* {
144+
* typeName: "MyTypeWithPartialData",
145+
* dataFetcherResult: true,
141146
* }
142147
* ]
143148
* @link https://opensource.expediagroup.com/graphql-kotlin-codegen/docs/recommended-usage
@@ -150,6 +155,7 @@ export const configSchema = object({
150155
union([literal("SUSPEND"), literal("COMPLETABLE_FUTURE")]),
151156
),
152157
nullableDataFetchingEnvironment: optional(boolean()),
158+
dataFetcherResult: optional(boolean()),
153159
}),
154160
),
155161
),

src/definitions/field.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,13 @@ function buildField(
183183
);
184184
const isCompletableFuture =
185185
typeInResolverInterfacesConfig?.classMethods === "COMPLETABLE_FUTURE";
186-
const completableFutureDefinition = `java.util.concurrent.CompletableFuture<${typeMetadata.typeName}${typeMetadata.isNullable ? "?" : ""}> = ${defaultImplementation}`;
187-
const defaultDefinition = `${typeMetadata.typeName}${defaultDefinitionValue}`;
186+
let typeDefinition = `${typeMetadata.typeName}${typeMetadata.isNullable ? "?" : ""}`;
187+
let defaultDefinition = `${typeMetadata.typeName}${defaultDefinitionValue}`;
188+
if (typeInResolverInterfacesConfig?.dataFetcherResult) {
189+
typeDefinition = `graphql.execution.DataFetcherResult<${typeDefinition}>`;
190+
defaultDefinition = `${typeDefinition} = ${defaultImplementation}`;
191+
}
192+
const completableFutureDefinition = `java.util.concurrent.CompletableFuture<${typeDefinition}> = ${defaultImplementation}`;
188193
return indent(
189194
`${functionDefinition}: ${isCompletableFuture ? completableFutureDefinition : defaultDefinition}`,
190195
2,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { GraphQLKotlinCodegenConfig } from "../../../src/plugin";
2+
3+
export default {
4+
resolverInterfaces: [
5+
{
6+
typeName: "DataFetcherResultCompletableFutureType",
7+
classMethods: "COMPLETABLE_FUTURE",
8+
dataFetcherResult: true,
9+
},
10+
],
11+
} satisfies GraphQLKotlinCodegenConfig;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.kotlin.generated
2+
3+
import com.expediagroup.graphql.generator.annotations.*
4+
5+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
6+
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.")
8+
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.")
10+
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.")
12+
open fun integerField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<Int>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.integerField2 must be implemented.")
13+
open fun listField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<graphql.execution.DataFetcherResult<List<String>>> = throw NotImplementedError("DataFetcherResultCompletableFutureType.listField must be implemented.")
14+
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.")
17+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
type DataFetcherResultCompletableFutureType {
2+
stringField1: String
3+
stringField2: String!
4+
booleanField1: Boolean
5+
booleanField2: Boolean!
6+
integerField1: Int
7+
integerField2: Int!
8+
listField: [String!]!
9+
listField2: [String]!
10+
listField3: [String!]
11+
listField4: [String]
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { GraphQLKotlinCodegenConfig } from "../../../src/plugin";
2+
3+
export default {
4+
resolverInterfaces: [
5+
{
6+
typeName: "DataFetcherResultSuspendType",
7+
classMethods: "SUSPEND",
8+
dataFetcherResult: true,
9+
},
10+
],
11+
} satisfies GraphQLKotlinCodegenConfig;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.kotlin.generated
2+
3+
import com.expediagroup.graphql.generator.annotations.*
4+
5+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
6+
open class DataFetcherResultSuspendType {
7+
open suspend fun stringField1(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<String?> = throw NotImplementedError("DataFetcherResultSuspendType.stringField1 must be implemented.")
8+
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.")
10+
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.")
12+
open suspend fun integerField2(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<Int> = throw NotImplementedError("DataFetcherResultSuspendType.integerField2 must be implemented.")
13+
open suspend fun listField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): graphql.execution.DataFetcherResult<List<String>> = throw NotImplementedError("DataFetcherResultSuspendType.listField must be implemented.")
14+
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.")
17+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
type DataFetcherResultSuspendType {
2+
stringField1: String
3+
stringField2: String!
4+
booleanField1: Boolean
5+
booleanField2: Boolean!
6+
integerField1: Int
7+
integerField2: Int!
8+
listField: [String!]!
9+
listField2: [String]!
10+
listField3: [String!]
11+
listField4: [String]
12+
}

test/unit/should_honor_resolverInterfaces_config/codegen.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,9 @@ export default {
2727
typeName: "MyIncludedResolverTypeWithNullDataFetchingEnvironment",
2828
nullableDataFetchingEnvironment: true,
2929
},
30+
{
31+
typeName: "MyTypeWithPartialData",
32+
dataFetcherResult: true,
33+
},
3034
],
3135
} satisfies GraphQLKotlinCodegenConfig;

0 commit comments

Comments
 (0)