Skip to content

fix: abstract classes should generate interface #221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -30,4 +30,4 @@ class PolymorphicQuery: Query {
"right" -> RightHand(12)
else -> LeftHand("hello world")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ internal open class TypeBuilder constructor(protected val generator: SchemaGener
kClass.isEnum() -> @Suppress("UNCHECKED_CAST") (generator.enumType(kClass as KClass<Enum<*>>))
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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<SuperclassFilter> = listOf(isPublic, isInterface, isNotUnion)
33 changes: 30 additions & 3 deletions src/test/kotlin/com/expedia/graphql/generator/PolymorphicTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand All @@ -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)
Expand All @@ -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 {
Expand Down Expand Up @@ -128,7 +142,7 @@ data class Arm(
val value: Boolean
) : BodyPart

class QueryWithInterfaceAnUnion {
class QueryWithInterfaceAndUnion {
fun product(): Product = Car("DB9", "black")
}

Expand Down Expand Up @@ -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()