Skip to content

Commit 22d15df

Browse files
committed
feat(codegen): refactor field resolvers
1 parent be28a95 commit 22d15df

File tree

3 files changed

+43
-63
lines changed

3 files changed

+43
-63
lines changed

graphql-kotlin-toolkit-codegen/src/main/kotlin/com/auritylab/graphql/kotlin/toolkit/codegen/generator/fieldResolver/AbstractFieldResolverGenerator.kt

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,38 @@ internal abstract class AbstractFieldResolverGenerator(
3333
kotlinTypeMapper: KotlinTypeMapper,
3434
generatedMapper: GeneratedMapper
3535
) : AbstractClassGenerator(options, kotlinTypeMapper, generatedMapper) {
36-
protected val fieldKotlinType = getKotlinType(field.type)
37-
36+
/**
37+
* Describes the [ClassName] for the actual class which describes the field resolver.
38+
* This will be used on the [TypeSpec] of [buildFieldResolverClass].
39+
*/
3840
override val fileClassName: ClassName = generatedMapper.getGeneratedFieldResolverClassName(container, field)
41+
42+
/**
43+
* Describes the [TypeName] for the return type of the field.
44+
*/
45+
protected val fieldTypeName = getKotlinType(field.type)
46+
47+
/**
48+
* Describes the actual return [TypeName] which will be returned by the "graphql.schema.DataFetcher", which will
49+
* be implemented, by this field resolver interface. This can be overridden by subclasses to adjust the
50+
*/
51+
protected open val returnTypeName: TypeName = fieldTypeName
52+
3953
protected val dataFetchingEnvironmentClassName = ClassName("graphql.schema", "DataFetchingEnvironment")
40-
protected val dataFetcherClassName = ClassName("graphql.schema", "DataFetcher").parameterizedBy(fieldKotlinType)
54+
55+
/**
56+
* Describes the "graphql.schema.DataFetcher" [TypeName] which is parameterized by the [returnTypeName].
57+
*/
58+
protected val parameterizedDataFetcherTypeName: TypeName
59+
get() = ClassName("graphql.schema", "DataFetcher").parameterizedBy(returnTypeName)
60+
4161
protected val contextClassName = options.globalContext?.let { ClassName.bestGuess(it) } ?: ANY
4262

4363
override fun build(builder: FileSpec.Builder) {
4464
val typeBuilder = TypeSpec.interfaceBuilder(fileClassName)
4565

66+
typeBuilder.addSuperinterface(parameterizedDataFetcherTypeName)
67+
4668
// Call the build methods with the type builder.
4769
buildFieldResolverClass(typeBuilder)
4870

@@ -58,7 +80,8 @@ internal abstract class AbstractFieldResolverGenerator(
5880
}
5981

6082
/**
61-
* Will build the [TypeSpec] which represents the field resolver itself.
83+
* Will continue the building of the resolver. Some types, functions, etc. have already been.
84+
* This shall only be used for additionally required types, functions, etc.
6285
*/
6386
protected abstract fun buildFieldResolverClass(builder: TypeSpec.Builder)
6487

@@ -79,11 +102,12 @@ internal abstract class AbstractFieldResolverGenerator(
79102
.getImplementers(container)
80103
.map { getKotlinType(it) }
81104

105+
// Fetch the first type to have a reference type to check against.
82106
val firstType = implementersTypes.first()
83-
if (implementersTypes.all { it == firstType })
84-
firstType
85-
else
86-
ANY
107+
108+
// If all implementers have the same type as the first, the reference type can be returned.
109+
if (implementersTypes.all { it == firstType }) firstType
110+
else ANY
87111
} else throw UnsupportedOperationException()
88112

89113
/**

graphql-kotlin-toolkit-codegen/src/main/kotlin/com/auritylab/graphql/kotlin/toolkit/codegen/generator/fieldResolver/FieldResolverGenerator.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,14 @@ internal class FieldResolverGenerator(
3434
) {
3535
override fun buildFieldResolverClass(builder: TypeSpec.Builder) {
3636
builder
37-
.addSuperinterface(dataFetcherClassName)
3837
.addType(environmentTypeSpec)
3938

4039
builder.addFunction(
4140
FunSpec.builder("resolve")
4241
.addModifiers(KModifier.ABSTRACT)
4342
.addParameters(field.arguments.map { ParameterSpec(it.name, getKotlinType(it.type, it)) })
4443
.addParameter("env", generatedMapper.getFieldResolverEnvironment(container, field))
45-
.returns(fieldKotlinType).build()
44+
.returns(fieldTypeName).build()
4645
)
4746

4847
builder.addFunction(FunSpec.builder("get")

graphql-kotlin-toolkit-codegen/src/main/kotlin/com/auritylab/graphql/kotlin/toolkit/codegen/generator/fieldResolver/PaginationFieldResolverGenerator.kt

Lines changed: 10 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,16 @@ internal class PaginationFieldResolverGenerator(
4747
private val unwrappedReturnKotlinType = getKotlinType(unwrappedReturnType)
4848
private val resolveReturnType: TypeName = getKotlinType(field.type, null, LIST)
4949

50+
override val returnTypeName: TypeName = generatedMapper
51+
.getPaginationConnectionClassName()
52+
.parameterizedBy(unwrappedReturnKotlinType)
53+
5054
override fun buildFieldResolverClass(builder: TypeSpec.Builder) {
5155
builder
5256
.addType(environmentTypeSpec)
5357
.addType(resultHolderTypeSpec)
5458
.addFunction(resolveCursorFunSpec)
5559
.addFunction(resultFunSpec)
56-
.addFunction(buildEdgeFunSpec)
57-
.addFunction(buildConnectionFunSpec)
58-
.addFunction(buildPageInfoFunSpec)
59-
.addSuperinterface(
60-
ClassName(
61-
"graphql.schema",
62-
"DataFetcher"
63-
).parameterizedBy(
64-
generatedMapper.getPaginationConnectionClassName().parameterizedBy(unwrappedReturnKotlinType)
65-
)
66-
)
6760

6861
builder.addFunction(
6962
FunSpec.builder("resolve")
@@ -95,9 +88,12 @@ internal class PaginationFieldResolverGenerator(
9588
)
9689
getFunSpec.addStatement("val result = resolve(${resolveArgs}env = internalEnv)")
9790

98-
getFunSpec.addStatement("val edges = result.data.map { _buildEdge(it, internalEnv) }")
99-
getFunSpec.addStatement("val pageInfo = _buildPageInfo(result.hasNextPage, result.hasPreviousPage, edges.first().cursor, edges.last().cursor)")
100-
getFunSpec.addStatement("return _buildConnection(edges, pageInfo)")
91+
getFunSpec.addStatement("val edges = result.data.map { %T(it, resolveCursor(it, internalEnv)) }", generatedMapper.getPaginationEdgeClassName())
92+
getFunSpec.addStatement(
93+
"val pageInfo = %T(result.hasNextPage, result.hasPreviousPage, edges.first().cursor, edges.last().cursor)",
94+
generatedMapper.getPaginationPageInfoClassName()
95+
)
96+
getFunSpec.addStatement("return %T(edges, pageInfo)", generatedMapper.getPaginationConnectionClassName())
10197
}
10298
.build())
10399
}
@@ -174,43 +170,4 @@ internal class PaginationFieldResolverGenerator(
174170
.addProperty(PropertySpec.builder("hasPreviousPage", BOOLEAN).initializer("hasPreviousPage").build())
175171
.addProperty(PropertySpec.builder("hasNextPage", BOOLEAN).initializer("hasNextPage").build())
176172
.build()
177-
178-
private val buildEdgeFunSpec = FunSpec.builder("_buildEdge")
179-
.addModifiers(KModifier.PRIVATE)
180-
.addParameter("data", unwrappedReturnKotlinType)
181-
.addParameter("env", generatedMapper.getFieldResolverEnvironment(container, field))
182-
.returns(generatedMapper.getPaginationEdgeClassName().parameterizedBy(unwrappedReturnKotlinType))
183-
.addCode(
184-
CodeBlock.of(
185-
"return %T(data, resolveCursor(data, env))",
186-
generatedMapper.getPaginationEdgeClassName()
187-
)
188-
)
189-
.build()
190-
191-
private val buildConnectionFunSpec = FunSpec.builder("_buildConnection")
192-
.addModifiers(KModifier.PRIVATE)
193-
.addParameter(
194-
"edges",
195-
LIST.parameterizedBy(
196-
generatedMapper.getPaginationEdgeClassName().parameterizedBy(unwrappedReturnKotlinType)
197-
)
198-
)
199-
.addParameter("pageInfo", generatedMapper.getPaginationPageInfoClassName())
200-
.returns(generatedMapper.getPaginationConnectionClassName().parameterizedBy(unwrappedReturnKotlinType))
201-
.addCode(CodeBlock.of("return %T(edges, pageInfo)", generatedMapper.getPaginationConnectionClassName()))
202-
.build()
203-
204-
private val buildPageInfoFunSpec = FunSpec.builder("_buildPageInfo")
205-
.addModifiers(KModifier.PRIVATE)
206-
.addParameter("hasNextPage", BOOLEAN)
207-
.addParameter("hasPreviousPage", BOOLEAN)
208-
.addParameter("startCursor", STRING)
209-
.addParameter("endCursor", STRING)
210-
.returns(generatedMapper.getPaginationPageInfoClassName())
211-
.addStatement(
212-
"return %T(hasNextPage, hasPreviousPage, startCursor, endCursor)",
213-
generatedMapper.getPaginationPageInfoClassName()
214-
)
215-
.build()
216173
}

0 commit comments

Comments
 (0)