diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/ConstantsGenerator.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/ConstantsGenerator.kt index fbf0db9d..1ce000a5 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/ConstantsGenerator.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/ConstantsGenerator.kt @@ -39,29 +39,41 @@ class ConstantsGenerator(private val config: CodeGenConfig, private val document .addOptionalGeneratedAnnotation(config) .addModifiers(Modifier.PUBLIC) + val types = mutableMapOf() + document.definitions.filterIsInstance() .asSequence() .excludeSchemaTypeExtension() .forEach { - val constantsType = createConstantTypeBuilder(config, it.name) + val constantsType = if (types.contains(it.name)) { + types[it.name]!! + } else { + createConstantTypeBuilder(config, it.name) + } val extensions = findTypeExtensions(it.name, document.definitions) val fields = it.fieldDefinitions + extensions.flatMap { ext -> ext.fieldDefinitions } - constantsType.addField( - FieldSpec.builder(ClassName.get(String::class.java), "TYPE_NAME") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) - .initializer("\$S", it.name).build() - ) + if (!types.contains(it.name)) { + constantsType.addField( + FieldSpec.builder(ClassName.get(String::class.java), "TYPE_NAME") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) + .initializer("\$S", it.name).build() + ) + } fields.forEach { field -> addFieldNameConstant(constantsType, field.name) addQueryInputArgument(constantsType, field) } - javaType.addType(constantsType.build()) + types[it.name] = constantsType } + types.values.forEach { + javaType.addType(it.build()) + } + document.definitions.filterIsInstance() .asSequence() .excludeSchemaTypeExtension() @@ -153,11 +165,7 @@ class ConstantsGenerator(private val config: CodeGenConfig, private val document private fun createConstantTypeBuilder(conf: CodeGenConfig, name: String): TypeSpec.Builder { val className = - if (conf.snakeCaseConstantNames) { - CodeGeneratorUtils.camelCaseToSnakeCase(name, CodeGeneratorUtils.Case.UPPERCASE) - } else { - name.uppercase() - } + getConstantTypeName(conf, name) return TypeSpec .classBuilder(className) @@ -165,23 +173,38 @@ class ConstantsGenerator(private val config: CodeGenConfig, private val document .addModifiers(Modifier.PUBLIC, Modifier.STATIC) } + private fun getConstantTypeName(conf: CodeGenConfig, name: String): String { + val className = + if (conf.snakeCaseConstantNames) { + CodeGeneratorUtils.camelCaseToSnakeCase(name, CodeGeneratorUtils.Case.UPPERCASE) + } else { + name.uppercase() + } + return className + } + private fun addFieldNameConstant(constantsType: TypeSpec.Builder, fieldName: String) { - constantsType.addField( - FieldSpec.builder( - ClassName.get(String::class.java), - ReservedKeywordSanitizer.sanitize(fieldName.capitalized()) + val sanitizedFieldName = ReservedKeywordSanitizer.sanitize(fieldName.capitalized()) + if (!constantsType.fieldSpecs.any { it.name == sanitizedFieldName }) { + constantsType.addField( + FieldSpec.builder( + ClassName.get(String::class.java), + sanitizedFieldName + ) + .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("\$S", fieldName).build() ) - .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("\$S", fieldName).build() - ) + } } private fun addQueryInputArgument(constantsType: TypeSpec.Builder, field: FieldDefinition) { val inputFields = field.inputValueDefinitions - if (inputFields.isNotEmpty()) { - val inputConstantsType = createConstantTypeBuilder(config, field.name + "_INPUT_ARGUMENT") + val name = getConstantTypeName(config, field.name + "_INPUT_ARGUMENT") + if (inputFields.isNotEmpty() && !constantsType.typeSpecs.any { it.name == name }) { + val inputConstantsType = createConstantTypeBuilder(config, name) inputFields.forEach { inputField -> addFieldNameConstant(inputConstantsType, inputField.name) } + constantsType.addType(inputConstantsType.build()) } } diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt index 186f8c24..44a96fce 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt @@ -2069,6 +2069,30 @@ class CodeGenTest { .containsExactly("TitleFilter", "MoveFilter") } + @Test + fun `Dedupe type names in Constants to support multiple schema files`() { + val schema = """ + type Query { + q1: String + } + + type Query { + q2: String + } + """.trimIndent() + + val result = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName + ) + ).generate() + val type = result.javaConstants[0].typeSpec + assertThat(type.typeSpecs).extracting("name").containsExactly("QUERY") + assertThat(type.typeSpecs[0].fieldSpecs).extracting("name") + .contains("Q1", "Q2") + } + @Test fun generateUnion() { val schema = """