master
branch. The latest version is v0.17.56.
While most generated Golang types must have unique names by virtue of being based on their GraphQL type
counterpart,
which themselves must be unique, there are a few edge scenarios where conflicts can occur. This document describes
how those collisions are handled.
Enum Constants
Enum type generation is a prime example of where naming collisions can occur, as we build the const names per value as a composite of the Enum name and each individual value.
Example Problem
Currently, enum types are transposed as such:
# graphql
enum MyEnum {
value1
value2
value3
value4
}
Which will result in the following Golang:
// golang
type MyEnum string
const (
MyEnumValue1 MyEnum = "value1"
MyEnumValue2 MyEnum = "value2"
MyEnumValue3 MyEnum = "value3"
MyEnumValue4 MyEnum = "value4"
)
However, those above enum values are just strings. What if you encounter a scenario where the following is necessary:
# graphql
enum MyEnum {
value1
value2
value3
value4
Value4
Value_4
}
The Value4
and Value_4
enum values cannot be directly transposed into the same “pretty” naming convention as their
resulting constant names would conflict with the name for value4
, as so:
// golang
type MyEnum string
const (
MyEnumValue1 MyEnum = "value1"
MyEnumValue2 MyEnum = "value2"
MyEnumValue3 MyEnum = "value3"
MyEnumValue4 MyEnum = "value4"
MyEnumValue4 MyEnum = "Value4"
MyEnumValue4 MyEnum = "Value_4"
)
Which immediately leads to compilation errors as we now have three constants with the same name, but different values.
Resolution
- Store each name generated as part of a run for later comparison
- Try to coerce name into
CapitalCase
. Use if no conflicts.- This process attempts to break apart identifiers into “words”, identified by separating on capital letters, underscores, hyphens, and spaces.
- Each “word” is capitalized and appended to previous word.
- If non-composite name, append integer to end of name, starting at 0 and going to
math.MaxInt
- If composite name, in reverse order, the pieces of the name have a less opinionated converter applied
- If all else fails, append integer to end of name, starting at 0 and going to
math.MaxInt
The first step to produce a name that does not conflict with an existing name succeeds.
Examples
Example A
GraphQL:
# graphql
enum MyEnum {
Value
value
TitleValue
title_value
}
Go:
// golang
type MyEnum string
const (
MyEnumValue MyEnum = "Value"
MyEnumvalue MyEnum = "value"
MyEnumTitleValue MyEnum = "TitleValue"
MyEnumtitle_value MyEnum = "title_value"
)
Example B
GraphQL:
# graphql
enum MyEnum {
TitleValue
title_value
title_Value
Title_Value
}
Go:
// golang
type MyEnum string
const (
MyEnumTitleValue MyEnum = "TitleValue"
MyEnumtitle_value MyEnum = "title_value"
MyEnumtitle_Value MyEnum = "title_Value"
MyEnumTitle_Value MyEnum = "Title_Value"
)
Example C
GraphQL:
# graphql
enum MyEnum {
value
Value
}
Go:
// golang
type MyEnum string
const (
MyEnumValue = "value"
MyEnumValue0 = "Value"
)
Warning
Name collision resolution is handled per-name, as they come in. If you change the order of an enum, you could very well end up with the same constant resolving to a different value.
Lets mutate Example C:
Example C - State A
GraphQL:
# graphql
enum MyEnum {
value
Value
}
Go:
// golang
type MyEnum string
const (
MyEnumValue = "value"
MyEnumValue0 = "Value"
)
Example C - State B
GraphQL:
# graphql
enum MyEnum {
Value
value
}
Go:
// golang
type MyEnum string
const (
MyEnumValue = "Value"
MyEnumValue0 = "value"
)
Notice how the constant names are the same, but the value that each applies to has changed.