Skip to content

Commit

Permalink
Merge pull request #762 from Netflix/feature/duplicate-constants
Browse files Browse the repository at this point in the history
Handle duplicate types and fields in constants better
  • Loading branch information
paulbakker authored Dec 2, 2024
2 parents 28eb116 + 601f8e8 commit a337d21
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,41 @@ class ConstantsGenerator(private val config: CodeGenConfig, private val document
.addOptionalGeneratedAnnotation(config)
.addModifiers(Modifier.PUBLIC)

val types = mutableMapOf<String, TypeSpec.Builder>()

document.definitions.filterIsInstance<ObjectTypeDefinition>()
.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<InputObjectTypeDefinition>()
.asSequence()
.excludeSchemaTypeExtension()
Expand Down Expand Up @@ -153,35 +165,46 @@ 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)
.addOptionalGeneratedAnnotation(config)
.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())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = """
Expand Down

0 comments on commit a337d21

Please sign in to comment.