Skip to content

Commit a337d21

Browse files
authored
Merge pull request #762 from Netflix/feature/duplicate-constants
Handle duplicate types and fields in constants better
2 parents 28eb116 + 601f8e8 commit a337d21

File tree

2 files changed

+67
-20
lines changed

2 files changed

+67
-20
lines changed

Diff for: graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/ConstantsGenerator.kt

+43-20
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,41 @@ class ConstantsGenerator(private val config: CodeGenConfig, private val document
3939
.addOptionalGeneratedAnnotation(config)
4040
.addModifiers(Modifier.PUBLIC)
4141

42+
val types = mutableMapOf<String, TypeSpec.Builder>()
43+
4244
document.definitions.filterIsInstance<ObjectTypeDefinition>()
4345
.asSequence()
4446
.excludeSchemaTypeExtension()
4547
.forEach {
46-
val constantsType = createConstantTypeBuilder(config, it.name)
48+
val constantsType = if (types.contains(it.name)) {
49+
types[it.name]!!
50+
} else {
51+
createConstantTypeBuilder(config, it.name)
52+
}
4753

4854
val extensions = findTypeExtensions(it.name, document.definitions)
4955
val fields = it.fieldDefinitions + extensions.flatMap { ext -> ext.fieldDefinitions }
5056

51-
constantsType.addField(
52-
FieldSpec.builder(ClassName.get(String::class.java), "TYPE_NAME")
53-
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
54-
.initializer("\$S", it.name).build()
55-
)
57+
if (!types.contains(it.name)) {
58+
constantsType.addField(
59+
FieldSpec.builder(ClassName.get(String::class.java), "TYPE_NAME")
60+
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
61+
.initializer("\$S", it.name).build()
62+
)
63+
}
5664

5765
fields.forEach { field ->
5866
addFieldNameConstant(constantsType, field.name)
5967
addQueryInputArgument(constantsType, field)
6068
}
6169

62-
javaType.addType(constantsType.build())
70+
types[it.name] = constantsType
6371
}
6472

73+
types.values.forEach {
74+
javaType.addType(it.build())
75+
}
76+
6577
document.definitions.filterIsInstance<InputObjectTypeDefinition>()
6678
.asSequence()
6779
.excludeSchemaTypeExtension()
@@ -153,35 +165,46 @@ class ConstantsGenerator(private val config: CodeGenConfig, private val document
153165

154166
private fun createConstantTypeBuilder(conf: CodeGenConfig, name: String): TypeSpec.Builder {
155167
val className =
156-
if (conf.snakeCaseConstantNames) {
157-
CodeGeneratorUtils.camelCaseToSnakeCase(name, CodeGeneratorUtils.Case.UPPERCASE)
158-
} else {
159-
name.uppercase()
160-
}
168+
getConstantTypeName(conf, name)
161169

162170
return TypeSpec
163171
.classBuilder(className)
164172
.addOptionalGeneratedAnnotation(config)
165173
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
166174
}
167175

176+
private fun getConstantTypeName(conf: CodeGenConfig, name: String): String {
177+
val className =
178+
if (conf.snakeCaseConstantNames) {
179+
CodeGeneratorUtils.camelCaseToSnakeCase(name, CodeGeneratorUtils.Case.UPPERCASE)
180+
} else {
181+
name.uppercase()
182+
}
183+
return className
184+
}
185+
168186
private fun addFieldNameConstant(constantsType: TypeSpec.Builder, fieldName: String) {
169-
constantsType.addField(
170-
FieldSpec.builder(
171-
ClassName.get(String::class.java),
172-
ReservedKeywordSanitizer.sanitize(fieldName.capitalized())
187+
val sanitizedFieldName = ReservedKeywordSanitizer.sanitize(fieldName.capitalized())
188+
if (!constantsType.fieldSpecs.any { it.name == sanitizedFieldName }) {
189+
constantsType.addField(
190+
FieldSpec.builder(
191+
ClassName.get(String::class.java),
192+
sanitizedFieldName
193+
)
194+
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("\$S", fieldName).build()
173195
)
174-
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("\$S", fieldName).build()
175-
)
196+
}
176197
}
177198

178199
private fun addQueryInputArgument(constantsType: TypeSpec.Builder, field: FieldDefinition) {
179200
val inputFields = field.inputValueDefinitions
180-
if (inputFields.isNotEmpty()) {
181-
val inputConstantsType = createConstantTypeBuilder(config, field.name + "_INPUT_ARGUMENT")
201+
val name = getConstantTypeName(config, field.name + "_INPUT_ARGUMENT")
202+
if (inputFields.isNotEmpty() && !constantsType.typeSpecs.any { it.name == name }) {
203+
val inputConstantsType = createConstantTypeBuilder(config, name)
182204
inputFields.forEach { inputField ->
183205
addFieldNameConstant(inputConstantsType, inputField.name)
184206
}
207+
185208
constantsType.addType(inputConstantsType.build())
186209
}
187210
}

Diff for: graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt

+24
Original file line numberDiff line numberDiff line change
@@ -2069,6 +2069,30 @@ class CodeGenTest {
20692069
.containsExactly("TitleFilter", "MoveFilter")
20702070
}
20712071

2072+
@Test
2073+
fun `Dedupe type names in Constants to support multiple schema files`() {
2074+
val schema = """
2075+
type Query {
2076+
q1: String
2077+
}
2078+
2079+
type Query {
2080+
q2: String
2081+
}
2082+
""".trimIndent()
2083+
2084+
val result = CodeGen(
2085+
CodeGenConfig(
2086+
schemas = setOf(schema),
2087+
packageName = basePackageName
2088+
)
2089+
).generate()
2090+
val type = result.javaConstants[0].typeSpec
2091+
assertThat(type.typeSpecs).extracting("name").containsExactly("QUERY")
2092+
assertThat(type.typeSpecs[0].fieldSpecs).extracting("name")
2093+
.contains("Q1", "Q2")
2094+
}
2095+
20722096
@Test
20732097
fun generateUnion() {
20742098
val schema = """

0 commit comments

Comments
 (0)