From bdbc209538e9058f1690ee4c841f43d1a2cd8c5a Mon Sep 17 00:00:00 2001 From: Ivan Savytskyi Date: Mon, 2 Sep 2019 20:44:26 -0400 Subject: [PATCH] Fix issue with checking if one type is assignable from another (#1570) This query should not fail ``` query TestQuery { search(text: "test") { ... on Character { ... ``` where `Character` is interface with `Human, Droid` possible types and `SearchResult` is a UNION type with `Human, Droid, Starship` possible types. --- .../compiler/parser/GraphQLDocumentParser.kt | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/parser/GraphQLDocumentParser.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/parser/GraphQLDocumentParser.kt index df532bf9868..847bead54b3 100644 --- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/parser/GraphQLDocumentParser.kt +++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/parser/GraphQLDocumentParser.kt @@ -754,14 +754,46 @@ class GraphQLDocumentParser(val schema: Schema) { } private fun Schema.Type.isAssignableFrom(other: Schema.Type): Boolean { + if (name == other.name) { + return true + } return when (this) { - is Schema.Type.Union -> name == other.name || (possibleTypes ?: emptyList()).mapNotNull { it.rawType.name }.contains(other.name) - is Schema.Type.Interface -> name == other.name || (possibleTypes ?: emptyList()).mapNotNull { it.rawType.name }.contains(other.name) - is Schema.Type.Object -> name == other.name + is Schema.Type.Union -> possibleTypes().intersect(other.possibleTypes()).isNotEmpty() + is Schema.Type.Interface -> { + val possibleTypes = (possibleTypes ?: emptyList()).mapNotNull { it.rawType.name } + possibleTypes.contains(other.name) || possibleTypes.any { typeName -> + val schemaType = schema[typeName] ?: throw throw GraphQLParseException( + message = "Unknown possible type `$typeName` for INTERFACE `$name`" + ) + schemaType.isAssignableFrom(other) + } + } else -> false } } + private fun Schema.Type.possibleTypes(): Set { + return when (this) { + is Schema.Type.Union -> (possibleTypes ?: emptyList()).flatMap { typeRef -> + val typeName = typeRef.rawType.name!! + val schemaType = schema[typeName] ?: throw throw GraphQLParseException( + message = "Unknown possible type `$typeName` for UNION `$name`" + ) + schemaType.possibleTypes() + }.toSet() + + is Schema.Type.Interface -> (possibleTypes ?: emptyList()).flatMap { typeRef -> + val typeName = typeRef.rawType.name!! + val schemaType = schema[typeName] ?: throw throw GraphQLParseException( + message = "Unknown possible type `$typeName` for INTERFACE `$name`" + ) + schemaType.possibleTypes() + }.toSet() + + else -> setOf(name) + } + } + private fun String.isGraphQLTypeAssignableFrom(otherType: String): Boolean { var i = 0 var j = 0