From 9fc8602f6832b80631ce6f2285e806aeef38ab13 Mon Sep 17 00:00:00 2001 From: Timofey Date: Fri, 2 Oct 2020 15:54:36 +0300 Subject: [PATCH 1/2] Add ability to generate int enums --- plugin/modelgen/models.go | 2 + plugin/modelgen/models.gotpl | 61 ++++++++++++++++++------- plugin/modelgen/models_test.go | 1 + plugin/modelgen/out/existing.go | 2 + plugin/modelgen/out/generated.go | 59 ++++++++++++++++++++---- plugin/modelgen/testdata/gqlgen.yml | 2 + plugin/modelgen/testdata/schema.graphql | 12 +++++ 7 files changed, 115 insertions(+), 24 deletions(-) diff --git a/plugin/modelgen/models.go b/plugin/modelgen/models.go index e0ca186632..f62a3b910a 100644 --- a/plugin/modelgen/models.go +++ b/plugin/modelgen/models.go @@ -48,6 +48,7 @@ type Enum struct { Description string Name string Values []*EnumValue + IntValues bool // Whether generated types should be integers } type EnumValue struct { @@ -175,6 +176,7 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { it := &Enum{ Name: schemaType.Name, Description: schemaType.Description, + IntValues: schemaType.Directives.ForName("intEnum") != nil, } for _, v := range schemaType.EnumValues { diff --git a/plugin/modelgen/models.gotpl b/plugin/modelgen/models.gotpl index e58d5b21a4..dc514dfd28 100644 --- a/plugin/modelgen/models.gotpl +++ b/plugin/modelgen/models.gotpl @@ -37,21 +37,35 @@ {{ range $enum := .Enums }} {{ with .Description }} {{.|prefixLines "// "}} {{end}} - type {{.Name|go }} string + type {{.Name|go }} {{if $enum.IntValues }}int{{else}}string{{end}} const ( - {{- range $value := .Values}} + {{- range $index, $value := .Values}} {{- with .Description}} {{.|prefixLines "// "}} {{- end}} - {{ $enum.Name|go }}{{ .Name|go }} {{$enum.Name|go }} = {{.Name|quote}} + {{ $enum.Name|go }}{{ .Name|go }} {{$enum.Name|go }} = {{if $enum.IntValues }}{{$index}}{{else}}{{.Name|quote}}{{end}} {{- end }} ) - var All{{.Name|go }} = []{{ .Name|go }}{ - {{- range $value := .Values}} - {{$enum.Name|go }}{{ .Name|go }}, - {{- end }} - } + {{if $enum.IntValues }} + var {{.Name|go }}Name = map[int]string{ + {{- range $index, $value := .Values}} + {{$index}}: {{$value.Name|quote}}, + {{- end }} + } + + var {{.Name|go }}Value = map[string]int{ + {{- range $index, $value := .Values}} + {{$value.Name|quote}}: {{$index}}, + {{- end }} + } + {{else}} + var All{{.Name|go }} = []{{ .Name|go }}{ + {{- range $value := .Values}} + {{$enum.Name|go }}{{ .Name|go }}, + {{- end }} + } + {{end}} func (e {{.Name|go }}) IsValid() bool { switch e { @@ -62,24 +76,39 @@ } func (e {{.Name|go }}) String() string { - return string(e) + {{ if $enum.IntValues -}} + return {{.Name|go }}Name[int(e)] + {{ else -}} + return string(e) + {{ end -}} } func (e *{{.Name|go }}) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } + {{ if $enum.IntValues -}} + value, ok := v.(int) + if !ok { + return fmt.Errorf("enums must be integers") + } + {{ else -}} + value, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + {{ end -}} - *e = {{ .Name|go }}(str) + *e = {{ .Name|go }}(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid {{ .Name }}", str) + return fmt.Errorf("%v is not a valid {{ .Name }}", value) } return nil } func (e {{.Name|go }}) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) + {{ if $enum.IntValues -}} + fmt.Fprint(w, e) + {{ else -}} + fmt.Fprint(w, strconv.Quote(e.String())) + {{ end -}} } {{- end }} diff --git a/plugin/modelgen/models_test.go b/plugin/modelgen/models_test.go index 20becda914..d6cabcc4da 100644 --- a/plugin/modelgen/models_test.go +++ b/plugin/modelgen/models_test.go @@ -24,6 +24,7 @@ func TestModelGeneration(t *testing.T) { require.True(t, cfg.Models.UserDefined("MissingTypeNotNull")) require.True(t, cfg.Models.UserDefined("MissingTypeNullable")) require.True(t, cfg.Models.UserDefined("MissingEnum")) + require.True(t, cfg.Models.UserDefined("MissingIntEnum")) require.True(t, cfg.Models.UserDefined("MissingUnion")) require.True(t, cfg.Models.UserDefined("MissingInterface")) require.True(t, cfg.Models.UserDefined("TypeWithDescription")) diff --git a/plugin/modelgen/out/existing.go b/plugin/modelgen/out/existing.go index 256d2d1bfa..00defeb6e0 100644 --- a/plugin/modelgen/out/existing.go +++ b/plugin/modelgen/out/existing.go @@ -21,6 +21,8 @@ type ExistingInput struct { type ExistingEnum string +type ExistingIntEnum int + type ExistingInterface interface { IsExistingInterface() } diff --git a/plugin/modelgen/out/generated.go b/plugin/modelgen/out/generated.go index bddf95bbff..4cd4a20e8b 100644 --- a/plugin/modelgen/out/generated.go +++ b/plugin/modelgen/out/generated.go @@ -100,14 +100,13 @@ func (e EnumWithDescription) String() string { } func (e *EnumWithDescription) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) + value, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } - - *e = EnumWithDescription(str) + *e = EnumWithDescription(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid EnumWithDescription", str) + return fmt.Errorf("%v is not a valid EnumWithDescription", value) } return nil } @@ -141,14 +140,13 @@ func (e MissingEnum) String() string { } func (e *MissingEnum) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) + value, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } - - *e = MissingEnum(str) + *e = MissingEnum(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid MissingEnum", str) + return fmt.Errorf("%v is not a valid MissingEnum", value) } return nil } @@ -156,3 +154,48 @@ func (e *MissingEnum) UnmarshalGQL(v interface{}) error { func (e MissingEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } + +type MissingIntEnum int + +const ( + MissingIntEnumHello MissingIntEnum = 0 + MissingIntEnumGoodbye MissingIntEnum = 1 +) + +var MissingIntEnumName = map[int]string{ + 0: "Hello", + 1: "Goodbye", +} + +var MissingIntEnumValue = map[string]int{ + "Hello": 0, + "Goodbye": 1, +} + +func (e MissingIntEnum) IsValid() bool { + switch e { + case MissingIntEnumHello, MissingIntEnumGoodbye: + return true + } + return false +} + +func (e MissingIntEnum) String() string { + return MissingIntEnumName[int(e)] +} + +func (e *MissingIntEnum) UnmarshalGQL(v interface{}) error { + value, ok := v.(int) + if !ok { + return fmt.Errorf("enums must be integers") + } + *e = MissingIntEnum(value) + if !e.IsValid() { + return fmt.Errorf("%v is not a valid MissingIntEnum", value) + } + return nil +} + +func (e MissingIntEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, e) +} diff --git a/plugin/modelgen/testdata/gqlgen.yml b/plugin/modelgen/testdata/gqlgen.yml index fcc8b7163a..0f1ed5462d 100644 --- a/plugin/modelgen/testdata/gqlgen.yml +++ b/plugin/modelgen/testdata/gqlgen.yml @@ -13,6 +13,8 @@ models: model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingInput ExistingEnum: model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingEnum + ExistingIntEnum: + model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingIntEnum ExistingInterface: model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingInterface ExistingUnion: diff --git a/plugin/modelgen/testdata/schema.graphql b/plugin/modelgen/testdata/schema.graphql index 7f0c0c93e9..08a03c7152 100644 --- a/plugin/modelgen/testdata/schema.graphql +++ b/plugin/modelgen/testdata/schema.graphql @@ -1,3 +1,5 @@ +directive @intEnum on ENUM + type Query { thisShoudlntGetGenerated: Boolean } @@ -36,6 +38,11 @@ enum MissingEnum { Goodbye } +enum MissingIntEnum @intEnum { + Hello + Goodbye +} + interface MissingInterface { name: String } @@ -59,6 +66,11 @@ enum ExistingEnum { Goodbye } +enum ExistingIntEnum @intEnum { + Hello + Goodbye +} + interface ExistingInterface { name: String } From 2a8c8cebacc14d2b9deec8bf208a87992591282a Mon Sep 17 00:00:00 2001 From: Timofey Date: Fri, 2 Oct 2020 16:29:37 +0300 Subject: [PATCH 2/2] run go generate --- codegen/testserver/models-gen.go | 14 ++++++-------- example/starwars/models/generated.go | 14 ++++++-------- example/todo/models_gen.go | 7 +++---- example/type-system-extension/models_gen.go | 7 +++---- integration/models-go/generated.go | 14 ++++++-------- 5 files changed, 24 insertions(+), 32 deletions(-) diff --git a/codegen/testserver/models-gen.go b/codegen/testserver/models-gen.go index 3bae2a74c6..d9c402ec81 100644 --- a/codegen/testserver/models-gen.go +++ b/codegen/testserver/models-gen.go @@ -231,14 +231,13 @@ func (e EnumTest) String() string { } func (e *EnumTest) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) + value, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } - - *e = EnumTest(str) + *e = EnumTest(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid EnumTest", str) + return fmt.Errorf("%v is not a valid EnumTest", value) } return nil } @@ -272,14 +271,13 @@ func (e Status) String() string { } func (e *Status) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) + value, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } - - *e = Status(str) + *e = Status(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid Status", str) + return fmt.Errorf("%v is not a valid Status", value) } return nil } diff --git a/example/starwars/models/generated.go b/example/starwars/models/generated.go index 2f02272c20..2a9309d7a1 100644 --- a/example/starwars/models/generated.go +++ b/example/starwars/models/generated.go @@ -63,14 +63,13 @@ func (e Episode) String() string { } func (e *Episode) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) + value, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } - - *e = Episode(str) + *e = Episode(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid Episode", str) + return fmt.Errorf("%v is not a valid Episode", value) } return nil } @@ -104,14 +103,13 @@ func (e LengthUnit) String() string { } func (e *LengthUnit) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) + value, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } - - *e = LengthUnit(str) + *e = LengthUnit(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid LengthUnit", str) + return fmt.Errorf("%v is not a valid LengthUnit", value) } return nil } diff --git a/example/todo/models_gen.go b/example/todo/models_gen.go index 74a1c0da57..1187c78c2b 100644 --- a/example/todo/models_gen.go +++ b/example/todo/models_gen.go @@ -41,14 +41,13 @@ func (e Role) String() string { } func (e *Role) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) + value, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } - - *e = Role(str) + *e = Role(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid Role", str) + return fmt.Errorf("%v is not a valid Role", value) } return nil } diff --git a/example/type-system-extension/models_gen.go b/example/type-system-extension/models_gen.go index ece1b800b2..8298302e94 100644 --- a/example/type-system-extension/models_gen.go +++ b/example/type-system-extension/models_gen.go @@ -55,14 +55,13 @@ func (e State) String() string { } func (e *State) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) + value, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } - - *e = State(str) + *e = State(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid State", str) + return fmt.Errorf("%v is not a valid State", value) } return nil } diff --git a/integration/models-go/generated.go b/integration/models-go/generated.go index 7d4b611e83..83f3b770f9 100644 --- a/integration/models-go/generated.go +++ b/integration/models-go/generated.go @@ -47,14 +47,13 @@ func (e DateFilterOp) String() string { } func (e *DateFilterOp) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) + value, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } - - *e = DateFilterOp(str) + *e = DateFilterOp(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid DATE_FILTER_OP", str) + return fmt.Errorf("%v is not a valid DATE_FILTER_OP", value) } return nil } @@ -88,14 +87,13 @@ func (e ErrorType) String() string { } func (e *ErrorType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) + value, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } - - *e = ErrorType(str) + *e = ErrorType(value) if !e.IsValid() { - return fmt.Errorf("%s is not a valid ErrorType", str) + return fmt.Errorf("%v is not a valid ErrorType", value) } return nil }