From d2294fbaa68d162f7247980d938e80ca78879df6 Mon Sep 17 00:00:00 2001 From: Ian Ling Date: Thu, 26 May 2022 15:19:29 -0700 Subject: [PATCH] Config option for generating embedded structs from interfaces --- codegen/config/config.go | 35 +-- codegen/data.go | 16 +- docs/content/config.md | 3 + init-templates/gqlgen.yml.gotmpl | 3 + plugin/modelgen/models.go | 34 ++- plugin/modelgen/models.gotpl | 61 ++++- plugin/modelgen/models_test.go | 27 +++ plugin/modelgen/out/generated.go | 26 ++ .../out_interface_field_methods/existing.go | 30 +++ .../out_interface_field_methods/generated.go | 223 ++++++++++++++++++ .../modelgen/out_struct_pointers/generated.go | 26 ++ .../gqlgen_interface_field_methods.yml | 24 ++ plugin/modelgen/testdata/schema.graphql | 9 + 13 files changed, 467 insertions(+), 50 deletions(-) create mode 100644 plugin/modelgen/out_interface_field_methods/existing.go create mode 100644 plugin/modelgen/out_interface_field_methods/generated.go create mode 100644 plugin/modelgen/testdata/gqlgen_interface_field_methods.yml diff --git a/codegen/config/config.go b/codegen/config/config.go index ed4ed3f0253..a7dac24e9f7 100644 --- a/codegen/config/config.go +++ b/codegen/config/config.go @@ -16,23 +16,24 @@ import ( ) type Config struct { - SchemaFilename StringList `yaml:"schema,omitempty"` - Exec ExecConfig `yaml:"exec"` - Model PackageConfig `yaml:"model,omitempty"` - Federation PackageConfig `yaml:"federation,omitempty"` - Resolver ResolverConfig `yaml:"resolver,omitempty"` - AutoBind []string `yaml:"autobind"` - Models TypeMap `yaml:"models,omitempty"` - StructTag string `yaml:"struct_tag,omitempty"` - Directives map[string]DirectiveConfig `yaml:"directives,omitempty"` - OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"` - StructFieldsAlwaysPointers bool `yaml:"struct_fields_always_pointers,omitempty"` - ResolversAlwaysReturnPointers bool `yaml:"resolvers_always_return_pointers,omitempty"` - SkipValidation bool `yaml:"skip_validation,omitempty"` - SkipModTidy bool `yaml:"skip_mod_tidy,omitempty"` - Sources []*ast.Source `yaml:"-"` - Packages *code.Packages `yaml:"-"` - Schema *ast.Schema `yaml:"-"` + SchemaFilename StringList `yaml:"schema,omitempty"` + Exec ExecConfig `yaml:"exec"` + Model PackageConfig `yaml:"model,omitempty"` + Federation PackageConfig `yaml:"federation,omitempty"` + Resolver ResolverConfig `yaml:"resolver,omitempty"` + AutoBind []string `yaml:"autobind"` + Models TypeMap `yaml:"models,omitempty"` + StructTag string `yaml:"struct_tag,omitempty"` + Directives map[string]DirectiveConfig `yaml:"directives,omitempty"` + OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"` + StructFieldsAlwaysPointers bool `yaml:"struct_fields_always_pointers,omitempty"` + ResolversAlwaysReturnPointers bool `yaml:"resolvers_always_return_pointers,omitempty"` + GenerateEmbeddedStructsForInterfaces bool `yaml:"generate_embedded_structs_for_interfaces,omitempty"` + SkipValidation bool `yaml:"skip_validation,omitempty"` + SkipModTidy bool `yaml:"skip_mod_tidy,omitempty"` + Sources []*ast.Source `yaml:"-"` + Packages *code.Packages `yaml:"-"` + Schema *ast.Schema `yaml:"-"` // Deprecated: use Federation instead. Will be removed next release Federated bool `yaml:"federated,omitempty"` diff --git a/codegen/data.go b/codegen/data.go index 3a636e3bdb6..b5328f74e98 100644 --- a/codegen/data.go +++ b/codegen/data.go @@ -109,7 +109,15 @@ func BuildData(cfg *config.Config) (*Data, error) { for _, schemaType := range b.Schema.Types { switch schemaType.Kind { - case ast.Object: + case ast.Union, ast.Interface, ast.Object: + if (schemaType.Kind == ast.Union || schemaType.Kind == ast.Interface) && !cfg.GenerateEmbeddedStructsForInterfaces { + s.Interfaces[schemaType.Name], err = b.buildInterface(schemaType) + if err != nil { + return nil, fmt.Errorf("unable to bind to interface: %w", err) + } + + continue + } obj, err := b.buildObject(schemaType) if err != nil { return nil, fmt.Errorf("unable to build object definition: %w", err) @@ -123,12 +131,6 @@ func BuildData(cfg *config.Config) (*Data, error) { } s.Inputs = append(s.Inputs, input) - - case ast.Union, ast.Interface: - s.Interfaces[schemaType.Name], err = b.buildInterface(schemaType) - if err != nil { - return nil, fmt.Errorf("unable to bind to interface: %w", err) - } } } diff --git a/docs/content/config.md b/docs/content/config.md index a274947d56e..06a755b0eb7 100644 --- a/docs/content/config.md +++ b/docs/content/config.md @@ -51,6 +51,9 @@ resolver: # Optional: turn off to make resolvers return values instead of pointers for structs # resolvers_always_return_pointers: true +# Optional: turn on to generate getter/setter methods for accessing interface fields instead of exporting the fields +# generate_interface_getters_setters: false + # Optional: set to speed up generation time by not performing a final validation pass. # skip_validation: true diff --git a/init-templates/gqlgen.yml.gotmpl b/init-templates/gqlgen.yml.gotmpl index 1ca1dd2d504..890e8a91863 100644 --- a/init-templates/gqlgen.yml.gotmpl +++ b/init-templates/gqlgen.yml.gotmpl @@ -36,6 +36,9 @@ resolver: # Optional: turn off to make resolvers return values instead of pointers for structs # resolvers_always_return_pointers: true +# Optional: turn on to generate embedded structs when processing GraphQL interfaces +# generate_embedded_structs_for_interfaces: false + # Optional: set to speed up generation time by not performing a final validation pass. # skip_validation: true diff --git a/plugin/modelgen/models.go b/plugin/modelgen/models.go index 9d0db43afcb..93426f87f2b 100644 --- a/plugin/modelgen/models.go +++ b/plugin/modelgen/models.go @@ -26,16 +26,17 @@ func defaultBuildMutateHook(b *ModelBuild) *ModelBuild { } type ModelBuild struct { - PackageName string - Interfaces []*Interface - Models []*Object - Enums []*Enum - Scalars []string + Config *config.Config + Interfaces []*Interface + Models []*Object + Enums []*Enum + Scalars []string } type Interface struct { Description string Name string + Fields ast.FieldList Implements []string } @@ -86,7 +87,7 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { binder := cfg.NewBinder() b := &ModelBuild{ - PackageName: cfg.Model.Package, + Config: cfg, } for _, schemaType := range cfg.Schema.Types { @@ -94,15 +95,22 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { continue } switch schemaType.Kind { - case ast.Interface, ast.Union: - it := &Interface{ - Description: schemaType.Description, - Name: schemaType.Name, - Implements: schemaType.Interfaces, + case ast.Interface, ast.Union, ast.Object, ast.InputObject: + if schemaType.Kind == ast.Interface || schemaType.Kind == ast.Union { + it := &Interface{ + Description: schemaType.Description, + Name: schemaType.Name, + Implements: schemaType.Interfaces, + Fields: schemaType.Fields, + } + + b.Interfaces = append(b.Interfaces, it) + + if !cfg.GenerateEmbeddedStructsForInterfaces { + continue + } } - b.Interfaces = append(b.Interfaces, it) - case ast.Object, ast.InputObject: if schemaType == cfg.Schema.Query || schemaType == cfg.Schema.Mutation || schemaType == cfg.Schema.Subscription { continue } diff --git a/plugin/modelgen/models.gotpl b/plugin/modelgen/models.gotpl index 8f425e58eb4..53c12082ab8 100644 --- a/plugin/modelgen/models.gotpl +++ b/plugin/modelgen/models.gotpl @@ -12,29 +12,64 @@ {{ reserveImport "github.com/99designs/gqlgen/graphql" }} {{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }} -{{- range $model := .Interfaces }} - {{ with .Description }} {{.|prefixLines "// "}} {{ end }} - type {{.Name|go }} interface { - {{- range $impl := .Implements }} - {{ $impl|go }} - {{- end }} - Is{{.Name|go }}() - } +{{- if not $.Config.GenerateEmbeddedStructsForInterfaces }} + {{- range $interface := .Interfaces }} + {{ with .Description }} {{.|prefixLines "// "}} {{ end }} + type {{.Name|go }} interface { + {{- range $impl := .Implements }} + {{ $impl|go }} + {{- end }} + Is{{.Name|go }}() + } + {{- end }} {{- end }} {{ range $model := .Models }} {{with .Description }} {{.|prefixLines "// "}} {{end}} type {{ .Name|go }} struct { + {{- range $impl := $model.Implements }} + {{ $impl|go }} + {{- end}} {{- range $field := .Fields }} - {{- with .Description }} - {{.|prefixLines "// "}} + {{- /* If we are generating embedded structs for GraphQL interfaces, + we need to determine which of the struct's fields are for the purpose of implementing an interface + and ignore those in favor of simply embedding the interface's struct */ -}} + {{- $found := false }} + {{- if and $.Config.GenerateEmbeddedStructsForInterfaces $model.Implements}} + {{- range $impl := $model.Implements }} + {{- range $interface := $.Interfaces }} + {{- if eq $impl $interface.Name }} + {{- range $interfaceField := $interface.Fields }} + {{- if eq $interfaceField.Name $field.Name }} + {{- $found = true }} + {{- break}} + {{- end }} + {{- end }} + {{- end }} + + {{- if $found }} + {{- break}} + {{- end }} + {{- end }} + + {{- if $found }} + {{- break}} + {{- end }} + {{- end }} + {{- end }} + {{- if not $found }} + {{- with .Description }} + {{.|prefixLines "// "}} + {{- end}} + {{ $field.Name|go }} {{$field.Type | ref}} `{{$field.Tag}}` {{- end}} - {{ $field.Name|go }} {{$field.Type | ref}} `{{$field.Tag}}` {{- end }} } - {{- range $iface := .Implements }} - func ({{ $model.Name|go }}) Is{{ $iface|go }}() {} + {{- if not $.Config.GenerateEmbeddedStructsForInterfaces }} + {{- range $iface := .Implements }} + func ({{ $model.Name|go }}) Is{{ $iface|go }}() {} + {{- end }} {{- end }} {{- end}} diff --git a/plugin/modelgen/models_test.go b/plugin/modelgen/models_test.go index e6e4f09cbd9..175b9b9d7ce 100644 --- a/plugin/modelgen/models_test.go +++ b/plugin/modelgen/models_test.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/99designs/gqlgen/plugin/modelgen/out_interface_field_methods" "github.com/99designs/gqlgen/plugin/modelgen/out_struct_pointers" "github.com/99designs/gqlgen/codegen/config" @@ -279,6 +280,32 @@ func TestModelGenerationStructFieldPointers(t *testing.T) { }) } +func TestModelGenerationInterfaceFieldMethods(t *testing.T) { + cfg, err := config.LoadConfig("testdata/gqlgen_interface_field_methods.yml") + require.NoError(t, err) + require.NoError(t, cfg.Init()) + p := Plugin{ + MutateHook: mutateHook, + FieldHook: defaultFieldMutateHook, + } + require.NoError(t, p.MutateConfig(cfg)) + + t.Run("no pointer pointers", func(t *testing.T) { + generated, err := ioutil.ReadFile("./out_interface_field_methods/generated.go") + require.NoError(t, err) + require.NotContains(t, string(generated), "**") + }) + + t.Run("interfaces become embedded structs", func(t *testing.T) { + human := out_interface_field_methods.Human{ + Animal: out_interface_field_methods.Animal{Species: "human"}, + Name: "ian", + } + require.Equal(t, "human", human.Species) + require.Equal(t, "ian", human.Name) + }) +} + func mutateHook(b *ModelBuild) *ModelBuild { for _, model := range b.Models { for _, field := range model.Fields { diff --git a/plugin/modelgen/out/generated.go b/plugin/modelgen/out/generated.go index e57ce6471cb..caa83fcef25 100644 --- a/plugin/modelgen/out/generated.go +++ b/plugin/modelgen/out/generated.go @@ -12,6 +12,10 @@ type A interface { IsA() } +type Animal interface { + IsAnimal() +} + type B interface { IsB() } @@ -50,6 +54,10 @@ type UnionWithDescription interface { } type CDImplemented struct { + C + A + D + B A string `json:"a" database:"CDImplementeda"` B int `json:"b" database:"CDImplementedb"` C bool `json:"c" database:"CDImplementedc"` @@ -83,12 +91,24 @@ type FieldMutationHook struct { Repeated *string `json:"repeated" someTag:"value" repeated:"true" database:"FieldMutationHookrepeated"` } +type Human struct { + Animal + Species string `json:"species" database:"Humanspecies"` + Name string `json:"name" database:"Humanname"` +} + +func (Human) IsAnimal() {} + type MissingInput struct { Name *string `json:"name" database:"MissingInputname"` Enum *MissingEnum `json:"enum" database:"MissingInputenum"` } type MissingTypeNotNull struct { + MissingInterface + ExistingInterface + MissingUnion + ExistingUnion Name string `json:"name" database:"MissingTypeNotNullname"` Enum MissingEnum `json:"enum" database:"MissingTypeNotNullenum"` Int MissingInterface `json:"int" database:"MissingTypeNotNullint"` @@ -102,6 +122,10 @@ func (MissingTypeNotNull) IsMissingUnion() {} func (MissingTypeNotNull) IsExistingUnion() {} type MissingTypeNullable struct { + MissingInterface + ExistingInterface + MissingUnion + ExistingUnion Name *string `json:"name" database:"MissingTypeNullablename"` Enum *MissingEnum `json:"enum" database:"MissingTypeNullableenum"` Int MissingInterface `json:"int" database:"MissingTypeNullableint"` @@ -133,12 +157,14 @@ type Recursive struct { // TypeWithDescription is a type with a description type TypeWithDescription struct { + UnionWithDescription Name *string `json:"name" database:"TypeWithDescriptionname"` } func (TypeWithDescription) IsUnionWithDescription() {} type FooBarr struct { + FooBarer Name string `json:"name" database:"_Foo_Barrname"` } diff --git a/plugin/modelgen/out_interface_field_methods/existing.go b/plugin/modelgen/out_interface_field_methods/existing.go new file mode 100644 index 00000000000..c15756b9897 --- /dev/null +++ b/plugin/modelgen/out_interface_field_methods/existing.go @@ -0,0 +1,30 @@ +package out_interface_field_methods + +type ExistingType struct { + Name *string `json:"name"` + Enum *ExistingEnum `json:"enum"` + Int ExistingInterface `json:"int"` + Existing *MissingTypeNullable `json:"existing"` +} + +type ExistingModel struct { + Name string + Enum ExistingEnum + Int ExistingInterface +} + +type ExistingInput struct { + Name string + Enum ExistingEnum + Int ExistingInterface +} + +type ExistingEnum string + +type ExistingInterface interface { + IsExistingInterface() +} + +type ExistingUnion interface { + IsExistingUnion() +} diff --git a/plugin/modelgen/out_interface_field_methods/generated.go b/plugin/modelgen/out_interface_field_methods/generated.go new file mode 100644 index 00000000000..28a712af262 --- /dev/null +++ b/plugin/modelgen/out_interface_field_methods/generated.go @@ -0,0 +1,223 @@ +// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. + +package out_interface_field_methods + +import ( + "fmt" + "io" + "strconv" +) + +type A struct { + A string `json:"a" database:"Aa"` +} + +type Animal struct { + Species string `json:"species" database:"Animalspecies"` +} + +type B struct { + B int `json:"b" database:"Bb"` +} + +type C struct { + A + C bool `json:"c" database:"Cc"` +} + +type CDImplemented struct { + C + A + D + B +} + +type CyclicalA struct { + FieldOne *CyclicalB `json:"field_one" database:"CyclicalAfield_one"` + FieldTwo *CyclicalB `json:"field_two" database:"CyclicalAfield_two"` + FieldThree *CyclicalB `json:"field_three" database:"CyclicalAfield_three"` + FieldFour string `json:"field_four" database:"CyclicalAfield_four"` +} + +type CyclicalB struct { + FieldOne *CyclicalA `json:"field_one" database:"CyclicalBfield_one"` + FieldTwo *CyclicalA `json:"field_two" database:"CyclicalBfield_two"` + FieldThree *CyclicalA `json:"field_three" database:"CyclicalBfield_three"` + FieldFour *CyclicalA `json:"field_four" database:"CyclicalBfield_four"` + FieldFive string `json:"field_five" database:"CyclicalBfield_five"` +} + +type D struct { + A + B + D *string `json:"d" database:"Dd"` +} + +type FieldMutationHook struct { + Name *string `json:"name" anotherTag:"tag" database:"FieldMutationHookname"` + Enum *ExistingEnum `json:"enum" yetAnotherTag:"12" database:"FieldMutationHookenum"` + NoVal *string `json:"noVal" yaml:"noVal" repeated:"true" database:"FieldMutationHooknoVal"` + Repeated *string `json:"repeated" someTag:"value" repeated:"true" database:"FieldMutationHookrepeated"` +} + +type FooBarer struct { + Name string `json:"name" database:"Foo_Barername"` +} + +type Human struct { + Animal + Name string `json:"name" database:"Humanname"` +} + +// InterfaceWithDescription is an interface with a description +type InterfaceWithDescription struct { + Name *string `json:"name" database:"InterfaceWithDescriptionname"` +} + +type MissingInput struct { + Name *string `json:"name" database:"MissingInputname"` + Enum *MissingEnum `json:"enum" database:"MissingInputenum"` +} + +type MissingInterface struct { + Name *string `json:"name" database:"MissingInterfacename"` +} + +type MissingTypeNotNull struct { + MissingInterface + ExistingInterface + MissingUnion + ExistingUnion + Enum MissingEnum `json:"enum" database:"MissingTypeNotNullenum"` + Int MissingInterface `json:"int" database:"MissingTypeNotNullint"` + Existing *ExistingType `json:"existing" database:"MissingTypeNotNullexisting"` + Missing2 *MissingTypeNullable `json:"missing2" database:"MissingTypeNotNullmissing2"` +} + +type MissingTypeNullable struct { + MissingInterface + ExistingInterface + MissingUnion + ExistingUnion + Enum *MissingEnum `json:"enum" database:"MissingTypeNullableenum"` + Int MissingInterface `json:"int" database:"MissingTypeNullableint"` + Existing *ExistingType `json:"existing" database:"MissingTypeNullableexisting"` + Missing2 *MissingTypeNotNull `json:"missing2" database:"MissingTypeNullablemissing2"` +} + +type MissingUnion struct { +} + +type NotCyclicalA struct { + FieldOne string `json:"FieldOne" database:"NotCyclicalAFieldOne"` + FieldTwo int `json:"FieldTwo" database:"NotCyclicalAFieldTwo"` +} + +type NotCyclicalB struct { + FieldOne string `json:"FieldOne" database:"NotCyclicalBFieldOne"` + FieldTwo *NotCyclicalA `json:"FieldTwo" database:"NotCyclicalBFieldTwo"` +} + +type Recursive struct { + FieldOne *Recursive `json:"FieldOne" database:"RecursiveFieldOne"` + FieldTwo *Recursive `json:"FieldTwo" database:"RecursiveFieldTwo"` + FieldThree *Recursive `json:"FieldThree" database:"RecursiveFieldThree"` + FieldFour string `json:"FieldFour" database:"RecursiveFieldFour"` +} + +// TypeWithDescription is a type with a description +type TypeWithDescription struct { + UnionWithDescription + Name *string `json:"name" database:"TypeWithDescriptionname"` +} + +// UnionWithDescription is an union with a description +type UnionWithDescription struct { +} + +type FooBarr struct { + FooBarer +} + +// EnumWithDescription is an enum with a description +type EnumWithDescription string + +const ( + EnumWithDescriptionCat EnumWithDescription = "CAT" + EnumWithDescriptionDog EnumWithDescription = "DOG" +) + +var AllEnumWithDescription = []EnumWithDescription{ + EnumWithDescriptionCat, + EnumWithDescriptionDog, +} + +func (e EnumWithDescription) IsValid() bool { + switch e { + case EnumWithDescriptionCat, EnumWithDescriptionDog: + return true + } + return false +} + +func (e EnumWithDescription) String() string { + return string(e) +} + +func (e *EnumWithDescription) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = EnumWithDescription(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid EnumWithDescription", str) + } + return nil +} + +func (e EnumWithDescription) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type MissingEnum string + +const ( + MissingEnumHello MissingEnum = "Hello" + MissingEnumGoodbye MissingEnum = "Goodbye" +) + +var AllMissingEnum = []MissingEnum{ + MissingEnumHello, + MissingEnumGoodbye, +} + +func (e MissingEnum) IsValid() bool { + switch e { + case MissingEnumHello, MissingEnumGoodbye: + return true + } + return false +} + +func (e MissingEnum) String() string { + return string(e) +} + +func (e *MissingEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = MissingEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid MissingEnum", str) + } + return nil +} + +func (e MissingEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} diff --git a/plugin/modelgen/out_struct_pointers/generated.go b/plugin/modelgen/out_struct_pointers/generated.go index c84c31f388e..a41c9826158 100644 --- a/plugin/modelgen/out_struct_pointers/generated.go +++ b/plugin/modelgen/out_struct_pointers/generated.go @@ -12,6 +12,10 @@ type A interface { IsA() } +type Animal interface { + IsAnimal() +} + type B interface { IsB() } @@ -50,6 +54,10 @@ type UnionWithDescription interface { } type CDImplemented struct { + C + A + D + B A string `json:"a" database:"CDImplementeda"` B int `json:"b" database:"CDImplementedb"` C bool `json:"c" database:"CDImplementedc"` @@ -83,12 +91,24 @@ type FieldMutationHook struct { Repeated *string `json:"repeated" someTag:"value" repeated:"true" database:"FieldMutationHookrepeated"` } +type Human struct { + Animal + Species string `json:"species" database:"Humanspecies"` + Name string `json:"name" database:"Humanname"` +} + +func (Human) IsAnimal() {} + type MissingInput struct { Name *string `json:"name" database:"MissingInputname"` Enum *MissingEnum `json:"enum" database:"MissingInputenum"` } type MissingTypeNotNull struct { + MissingInterface + ExistingInterface + MissingUnion + ExistingUnion Name string `json:"name" database:"MissingTypeNotNullname"` Enum MissingEnum `json:"enum" database:"MissingTypeNotNullenum"` Int MissingInterface `json:"int" database:"MissingTypeNotNullint"` @@ -102,6 +122,10 @@ func (MissingTypeNotNull) IsMissingUnion() {} func (MissingTypeNotNull) IsExistingUnion() {} type MissingTypeNullable struct { + MissingInterface + ExistingInterface + MissingUnion + ExistingUnion Name *string `json:"name" database:"MissingTypeNullablename"` Enum *MissingEnum `json:"enum" database:"MissingTypeNullableenum"` Int MissingInterface `json:"int" database:"MissingTypeNullableint"` @@ -133,12 +157,14 @@ type Recursive struct { // TypeWithDescription is a type with a description type TypeWithDescription struct { + UnionWithDescription Name *string `json:"name" database:"TypeWithDescriptionname"` } func (TypeWithDescription) IsUnionWithDescription() {} type FooBarr struct { + FooBarer Name string `json:"name" database:"_Foo_Barrname"` } diff --git a/plugin/modelgen/testdata/gqlgen_interface_field_methods.yml b/plugin/modelgen/testdata/gqlgen_interface_field_methods.yml new file mode 100644 index 00000000000..6d864876f90 --- /dev/null +++ b/plugin/modelgen/testdata/gqlgen_interface_field_methods.yml @@ -0,0 +1,24 @@ +schema: + - "testdata/schema.graphql" + +exec: + filename: out_interface_field_methods/ignored.go +model: + filename: out_interface_field_methods/generated.go + +generate_embedded_structs_for_interfaces: true + +models: + ExistingModel: + model: github.com/99designs/gqlgen/plugin/modelgen/out_interface_field_methods.ExistingModel + ExistingInput: + model: github.com/99designs/gqlgen/plugin/modelgen/out_interface_field_methods.ExistingInput + ExistingEnum: + model: github.com/99designs/gqlgen/plugin/modelgen/out_interface_field_methods.ExistingEnum + ExistingInterface: + model: github.com/99designs/gqlgen/plugin/modelgen/out_interface_field_methods.ExistingInterface + ExistingUnion: + model: github.com/99designs/gqlgen/plugin/modelgen/out_interface_field_methods.ExistingUnion + ExistingType: + model: github.com/99designs/gqlgen/plugin/modelgen/out_interface_field_methods.ExistingType + diff --git a/plugin/modelgen/testdata/schema.graphql b/plugin/modelgen/testdata/schema.graphql index 23fd26ced81..c29b528cb29 100644 --- a/plugin/modelgen/testdata/schema.graphql +++ b/plugin/modelgen/testdata/schema.graphql @@ -164,3 +164,12 @@ type Recursive { FieldThree: Recursive! FieldFour: String! } + +interface Animal { + species: String! +} + +type Human implements Animal { + species: String! + name: String! +}