Skip to content

Commit d60e439

Browse files
authored
[generator] allow interfaces to implement other interfaces (#732)
Adding support for creating schemas where interfaces implement other interfaces Resolves: #589
1 parent a92102e commit d60e439

File tree

6 files changed

+35
-43
lines changed

6 files changed

+35
-43
lines changed

graphql-kotlin-schema-generator/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ tasks {
2828
limit {
2929
counter = "BRANCH"
3030
value = "COVEREDRATIO"
31-
minimum = "0.96".toBigDecimal()
31+
minimum = "0.95".toBigDecimal()
3232
}
3333
}
3434
}

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/exceptions/InvalidInterfaceException.kt

Lines changed: 0 additions & 27 deletions
This file was deleted.

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/extensions/kClassExtensions.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,8 @@ internal fun KClass<*>.getValidSuperclasses(hooks: SchemaGeneratorHooks): List<K
5151
this.superclasses
5252
.filter { hooks.isValidSuperclass(it) }
5353
.filter { kClass -> superclassFilters.all { it.invoke(kClass) } }
54-
.ifEmpty {
55-
this.superclasses.flatMap { it.getValidSuperclasses(hooks) }
56-
}
54+
.plus(this.superclasses.flatMap { it.getValidSuperclasses(hooks) })
55+
.distinct()
5756

5857
internal fun KClass<*>.findConstructorParameter(name: String): KParameter? =
5958
this.primaryConstructor?.findParameterByName(name)

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateInterface.kt

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package com.expediagroup.graphql.generator.types
1818

19-
import com.expediagroup.graphql.exceptions.InvalidInterfaceException
19+
import com.expediagroup.graphql.extensions.unwrapType
2020
import com.expediagroup.graphql.generator.SchemaGenerator
2121
import com.expediagroup.graphql.generator.extensions.getGraphQLDescription
2222
import com.expediagroup.graphql.generator.extensions.getSimpleName
@@ -27,15 +27,11 @@ import com.expediagroup.graphql.generator.extensions.isGraphQLIgnored
2727
import com.expediagroup.graphql.generator.extensions.safeCast
2828
import graphql.TypeResolutionEnvironment
2929
import graphql.schema.GraphQLInterfaceType
30+
import graphql.schema.GraphQLTypeReference
3031
import kotlin.reflect.KClass
3132
import kotlin.reflect.full.createType
3233

3334
internal fun generateInterface(generator: SchemaGenerator, kClass: KClass<*>): GraphQLInterfaceType {
34-
// Interfaces can not implement another interface in GraphQL
35-
if (kClass.getValidSuperclasses(generator.config.hooks).isNotEmpty()) {
36-
throw InvalidInterfaceException(klazz = kClass)
37-
}
38-
3935
val builder = GraphQLInterfaceType.newInterface()
4036

4137
builder.name(kClass.getSimpleName())
@@ -45,6 +41,15 @@ internal fun generateInterface(generator: SchemaGenerator, kClass: KClass<*>): G
4541
builder.withDirective(it)
4642
}
4743

44+
kClass.getValidSuperclasses(generator.config.hooks)
45+
.map { generateGraphQLType(generator, it.createType()) }
46+
.forEach {
47+
when (val unwrappedType = it.unwrapType()) {
48+
is GraphQLTypeReference -> builder.withInterface(unwrappedType)
49+
is GraphQLInterfaceType -> builder.withInterface(unwrappedType)
50+
}
51+
}
52+
4853
kClass.getValidProperties(generator.config.hooks)
4954
.forEach { builder.field(generateProperty(generator, it, kClass)) }
5055

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ internal class GenerateInterfaceTest : TypeTestHelper() {
5454
}
5555

5656
@Test
57-
fun `absctract classes generate interfaces`() {
57+
fun `abstract classes generate interfaces`() {
5858
assertEquals(0, generator.additionalTypes.size)
5959
val result = generateInterface(generator, Shape::class) as? GraphQLInterfaceType
6060
assertEquals("Shape", result?.name)

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

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,36 @@
1717
package com.expediagroup.graphql.test.integration
1818

1919
import com.expediagroup.graphql.TopLevelObject
20-
import com.expediagroup.graphql.exceptions.InvalidInterfaceException
2120
import com.expediagroup.graphql.testSchemaConfig
2221
import com.expediagroup.graphql.toSchema
22+
import graphql.schema.GraphQLInterfaceType
2323
import org.junit.jupiter.api.Test
24-
import kotlin.test.assertFailsWith
24+
import kotlin.test.assertEquals
25+
import kotlin.test.assertNotNull
2526

2627
class InterfaceOfInterfaceTest {
2728

2829
@Test
2930
fun `interface of interface`() {
3031
val queries = listOf(TopLevelObject(InterfaceOfInterfaceQuery()))
32+
val schema = toSchema(queries = queries, config = testSchemaConfig)
33+
assertEquals(expected = 1, actual = schema.queryType.fieldDefinitions.size)
3134

32-
assertFailsWith(InvalidInterfaceException::class) {
33-
toSchema(queries = queries, config = testSchemaConfig)
34-
}
35+
val implementation = schema.getObjectType("MyClass")
36+
assertNotNull(implementation)
37+
val interfaces = implementation.interfaces
38+
assertEquals(2, interfaces.size)
39+
assertNotNull(interfaces.firstOrNull { it.name == "FirstLevel" })
40+
assertNotNull(interfaces.firstOrNull { it.name == "SecondLevel" })
41+
42+
val secondLevelInterface = schema.getType("SecondLevel") as? GraphQLInterfaceType
43+
assertNotNull(secondLevelInterface)
44+
val interfaceOfInterface = secondLevelInterface.interfaces
45+
assertEquals(1, interfaceOfInterface.size)
46+
assertNotNull(interfaceOfInterface.firstOrNull { it.name == "FirstLevel" })
47+
48+
val firstLevelInterface = schema.getType("FirstLevel") as? GraphQLInterfaceType
49+
assertNotNull(firstLevelInterface)
3550
}
3651

3752
interface FirstLevel {

0 commit comments

Comments
 (0)