Skip to content

Commit e8a9d80

Browse files
committed
fix: Revert #64 (#66)
1 parent 685d6c7 commit e8a9d80

File tree

9 files changed

+66
-75
lines changed

9 files changed

+66
-75
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ In essence, it unlocks a schema-first approach to [code-first GraphQL](https://w
1212

1313
## 📋 Docs
1414

15-
Check out our <a href="https://opensource.expediagroup.com/graphql-kotlin-codegen/" target="_blank">documentation site</a>!.
15+
<a href="https://opensource.expediagroup.com/graphql-kotlin-codegen/" target="_blank">Check out our docs site!</a>
1616

1717
## ✏️ Contributions
1818

docs/docs/recommended-usage.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ sidebar_position: 4
44

55
# Recommended Usage
66

7-
In general, the `resolverClasses` config should be used to generate more performant code. This is especially important
7+
In general, the `resolverInterfaces` config should be used to generate more performant code. This is especially important
88
when dealing with expensive operations, such as database queries or network requests. When at least one field has
9-
arguments in a type, we generate an interface with function signatures to be inherited in source code.
9+
arguments in a type, we generate an open class with function signatures to be inherited in source code.
1010
However, when fields have no arguments, we generate data classes by default.
1111

1212
## Example
@@ -33,8 +33,8 @@ Generated Kotlin:
3333
```kotlin
3434
package com.types.generated
3535

36-
interface Query {
37-
fun resolveMyType(input: String): MyType
36+
open class Query {
37+
open fun resolveMyType(input: String): MyType = throw NotImplementedError("Query.resolveMyType must be implemented.")
3838
}
3939

4040
data class MyType(
@@ -50,7 +50,7 @@ import com.expediagroup.graphql.server.operations.Query
5050
import com.types.generated.MyType
5151
import com.types.generated.Query as QueryInterface
5252

53-
class MyQuery : Query, QueryInterface {
53+
class MyQuery : Query, QueryInterface() {
5454
override fun resolveMyType(input: String): MyType =
5555
MyType(
5656
field1 = myExpensiveCall1(),
@@ -65,15 +65,15 @@ that the `field1` and `field2` properties are both initialized when the `MyType`
6565
`myExpensiveCall1()` and `myExpensiveCall2()` will both be called in sequence! Even if I only query for `field1`, not
6666
only will `myExpensiveCall2()` still run, but it will also wait until `myExpensiveCall1()` is totally finished.
6767

68-
### Instead, use the `resolverClasses` config!
68+
### Instead, use the `resolverInterfaces` config!
6969

7070
Codegen config:
7171

7272
```ts
7373
import { GraphQLKotlinCodegenConfig } from "@expediagroup/graphql-kotlin-codegen";
7474

7575
export default {
76-
resolverClasses: [
76+
resolverInterfaces: [
7777
{
7878
typeName: "MyType",
7979
},
@@ -86,13 +86,13 @@ Generated Kotlin:
8686
```kotlin
8787
package com.types.generated
8888

89-
interface Query {
90-
fun resolveMyType(input: String): MyType
89+
open class Query {
90+
open fun resolveMyType(input: String): MyType = throw NotImplementedError("Query.resolveMyType must be implemented.")
9191
}
9292

93-
interface MyType {
94-
fun field1(): String
95-
fun field2(): String?
93+
open class MyType {
94+
open fun field1(): String = throw NotImplementedError("MyType.field1 must be implemented.")
95+
open fun field2(): String? = throw NotImplementedError("MyType.field2 must be implemented.")
9696
}
9797
```
9898

@@ -102,12 +102,12 @@ Source code:
102102
import com.types.generated.MyType as MyTypeInterface
103103
import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
104104

105-
class MyQuery : Query, QueryInterface {
105+
class MyQuery : Query, QueryInterface() {
106106
override fun resolveMyType(input: String): MyType = MyType()
107107
}
108108

109109
@GraphQLIgnore
110-
class MyType : MyTypeInterface {
110+
class MyType : MyTypeInterface() {
111111
override fun field1(): String = myExpensiveCall1()
112112
override fun field2(): String? = myExpensiveCall2()
113113
}

src/definitions/object.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,8 @@ export function buildObjectTypeDefinition(
9898
const fieldNodes = typeInResolverInterfacesConfig
9999
? node.fields
100100
: fieldsWithArguments;
101-
const abstractModifier = constructor ? "abstract " : "";
102-
const keyWord = constructor ? "abstract class" : "interface";
103-
return `${annotations}${outputRestrictionAnnotation}${keyWord} ${name}${constructor}${interfaceInheritance} {
104-
${getDataClassMembers({ node, fieldNodes, schema, config, shouldGenerateFunctions, abstractModifier })}
101+
return `${annotations}${outputRestrictionAnnotation}open class ${name}${constructor}${interfaceInheritance} {
102+
${getDataClassMembers({ node, fieldNodes, schema, config, shouldGenerateFunctions })}
105103
}`;
106104
}
107105

@@ -115,14 +113,12 @@ function getDataClassMembers({
115113
fieldNodes,
116114
schema,
117115
config,
118-
abstractModifier,
119116
shouldGenerateFunctions,
120117
}: {
121118
node: ObjectTypeDefinitionNode;
122119
fieldNodes?: readonly FieldDefinitionNode[];
123120
schema: GraphQLSchema;
124121
config: CodegenConfigWithDefaults;
125-
abstractModifier?: string;
126122
shouldGenerateFunctions?: boolean;
127123
}) {
128124
return (fieldNodes ?? node.fields)
@@ -135,7 +131,6 @@ function getDataClassMembers({
135131
config,
136132
typeMetadata,
137133
shouldGenerateFunctions,
138-
abstractModifier,
139134
);
140135
})
141136
.join(`${shouldGenerateFunctions ? "" : ","}\n`);

src/helpers/build-field-definition.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,8 @@ export function buildFieldDefinition(
3232
config: CodegenConfigWithDefaults,
3333
typeMetadata: TypeMetadata,
3434
shouldGenerateFunctions?: boolean,
35-
abstractModifier: string = "",
3635
) {
37-
const modifier = buildFieldModifier(
38-
node,
39-
fieldNode,
40-
schema,
41-
config,
42-
abstractModifier,
43-
);
36+
const modifier = buildFieldModifier(node, fieldNode, schema, config);
4437
const fieldArguments = buildFieldArguments(node, fieldNode, schema, config);
4538
const fieldDefinition = `${modifier} ${fieldNode.name.value}${fieldArguments}`;
4639
const annotations = buildAnnotations({
@@ -56,7 +49,8 @@ export function buildFieldDefinition(
5649
);
5750
}
5851

59-
const defaultFunctionValue = `${typeMetadata.isNullable ? "?" : ""}`;
52+
const notImplementedError = ` = throw NotImplementedError("${node.name.value}.${fieldNode.name.value} must be implemented.")`;
53+
const defaultFunctionValue = `${typeMetadata.isNullable ? "?" : ""}${notImplementedError}`;
6054
const defaultValue = shouldGenerateFunctions
6155
? defaultFunctionValue
6256
: typeMetadata.defaultValue;
@@ -67,7 +61,7 @@ export function buildFieldDefinition(
6761
);
6862
const isCompletableFuture =
6963
typeInResolverInterfacesConfig?.classMethods === "COMPLETABLE_FUTURE";
70-
const completableFutureDefinition = `java.util.concurrent.CompletableFuture<${typeMetadata.typeName}${typeMetadata.isNullable ? "?" : ""}>`;
64+
const completableFutureDefinition = `java.util.concurrent.CompletableFuture<${typeMetadata.typeName}${typeMetadata.isNullable ? "?" : ""}>${notImplementedError}`;
7165
const field = indent(
7266
`${fieldDefinition}: ${isCompletableFuture ? completableFutureDefinition : defaultDefinition}`,
7367
2,
@@ -80,7 +74,6 @@ function buildFieldModifier(
8074
fieldNode: FieldDefinitionNode,
8175
schema: GraphQLSchema,
8276
config: CodegenConfigWithDefaults,
83-
abstractModifier: string,
8477
) {
8578
const typeInResolverInterfacesConfig = findTypeInResolverInterfacesConfig(
8679
node,
@@ -91,9 +84,8 @@ function buildFieldModifier(
9184
fieldNode,
9285
schema,
9386
);
94-
const overrideModifier = shouldOverrideField ? "override " : "";
9587
if (!typeInResolverInterfacesConfig && !fieldNode.arguments?.length) {
96-
return `${overrideModifier}val`;
88+
return shouldOverrideField ? "override val" : "val";
9789
}
9890
const functionModifier =
9991
typeInResolverInterfacesConfig?.classMethods === "SUSPEND"
@@ -102,8 +94,12 @@ function buildFieldModifier(
10294
if (node.kind === Kind.INTERFACE_TYPE_DEFINITION) {
10395
return `${functionModifier}fun`;
10496
}
105-
106-
return `${abstractModifier}${overrideModifier}${functionModifier}fun`;
97+
const isCompletableFuture =
98+
typeInResolverInterfacesConfig?.classMethods === "COMPLETABLE_FUTURE";
99+
if (shouldOverrideField && !isCompletableFuture) {
100+
return "override fun";
101+
}
102+
return `open ${functionModifier}fun`;
107103
}
108104

109105
function buildFieldArguments(

test/integration/Query.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import com.expediagroup.graphql.server.operations.Query
44
import graphql.schema.DataFetchingEnvironment
55
import test.integration.Query as QueryInterface
66

7-
class IntegrationTestQuery : Query, QueryInterface {
7+
class IntegrationTestQuery() : Query, QueryInterface() {
88
override fun testQuery(dataFetchingEnvironment: DataFetchingEnvironment): SomeType = SomeType()
99
}

test/unit/should_consolidate_input_and_output_types/expected.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ data class MyTypeToConsolidateInputParent(
6969
)
7070

7171
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
72-
interface MyTypeToConsolidateParent2 {
73-
fun field(input: MyTypeToConsolidate, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String?
72+
open class MyTypeToConsolidateParent2 {
73+
open fun field(input: MyTypeToConsolidate, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("MyTypeToConsolidateParent2.field must be implemented.")
7474
}
7575

7676
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])

test/unit/should_generate_classes_for_types_with_field_args/expected.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@ package com.kotlin.generated
33
import com.expediagroup.graphql.generator.annotations.*
44

55
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
6-
interface TypeWithOnlyFieldArgs {
7-
fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String?
8-
fun nonNullableResolver(arg: InputTypeForResolver, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String
6+
open class TypeWithOnlyFieldArgs {
7+
open fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("TypeWithOnlyFieldArgs.nullableResolver must be implemented.")
8+
open fun nonNullableResolver(arg: InputTypeForResolver, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("TypeWithOnlyFieldArgs.nonNullableResolver must be implemented.")
99
}
1010

1111
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
12-
abstract class HybridType(
12+
open class HybridType(
1313
val nullableField: String? = null,
1414
val nonNullableField: String
1515
) {
16-
abstract fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String?
17-
abstract fun nonNullableResolver(arg: InputTypeForResolver, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String
16+
open fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("HybridType.nullableResolver must be implemented.")
17+
open fun nonNullableResolver(arg: InputTypeForResolver, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("HybridType.nonNullableResolver must be implemented.")
1818
}
1919

2020
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
@@ -30,14 +30,14 @@ interface HybridInterface {
3030
}
3131

3232
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
33-
abstract class TypeImplementingInterface(
33+
open class TypeImplementingInterface(
3434
override val field1: String? = null,
3535
override val field2: String,
3636
val booleanField1: Boolean? = null,
3737
val booleanField2: Boolean = false,
3838
val integerField1: Int? = null,
3939
val integerField2: Int
4040
) : HybridInterface {
41-
abstract override fun nullableListResolver(arg1: Int?, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String?>?
42-
abstract override fun nonNullableListResolver(arg1: Int, arg2: Int?, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String>
41+
override fun nullableListResolver(arg1: Int?, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String?>? = throw NotImplementedError("TypeImplementingInterface.nullableListResolver must be implemented.")
42+
override fun nonNullableListResolver(arg1: Int, arg2: Int?, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String> = throw NotImplementedError("TypeImplementingInterface.nonNullableListResolver must be implemented.")
4343
}

test/unit/should_honor_resolverInterfaces_config/expected.kt

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,39 @@ package com.kotlin.generated
33
import com.expediagroup.graphql.generator.annotations.*
44

55
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
6-
interface MyIncludedResolverType {
7-
fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String?
8-
fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String
9-
fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String?
10-
fun nonNullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String
11-
fun nullableListResolver(arg1: Int? = null, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String?>?
12-
fun nonNullableListResolver(arg1: Int, arg2: Int? = null, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String>
6+
open class MyIncludedResolverType {
7+
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("MyIncludedResolverType.nullableField must be implemented.")
8+
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.")
10+
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.")
12+
open fun nonNullableListResolver(arg1: Int, arg2: Int? = null, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String> = throw NotImplementedError("MyIncludedResolverType.nonNullableListResolver must be implemented.")
1313
}
1414

1515
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
16-
interface MyIncludedResolverTypeWithNoFieldArgs {
17-
fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String?
18-
fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String
16+
open class MyIncludedResolverTypeWithNoFieldArgs {
17+
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("MyIncludedResolverTypeWithNoFieldArgs.nullableField must be implemented.")
18+
open fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("MyIncludedResolverTypeWithNoFieldArgs.nonNullableField must be implemented.")
1919
}
2020

2121
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
22-
interface MySuspendResolverType {
23-
suspend fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String?
24-
suspend fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String
25-
suspend fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String?
26-
suspend fun nonNullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String
27-
suspend fun nullableListResolver(arg1: Int? = null, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String?>?
28-
suspend fun nonNullableListResolver(arg1: Int, arg2: Int? = null, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String>
22+
open class MySuspendResolverType {
23+
open suspend fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("MySuspendResolverType.nullableField must be implemented.")
24+
open suspend fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("MySuspendResolverType.nonNullableField must be implemented.")
25+
open suspend fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("MySuspendResolverType.nullableResolver must be implemented.")
26+
open suspend fun nonNullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("MySuspendResolverType.nonNullableResolver must be implemented.")
27+
open suspend fun nullableListResolver(arg1: Int? = null, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String?>? = throw NotImplementedError("MySuspendResolverType.nullableListResolver must be implemented.")
28+
open suspend fun nonNullableListResolver(arg1: Int, arg2: Int? = null, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): List<String> = throw NotImplementedError("MySuspendResolverType.nonNullableListResolver must be implemented.")
2929
}
3030

3131
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
32-
interface MyCompletableFutureResolverType {
33-
fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String?>
34-
fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String>
35-
fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String?>
36-
fun nonNullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String>
37-
fun nullableListResolver(arg1: Int? = null, arg2: Int, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<List<String?>?>
38-
fun nonNullableListResolver(arg1: Int, arg2: Int? = null, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<List<String>>
32+
open class MyCompletableFutureResolverType {
33+
open fun nullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String?> = throw NotImplementedError("MyCompletableFutureResolverType.nullableField must be implemented.")
34+
open fun nonNullableField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String> = throw NotImplementedError("MyCompletableFutureResolverType.nonNullableField must be implemented.")
35+
open fun nullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String?> = throw NotImplementedError("MyCompletableFutureResolverType.nullableResolver must be implemented.")
36+
open fun nonNullableResolver(arg: String, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String> = throw NotImplementedError("MyCompletableFutureResolverType.nonNullableResolver must be implemented.")
37+
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.")
38+
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.")
3939
}
4040

4141
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])

0 commit comments

Comments
 (0)