From 1958e54e9012d553a952ae3d070b6fab7e8289f9 Mon Sep 17 00:00:00 2001 From: Paul Bakker Date: Mon, 19 Apr 2021 16:53:59 -0700 Subject: [PATCH 1/2] Fix to prevent stackoverflow when a cycle in an input type exists. --- .../dgs/codegen/RequiredTypeCollector.kt | 6 ++-- .../graphql/dgs/codegen/ClientApiGenTest.kt | 36 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/RequiredTypeCollector.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/RequiredTypeCollector.kt index ed7d33543..f718d26b5 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/RequiredTypeCollector.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/RequiredTypeCollector.kt @@ -42,16 +42,18 @@ class RequiredTypeCollector( NodeTraverser().postOrder( object : NodeVisitorStub() { + val visitedTypes = mutableSetOf() + override fun visitInputObjectTypeDefinition( node: InputObjectTypeDefinition, context: TraverserContext>> ): TraversalControl { required += node.name - node.inputValueDefinitions.forEach { + node.inputValueDefinitions.filter { !visitedTypes.contains(it.name) }.forEach { + visitedTypes.add(it.name) it.type.findTypeDefinition(document)?.accept(context, this) } - return TraversalControl.CONTINUE } diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/ClientApiGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/ClientApiGenTest.kt index 51dcba285..db3c752de 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/ClientApiGenTest.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/ClientApiGenTest.kt @@ -118,6 +118,42 @@ class ClientApiGenTest { assertCompilesJava(codeGenResult.clientProjections.plus(codeGenResult.queryTypes).plus(codeGenResult.dataTypes)) } + @Test + fun generateRecursiveInputTypes() { + + val schema = """ + type Query { + movies(filter: MovieQuery): [String] + } + + input MovieQuery { + booleanQuery: BooleanQuery! + titleFilter: String + } + + input BooleanQuery { + first: MovieQuery! + second: MovieQuery! + } + """.trimIndent() + + val codeGenResult = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + generateDataTypes = false, + generateClientApi = true, + includeQueries = mutableSetOf("movies") + ) + ).generate() as CodeGenResult + + assertThat(codeGenResult.dataTypes.size).isEqualTo(2) + assertThat(codeGenResult.dataTypes[0].typeSpec.name).isEqualTo("MovieQuery") + assertThat(codeGenResult.dataTypes[1].typeSpec.name).isEqualTo("BooleanQuery") + + assertCompilesJava(codeGenResult.dataTypes) + } + @Test fun generateMutationAddsNullChecksDuringInit() { From 3e47a7e69aec28a795e4dffc24475a47019030f8 Mon Sep 17 00:00:00 2001 From: Paul Bakker Date: Mon, 19 Apr 2021 17:01:55 -0700 Subject: [PATCH 2/2] Added test for Kotlin for recursive input types --- .../dgs/codegen/KotlinClientApiGenTest.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinClientApiGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinClientApiGenTest.kt index e4a87c661..ec4e97291 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinClientApiGenTest.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinClientApiGenTest.kt @@ -125,6 +125,42 @@ class KotlinClientApiGenTest { assertCompilesKotlin(codeGenResult.clientProjections) } + @Test + fun generateRecursiveInputTypes() { + + val schema = """ + type Query { + movies(filter: MovieQuery): [String] + } + + input MovieQuery { + booleanQuery: BooleanQuery! + titleFilter: String + } + + input BooleanQuery { + first: MovieQuery! + second: MovieQuery! + } + """.trimIndent() + + val codeGenResult = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + language = Language.KOTLIN, + generateClientApi = true, + ) + ).generate() as KotlinCodeGenResult + + assertThat(codeGenResult.dataTypes.size).isEqualTo(2) + val movieQuery = codeGenResult.dataTypes[0].members[0] as TypeSpec + assertThat(movieQuery.name).isEqualTo("MovieQuery") + + val booleanQuery = codeGenResult.dataTypes[1].members[0] as TypeSpec + assertThat(booleanQuery.name).isEqualTo("BooleanQuery") + } + @Test fun interfaceReturnTypes() {