From 087872378426c0357f5ef83d58b11d5c6af550b6 Mon Sep 17 00:00:00 2001 From: Dariusz Kuc <9501705+dariuszkuc@users.noreply.github.com> Date: Mon, 13 May 2019 13:55:54 -0500 Subject: [PATCH] fix: abstract classes should generate interface (#221) Fixes: https://github.com/ExpediaDotCom/graphql-kotlin/issues/220 --- .../graphql/sample/query/PolymorphicQuery.kt | 4 +-- .../expedia/graphql/generator/TypeBuilder.kt | 2 +- .../generator/filters/superclassFilters.kt | 2 +- .../graphql/generator/PolymorphicTests.kt | 33 +++++++++++++++++-- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/example/src/main/kotlin/com/expedia/graphql/sample/query/PolymorphicQuery.kt b/example/src/main/kotlin/com/expedia/graphql/sample/query/PolymorphicQuery.kt index 9b5afafdd7..711c7c4c57 100644 --- a/example/src/main/kotlin/com/expedia/graphql/sample/query/PolymorphicQuery.kt +++ b/example/src/main/kotlin/com/expedia/graphql/sample/query/PolymorphicQuery.kt @@ -1,9 +1,9 @@ package com.expedia.graphql.sample.query import com.expedia.graphql.annotations.GraphQLDescription -import com.expedia.graphql.sample.model.BodyPart import com.expedia.graphql.sample.model.Animal import com.expedia.graphql.sample.model.AnimalType +import com.expedia.graphql.sample.model.BodyPart import com.expedia.graphql.sample.model.Cat import com.expedia.graphql.sample.model.Dog import com.expedia.graphql.sample.model.LeftHand @@ -30,4 +30,4 @@ class PolymorphicQuery: Query { "right" -> RightHand(12) else -> LeftHand("hello world") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/expedia/graphql/generator/TypeBuilder.kt b/src/main/kotlin/com/expedia/graphql/generator/TypeBuilder.kt index ed7b6d3de8..01fc5429ce 100644 --- a/src/main/kotlin/com/expedia/graphql/generator/TypeBuilder.kt +++ b/src/main/kotlin/com/expedia/graphql/generator/TypeBuilder.kt @@ -51,7 +51,7 @@ internal open class TypeBuilder constructor(protected val generator: SchemaGener kClass.isEnum() -> @Suppress("UNCHECKED_CAST") (generator.enumType(kClass as KClass>)) kClass.isListType() -> generator.listType(type, inputType) kClass.isUnion() -> generator.unionType(kClass) - kClass.isInterface() -> generator.interfaceType(kClass) + kClass.isInterface() || kClass.isAbstract -> generator.interfaceType(kClass) inputType -> generator.inputObjectType(kClass) else -> generator.objectType(kClass) } diff --git a/src/main/kotlin/com/expedia/graphql/generator/filters/superclassFilters.kt b/src/main/kotlin/com/expedia/graphql/generator/filters/superclassFilters.kt index db5500226c..5ddc59cba7 100644 --- a/src/main/kotlin/com/expedia/graphql/generator/filters/superclassFilters.kt +++ b/src/main/kotlin/com/expedia/graphql/generator/filters/superclassFilters.kt @@ -8,7 +8,7 @@ import kotlin.reflect.KClass private typealias SuperclassFilter = (KClass<*>) -> Boolean private val isPublic: SuperclassFilter = { it.isPublic() } -private val isInterface: SuperclassFilter = { it.isInterface() } +private val isInterface: SuperclassFilter = { it.isInterface() || it.isAbstract } private val isNotUnion: SuperclassFilter = { it.isUnion().not() } internal val superclassFilters: List = listOf(isPublic, isInterface, isNotUnion) diff --git a/src/test/kotlin/com/expedia/graphql/generator/PolymorphicTests.kt b/src/test/kotlin/com/expedia/graphql/generator/PolymorphicTests.kt index e0610ddeb6..b5955eda71 100644 --- a/src/test/kotlin/com/expedia/graphql/generator/PolymorphicTests.kt +++ b/src/test/kotlin/com/expedia/graphql/generator/PolymorphicTests.kt @@ -4,6 +4,7 @@ import com.expedia.graphql.TopLevelObject import com.expedia.graphql.exceptions.InvalidInputFieldTypeException import com.expedia.graphql.testSchemaConfig import com.expedia.graphql.toSchema +import graphql.schema.GraphQLInterfaceType import graphql.schema.GraphQLObjectType import graphql.schema.GraphQLUnionType import org.junit.jupiter.api.Assertions.assertThrows @@ -35,7 +36,7 @@ internal class PolymorphicTests { fun `SchemaGenerator can expose an interface and its implementations`() { val schema = toSchema(queries = listOf(TopLevelObject(QueryWithInterface())), config = testSchemaConfig) - val interfaceType = schema.getType("AnInterface") + val interfaceType = schema.getType("AnInterface") as? GraphQLInterfaceType assertNotNull(interfaceType) val implementationType = schema.getObjectType("AnImplementation") @@ -60,7 +61,7 @@ internal class PolymorphicTests { @Test fun `Object types implementing union and interfaces are only created once`() { - val schema = toSchema(queries = listOf(TopLevelObject(QueryWithInterfaceAnUnion())), config = testSchemaConfig) + val schema = toSchema(queries = listOf(TopLevelObject(QueryWithInterfaceAndUnion())), config = testSchemaConfig) val carType = schema.getType("Car") as? GraphQLObjectType assertNotNull(carType) @@ -79,6 +80,19 @@ internal class PolymorphicTests { val personType = schema.getType("Person") assertNotNull(personType) } + + @Test + fun `Abstract classes should be converted to interfaces`() { + val schema = toSchema(queries = listOf(TopLevelObject(QueryWithAbstract())), config = testSchemaConfig) + + val abstractInterface = schema.getType("MyAbstract") as? GraphQLInterfaceType + assertNotNull(abstractInterface) + + val classWithBaseAbstractType = schema.getObjectType("MyClass") + assertNotNull(classWithBaseAbstractType) + assertEquals(1, classWithBaseAbstractType.interfaces.size) + assertEquals(classWithBaseAbstractType.interfaces.first(), abstractInterface) + } } class QueryWithInterface { @@ -128,7 +142,7 @@ data class Arm( val value: Boolean ) : BodyPart -class QueryWithInterfaceAnUnion { +class QueryWithInterfaceAndUnion { fun product(): Product = Car("DB9", "black") } @@ -156,3 +170,16 @@ data class Father( val dadJoke: String, override val child: Person? ) : Person + +class QueryWithAbstract { + fun query(): MyAbstract = MyClass(id = 1, name = "JUnit") + + fun queryImplementation(): MyClass = MyClass(id = 1, name = "JUnit_2") +} + +@Suppress("UnnecessaryAbstractClass") +abstract class MyAbstract { + abstract val id: Int +} + +data class MyClass(override val id: Int, val name: String) : MyAbstract()