Skip to content

Commit 14bdf9d

Browse files
author
Samuel Vazquez
committed
fix: register getter on runtime when field is of a parent type
1 parent 48bf99f commit 14bdf9d

File tree

3 files changed

+48
-7
lines changed

3 files changed

+48
-7
lines changed

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/KotlinDataFetcherFactoryProvider.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ open class SimpleKotlinDataFetcherFactoryProvider : KotlinDataFetcherFactoryProv
6666
}
6767

6868
/**
69-
* [SimpleSingletonKotlinDataFetcherFactoryProvider] is a specialization of [SimpleKotlinDataFetcherFactoryProvider] that will provide a
69+
* [SimpleSingletonKotlinDataFetcherFactoryProvider] is a specialization of [SimpleKotlinDataFetcherFactoryProvider] that will provide
7070
* a [SingletonPropertyDataFetcher] that should be used to target property resolutions without allocating a DataFetcher per property
7171
*/
7272
open class SimpleSingletonKotlinDataFetcherFactoryProvider : SimpleKotlinDataFetcherFactoryProvider() {
7373
override fun propertyDataFetcherFactory(kClass: KClass<*>, kProperty: KProperty<*>): DataFetcherFactory<Any?> =
74-
SingletonPropertyDataFetcher.getFactoryAndRegister(kClass, kProperty)
74+
SingletonPropertyDataFetcher.factory.also {
75+
SingletonPropertyDataFetcher.register(kClass, kProperty)
76+
}
7577
}

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/SingletonPropertyDataFetcher.kt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,26 @@ import graphql.schema.DataFetcherFactory
55
import graphql.schema.DataFetchingEnvironment
66
import graphql.schema.GraphQLFieldDefinition
77
import graphql.schema.LightDataFetcher
8+
import org.slf4j.LoggerFactory
89
import java.util.concurrent.ConcurrentHashMap
910
import java.util.function.Supplier
1011
import kotlin.reflect.KClass
1112
import kotlin.reflect.KProperty
13+
import kotlin.reflect.full.memberProperties
1214

1315
/**
1416
* Singleton Property [DataFetcher] that stores references to underlying properties getters.
1517
*/
1618
internal object SingletonPropertyDataFetcher : LightDataFetcher<Any?> {
1719

18-
private val factory: DataFetcherFactory<Any?> = DataFetcherFactory<Any?> { SingletonPropertyDataFetcher }
19-
20+
private val logger = LoggerFactory.getLogger(SingletonPropertyDataFetcher::class.java)
21+
val factory: DataFetcherFactory<Any?> = DataFetcherFactory<Any?> { SingletonPropertyDataFetcher }
2022
private val getters: ConcurrentHashMap<String, KProperty.Getter<*>> = ConcurrentHashMap()
2123

22-
fun getFactoryAndRegister(kClass: KClass<*>, kProperty: KProperty<*>): DataFetcherFactory<Any?> {
24+
fun register(kClass: KClass<*>, kProperty: KProperty<*>) {
2325
getters.computeIfAbsent("${kClass.java.name}.${kProperty.name}") {
2426
kProperty.getter
2527
}
26-
return factory
2728
}
2829

2930
override fun get(
@@ -32,7 +33,17 @@ internal object SingletonPropertyDataFetcher : LightDataFetcher<Any?> {
3233
environmentSupplier: Supplier<DataFetchingEnvironment>
3334
): Any? =
3435
sourceObject?.let {
35-
getters["${sourceObject.javaClass.name}.${fieldDefinition.name}"]?.call(sourceObject)
36+
getters["${sourceObject.javaClass.name}.${fieldDefinition.name}"]?.call(sourceObject) ?: run {
37+
sourceObject::class.memberProperties
38+
.find { it.name == fieldDefinition.name }
39+
?.let { kProperty ->
40+
kProperty.getter.call(sourceObject).also {
41+
register(sourceObject::class, kProperty)
42+
}
43+
}
44+
} ?: run {
45+
logger.error("getter method not found: ${sourceObject.javaClass.name}.${fieldDefinition.name}")
46+
}
3647
}
3748

3849
override fun get(environment: DataFetchingEnvironment): Any? =

generator/graphql-kotlin-schema-generator/src/test/kotlin/com/expediagroup/graphql/generator/ToSchemaTest.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,22 @@ class ToSchemaTest {
8686
assertEquals(1, geo?.get("query")?.get("id"))
8787
}
8888

89+
@ParameterizedTest(name = "{index} ==> {1}")
90+
@MethodSource("toSchemaTestArguments")
91+
fun `SchemaGenerator generates resolvers for parent classes`(provider: KotlinDataFetcherFactoryProvider, name: String) {
92+
val schema = toSchema(
93+
queries = listOf(TopLevelObject(QueryObject())),
94+
mutations = listOf(TopLevelObject(MutationObject())),
95+
config = testSchemaConfig(provider)
96+
)
97+
val graphQL = GraphQL.newGraphQL(schema).build()
98+
99+
val result = graphQL.execute(" { range { start { day } end { day } } }")
100+
val data: Map<String, Map<String, Map<String, Any>>>? = result.getData()
101+
assertEquals(30, data?.get("range")?.get("start")?.get("day"))
102+
assertEquals(14, data?.get("range")?.get("end")?.get("day"))
103+
}
104+
89105
@ParameterizedTest(name = "{index} ==> {1}")
90106
@MethodSource("toSchemaTestArguments")
91107
fun `SchemaGenerator generates a simple GraphQL schema with default builder`(provider: KotlinDataFetcherFactoryProvider, name: String) {
@@ -405,9 +421,21 @@ class ToSchemaTest {
405421
fun foo(): String = "bar"
406422
}
407423

424+
open class ParentDate(val day: Int, val month: Int, val year: Int)
425+
426+
data class DateRange(val start: ParentDate, val end: ParentDate)
427+
428+
class ChildDate(day: Int, month: Int, year: Int) : ParentDate(day, month, year)
429+
408430
class QueryObject {
409431
@GraphQLDescription("A GraphQL query method")
410432
fun query(@GraphQLDescription("A GraphQL value") value: Int): Geography = Geography(value, GeoType.CITY, listOf())
433+
fun range(): DateRange {
434+
return DateRange(
435+
ChildDate(30, 5, 1992),
436+
ChildDate(14, 6, 1992),
437+
)
438+
}
411439
}
412440

413441
class QueryWithIgnored {

0 commit comments

Comments
 (0)