From 4a763392f2ccc90ae40d7ce45e26bb11bb5eeee7 Mon Sep 17 00:00:00 2001 From: abe-tetsu Date: Wed, 18 Dec 2024 16:43:46 +0900 Subject: [PATCH 1/8] add EnableModelJsonOmitemptyTag to config --- config/config.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/config/config.go b/config/config.go index a823e91..ef432f5 100644 --- a/config/config.go +++ b/config/config.go @@ -22,14 +22,15 @@ import ( // Config extends the gqlgen basic config // and represents the config file type Config struct { - SchemaFilename StringList `yaml:"schema,omitempty"` - Model config.PackageConfig `yaml:"model,omitempty"` - AutoBind []string `yaml:"autobind"` - Client config.PackageConfig `yaml:"client,omitempty"` - Federation config.PackageConfig `yaml:"federation,omitempty"` - Models config.TypeMap `yaml:"models,omitempty"` - Endpoint *EndPointConfig `yaml:"endpoint,omitempty"` - Generate *GenerateConfig `yaml:"generate,omitempty"` + SchemaFilename StringList `yaml:"schema,omitempty"` + Model config.PackageConfig `yaml:"model,omitempty"` + AutoBind []string `yaml:"autobind"` + Client config.PackageConfig `yaml:"client,omitempty"` + Federation config.PackageConfig `yaml:"federation,omitempty"` + Models config.TypeMap `yaml:"models,omitempty"` + Endpoint *EndPointConfig `yaml:"endpoint,omitempty"` + Generate *GenerateConfig `yaml:"generate,omitempty"` + EnableModelJsonOmitemptyTag *bool `yaml:"enable_model_json_omitempty_tag,omitempty"` Query []string `yaml:"query"` @@ -223,6 +224,7 @@ func LoadConfig(filename string) (*Config, error) { ReturnPointersInUnmarshalInput: false, ResolversAlwaysReturnPointers: true, NullableInputOmittable: false, + EnableModelJsonOmitemptyTag: cfg.EnableModelJsonOmitemptyTag, } if err := cfg.Client.Check(); err != nil { From c42826d786fa63d6ae37062a76b29e8669235805 Mon Sep 17 00:00:00 2001 From: abe-tetsu Date: Wed, 18 Dec 2024 19:05:41 +0900 Subject: [PATCH 2/8] fix: Refer to the value of EnableClientJsonOmitemptyTag --- clientgenv2/client.go | 2 +- clientgenv2/source_generator.go | 31 ++++++++++++++----------- config/config.go | 18 +++++++------- config/generate_config.go | 25 ++++++++++++++++---- config/testdata/cfg/generate.yml | 1 + example/skipmodel/.gqlgenc.yml | 1 + example/skipmodel/gen/client.go | 23 +++++++++++++++++- example/skipmodel/query/query.graphql | 3 +++ example/skipmodel/schema/schema.graphql | 2 +- 9 files changed, 75 insertions(+), 31 deletions(-) diff --git a/clientgenv2/client.go b/clientgenv2/client.go index 0b6cae0..d6bb74a 100644 --- a/clientgenv2/client.go +++ b/clientgenv2/client.go @@ -36,7 +36,7 @@ func (p *Plugin) Name() string { func (p *Plugin) MutateConfig(cfg *config.Config) error { // テンプレートと情報ソースを元にコード生成 // Generate code from template and document source - sourceGenerator := NewSourceGenerator(cfg, p.Client) + sourceGenerator := NewSourceGenerator(cfg, p.Client, p.GenerateConfig) source := NewSource(cfg.Schema, p.queryDocument, sourceGenerator, p.GenerateConfig) fragments, err := source.Fragments() diff --git a/clientgenv2/source_generator.go b/clientgenv2/source_generator.go index 12e41c4..ae68d58 100644 --- a/clientgenv2/source_generator.go +++ b/clientgenv2/source_generator.go @@ -2,6 +2,7 @@ package clientgenv2 import ( "fmt" + gqlgencConfig "github.com/Yamashou/gqlgenc/config" "go/types" "strings" @@ -81,18 +82,20 @@ type StructSource struct { } type SourceGenerator struct { - cfg *config.Config - binder *config.Binder - client config.PackageConfig - StructSources []*StructSource + cfg *config.Config + binder *config.Binder + client config.PackageConfig + StructSources []*StructSource + GenerateConfig *gqlgencConfig.GenerateConfig } -func NewSourceGenerator(cfg *config.Config, client config.PackageConfig) *SourceGenerator { +func NewSourceGenerator(cfg *config.Config, client config.PackageConfig, generateConfig *gqlgencConfig.GenerateConfig) *SourceGenerator { return &SourceGenerator{ - cfg: cfg, - binder: cfg.NewBinder(), - client: client, - StructSources: []*StructSource{}, + cfg: cfg, + binder: cfg.NewBinder(), + client: client, + StructSources: []*StructSource{}, + GenerateConfig: generateConfig, } } @@ -110,13 +113,13 @@ func NewLayerTypeName(base, thisField string) string { } func (r *SourceGenerator) NewResponseField(selection ast.Selection, typeName string) *ResponseField { - var nonNull bool + var isOptional bool switch selection := selection.(type) { case *ast.Field: typeName = NewLayerTypeName(typeName, templates.ToGo(selection.Alias)) fieldsResponseFields := r.NewResponseFields(selection.SelectionSet, typeName) - nonNull = selection.Definition.Type.NonNull + isOptional = !selection.Definition.Type.NonNull var baseType types.Type switch { @@ -147,9 +150,9 @@ func (r *SourceGenerator) NewResponseField(selection ast.Selection, typeName str // return pointer type then optional type or slice pointer then slice type of definition in GraphQL. typ := r.binder.CopyModifiersFromAst(selection.Definition.Type, baseType) - jsonTag := fmt.Sprintf(`json:"%s,omitempty"`, selection.Alias) - if nonNull { - jsonTag = fmt.Sprintf(`json:"%s"`, selection.Alias) + jsonTag := fmt.Sprintf(`json:"%s"`, selection.Alias) + if r.GenerateConfig.IsEnableClientJsonOmitemptyTag() && isOptional { + jsonTag = fmt.Sprintf(`json:"%s,omitempty"`, selection.Alias) } tags := []string{ jsonTag, diff --git a/config/config.go b/config/config.go index ef432f5..a823e91 100644 --- a/config/config.go +++ b/config/config.go @@ -22,15 +22,14 @@ import ( // Config extends the gqlgen basic config // and represents the config file type Config struct { - SchemaFilename StringList `yaml:"schema,omitempty"` - Model config.PackageConfig `yaml:"model,omitempty"` - AutoBind []string `yaml:"autobind"` - Client config.PackageConfig `yaml:"client,omitempty"` - Federation config.PackageConfig `yaml:"federation,omitempty"` - Models config.TypeMap `yaml:"models,omitempty"` - Endpoint *EndPointConfig `yaml:"endpoint,omitempty"` - Generate *GenerateConfig `yaml:"generate,omitempty"` - EnableModelJsonOmitemptyTag *bool `yaml:"enable_model_json_omitempty_tag,omitempty"` + SchemaFilename StringList `yaml:"schema,omitempty"` + Model config.PackageConfig `yaml:"model,omitempty"` + AutoBind []string `yaml:"autobind"` + Client config.PackageConfig `yaml:"client,omitempty"` + Federation config.PackageConfig `yaml:"federation,omitempty"` + Models config.TypeMap `yaml:"models,omitempty"` + Endpoint *EndPointConfig `yaml:"endpoint,omitempty"` + Generate *GenerateConfig `yaml:"generate,omitempty"` Query []string `yaml:"query"` @@ -224,7 +223,6 @@ func LoadConfig(filename string) (*Config, error) { ReturnPointersInUnmarshalInput: false, ResolversAlwaysReturnPointers: true, NullableInputOmittable: false, - EnableModelJsonOmitemptyTag: cfg.EnableModelJsonOmitemptyTag, } if err := cfg.Client.Check(); err != nil { diff --git a/config/generate_config.go b/config/generate_config.go index f33253e..7d48071 100644 --- a/config/generate_config.go +++ b/config/generate_config.go @@ -7,10 +7,12 @@ type GenerateConfig struct { // Deprecated: not working because it is generated by gqlgen Query *bool `yaml:"query,omitempty"` // Deprecated: not working because it is generated by gqlgen - Mutation *bool `yaml:"mutation,omitempty"` - Client *bool `yaml:"client,omitempty"` - ClientInterfaceName *string `yaml:"clientInterfaceName,omitempty"` - OmitEmptyTypes *bool `yaml:"omitEmptyTypes,omitempty"` + Mutation *bool `yaml:"mutation,omitempty"` + Client *bool `yaml:"client,omitempty"` + ClientInterfaceName *string `yaml:"clientInterfaceName,omitempty"` + OmitEmptyTypes *bool `yaml:"omitEmptyTypes,omitempty"` + EnableClientJsonOmitemptyTag *bool `yaml:"enableClientJsonOmitemptyTag,omitempty"` + // Deprecated: not working because v1 is deleted. Must use ClientV2 // if true, used client v2 in generate code ClientV2 bool `yaml:"clientV2,omitempty"` @@ -42,6 +44,21 @@ func (c *GenerateConfig) ShouldOmitEmptyTypes() bool { return false } +// IsEnableClientJsonOmitemptyTag controls whether the "omitempty" option is added to JSON tags. +// If EnableClientJsonOmitemptyTag is set to false, even optional fields will not include "omitempty". +// The default value is true. +func (c *GenerateConfig) IsEnableClientJsonOmitemptyTag() bool { + if c == nil { + return true + } + + if c.EnableClientJsonOmitemptyTag != nil && *c.EnableClientJsonOmitemptyTag { + return true + } + + return false +} + func (c *GenerateConfig) GetClientInterfaceName() *string { if c == nil { return nil diff --git a/config/testdata/cfg/generate.yml b/config/testdata/cfg/generate.yml index dc07180..0793ed8 100644 --- a/config/testdata/cfg/generate.yml +++ b/config/testdata/cfg/generate.yml @@ -14,3 +14,4 @@ generate: suffix: mutation: Bar query: Foo +enable_model_json_omitempty_tag: false diff --git a/example/skipmodel/.gqlgenc.yml b/example/skipmodel/.gqlgenc.yml index 17fabfd..cff06e7 100644 --- a/example/skipmodel/.gqlgenc.yml +++ b/example/skipmodel/.gqlgenc.yml @@ -12,3 +12,4 @@ query: generate: clientV2: true onlyUsedModels: true + enableClientJsonOmitemptyTag: false diff --git a/example/skipmodel/gen/client.go b/example/skipmodel/gen/client.go index f11a0c6..ad35317 100644 --- a/example/skipmodel/gen/client.go +++ b/example/skipmodel/gen/client.go @@ -17,16 +17,34 @@ func NewClient(cli clientv2.HttpClient, baseURL string, options *clientv2.Option return &Client{Client: clientv2.NewClient(cli, baseURL, options, interceptors...)} } -type A_User struct { +type A_User_Profile struct { ID string "json:\"id\" graphql:\"id\"" } +func (t *A_User_Profile) GetID() string { + if t == nil { + t = &A_User_Profile{} + } + return t.ID +} + +type A_User struct { + ID string "json:\"id\" graphql:\"id\"" + Profile *A_User_Profile "json:\"profile\" graphql:\"profile\"" +} + func (t *A_User) GetID() string { if t == nil { t = &A_User{} } return t.ID } +func (t *A_User) GetProfile() *A_User_Profile { + if t == nil { + t = &A_User{} + } + return t.Profile +} type A struct { User A_User "json:\"user\" graphql:\"user\"" @@ -42,6 +60,9 @@ func (t *A) GetUser() *A_User { const ADocument = `mutation A ($input: UserInput!) { user(input: $input) { id + profile { + id + } } } ` diff --git a/example/skipmodel/query/query.graphql b/example/skipmodel/query/query.graphql index 3721aa5..f31d353 100644 --- a/example/skipmodel/query/query.graphql +++ b/example/skipmodel/query/query.graphql @@ -1,5 +1,8 @@ mutation A($input: UserInput!) { user(input: $input) { id + profile { + id + } } } diff --git a/example/skipmodel/schema/schema.graphql b/example/skipmodel/schema/schema.graphql index e71e83b..3809c71 100644 --- a/example/skipmodel/schema/schema.graphql +++ b/example/skipmodel/schema/schema.graphql @@ -23,7 +23,7 @@ input ProfileInput { type User { id: ID! - profile: Profile! + profile: Profile } type Profile { From 4a5bf204492a644e411d71707e2750edc44aaca3 Mon Sep 17 00:00:00 2001 From: abe-tetsu Date: Wed, 18 Dec 2024 19:07:11 +0900 Subject: [PATCH 3/8] fix: Remove unwanted changes --- config/testdata/cfg/generate.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/testdata/cfg/generate.yml b/config/testdata/cfg/generate.yml index 0793ed8..dc07180 100644 --- a/config/testdata/cfg/generate.yml +++ b/config/testdata/cfg/generate.yml @@ -14,4 +14,3 @@ generate: suffix: mutation: Bar query: Foo -enable_model_json_omitempty_tag: false From fb8792c901328a9aeccf96d25ccbfe023d0eca10 Mon Sep 17 00:00:00 2001 From: abe-tetsu Date: Wed, 18 Dec 2024 19:15:45 +0900 Subject: [PATCH 4/8] add README.md about enableClientJsonOmitemptyTag --- README.md | 1 + clientgenv2/source_generator.go | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 63444f3..aedc429 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ generate: clientInterfaceName: "GithubGraphQLClient" # Determine the name of the generated client interface structFieldsAlwaysPointers: true # Optional: Always use pointers for struct fields (default: true). [same as gqlgen](https://github.com/99designs/gqlgen/blob/e1ef86e795e738654c98553b325a248c02c8c2f8/docs/content/config.md?plain=1#L73) onlyUsedModels: true # Optional: Only generate used models + enableClientJsonOmitemptyTag: true # Optional: Controls whether the "omitempty" option is added to JSON tags (default: true) ``` Execute the following command on same directory for .gqlgenc.yml diff --git a/clientgenv2/source_generator.go b/clientgenv2/source_generator.go index ae68d58..11f23be 100644 --- a/clientgenv2/source_generator.go +++ b/clientgenv2/source_generator.go @@ -85,8 +85,8 @@ type SourceGenerator struct { cfg *config.Config binder *config.Binder client config.PackageConfig + generateConfig *gqlgencConfig.GenerateConfig StructSources []*StructSource - GenerateConfig *gqlgencConfig.GenerateConfig } func NewSourceGenerator(cfg *config.Config, client config.PackageConfig, generateConfig *gqlgencConfig.GenerateConfig) *SourceGenerator { @@ -95,7 +95,7 @@ func NewSourceGenerator(cfg *config.Config, client config.PackageConfig, generat binder: cfg.NewBinder(), client: client, StructSources: []*StructSource{}, - GenerateConfig: generateConfig, + generateConfig: generateConfig, } } @@ -151,7 +151,7 @@ func (r *SourceGenerator) NewResponseField(selection ast.Selection, typeName str typ := r.binder.CopyModifiersFromAst(selection.Definition.Type, baseType) jsonTag := fmt.Sprintf(`json:"%s"`, selection.Alias) - if r.GenerateConfig.IsEnableClientJsonOmitemptyTag() && isOptional { + if r.generateConfig.IsEnableClientJsonOmitemptyTag() && isOptional { jsonTag = fmt.Sprintf(`json:"%s,omitempty"`, selection.Alias) } tags := []string{ From c845005dffd0e828ab4594b7da1005be56ea52ba Mon Sep 17 00:00:00 2001 From: abe-tetsu Date: Wed, 18 Dec 2024 19:17:19 +0900 Subject: [PATCH 5/8] fix: generateConfig --- clientgenv2/source_generator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clientgenv2/source_generator.go b/clientgenv2/source_generator.go index 11f23be..3b7705b 100644 --- a/clientgenv2/source_generator.go +++ b/clientgenv2/source_generator.go @@ -94,8 +94,8 @@ func NewSourceGenerator(cfg *config.Config, client config.PackageConfig, generat cfg: cfg, binder: cfg.NewBinder(), client: client, - StructSources: []*StructSource{}, generateConfig: generateConfig, + StructSources: []*StructSource{}, } } From 2324b3705ea04c8a2291ed9767bc4470e5cf7c8b Mon Sep 17 00:00:00 2001 From: abe-tetsu Date: Wed, 18 Dec 2024 19:42:18 +0900 Subject: [PATCH 6/8] fix --- clientgenv2/source_generator.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clientgenv2/source_generator.go b/clientgenv2/source_generator.go index 3b7705b..a7f8c7e 100644 --- a/clientgenv2/source_generator.go +++ b/clientgenv2/source_generator.go @@ -2,7 +2,7 @@ package clientgenv2 import ( "fmt" - gqlgencConfig "github.com/Yamashou/gqlgenc/config" + gqlgencConfiga "github.com/Yamashou/gqlgenc/config" "go/types" "strings" @@ -85,11 +85,11 @@ type SourceGenerator struct { cfg *config.Config binder *config.Binder client config.PackageConfig - generateConfig *gqlgencConfig.GenerateConfig + generateConfig *gqlgencConfiga.GenerateConfig StructSources []*StructSource } -func NewSourceGenerator(cfg *config.Config, client config.PackageConfig, generateConfig *gqlgencConfig.GenerateConfig) *SourceGenerator { +func NewSourceGenerator(cfg *config.Config, client config.PackageConfig, generateConfig *gqlgencConfiga.GenerateConfig) *SourceGenerator { return &SourceGenerator{ cfg: cfg, binder: cfg.NewBinder(), From 5edb1221ced83d8ac1d599c536ba6a72b12b6d14 Mon Sep 17 00:00:00 2001 From: abe-tetsu Date: Wed, 18 Dec 2024 19:48:17 +0900 Subject: [PATCH 7/8] fix --- clientgenv2/source_generator.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clientgenv2/source_generator.go b/clientgenv2/source_generator.go index a7f8c7e..e988f80 100644 --- a/clientgenv2/source_generator.go +++ b/clientgenv2/source_generator.go @@ -2,12 +2,12 @@ package clientgenv2 import ( "fmt" - gqlgencConfiga "github.com/Yamashou/gqlgenc/config" "go/types" "strings" "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/templates" + gqlgencConfig "github.com/Yamashou/gqlgenc/config" "github.com/vektah/gqlparser/v2/ast" "golang.org/x/text/cases" "golang.org/x/text/language" @@ -85,16 +85,16 @@ type SourceGenerator struct { cfg *config.Config binder *config.Binder client config.PackageConfig - generateConfig *gqlgencConfiga.GenerateConfig + GenerateConfig *gqlgencConfig.GenerateConfig StructSources []*StructSource } -func NewSourceGenerator(cfg *config.Config, client config.PackageConfig, generateConfig *gqlgencConfiga.GenerateConfig) *SourceGenerator { +func NewSourceGenerator(cfg *config.Config, client config.PackageConfig, generateConfig *gqlgencConfig.GenerateConfig) *SourceGenerator { return &SourceGenerator{ cfg: cfg, binder: cfg.NewBinder(), client: client, - generateConfig: generateConfig, + GenerateConfig: generateConfig, StructSources: []*StructSource{}, } } @@ -151,7 +151,7 @@ func (r *SourceGenerator) NewResponseField(selection ast.Selection, typeName str typ := r.binder.CopyModifiersFromAst(selection.Definition.Type, baseType) jsonTag := fmt.Sprintf(`json:"%s"`, selection.Alias) - if r.generateConfig.IsEnableClientJsonOmitemptyTag() && isOptional { + if r.GenerateConfig.IsEnableClientJsonOmitemptyTag() && isOptional { jsonTag = fmt.Sprintf(`json:"%s,omitempty"`, selection.Alias) } tags := []string{ From 5081f236593bf13b312e477da90ea5fbb5e92291 Mon Sep 17 00:00:00 2001 From: abe-tetsu Date: Wed, 18 Dec 2024 20:11:54 +0900 Subject: [PATCH 8/8] rename config field name --- clientgenv2/source_generator.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/clientgenv2/source_generator.go b/clientgenv2/source_generator.go index e988f80..05d6bfe 100644 --- a/clientgenv2/source_generator.go +++ b/clientgenv2/source_generator.go @@ -82,20 +82,20 @@ type StructSource struct { } type SourceGenerator struct { - cfg *config.Config - binder *config.Binder - client config.PackageConfig - GenerateConfig *gqlgencConfig.GenerateConfig - StructSources []*StructSource + cfg *config.Config + binder *config.Binder + client config.PackageConfig + genCfg *gqlgencConfig.GenerateConfig + StructSources []*StructSource } func NewSourceGenerator(cfg *config.Config, client config.PackageConfig, generateConfig *gqlgencConfig.GenerateConfig) *SourceGenerator { return &SourceGenerator{ - cfg: cfg, - binder: cfg.NewBinder(), - client: client, - GenerateConfig: generateConfig, - StructSources: []*StructSource{}, + cfg: cfg, + binder: cfg.NewBinder(), + client: client, + genCfg: generateConfig, + StructSources: []*StructSource{}, } } @@ -151,7 +151,7 @@ func (r *SourceGenerator) NewResponseField(selection ast.Selection, typeName str typ := r.binder.CopyModifiersFromAst(selection.Definition.Type, baseType) jsonTag := fmt.Sprintf(`json:"%s"`, selection.Alias) - if r.GenerateConfig.IsEnableClientJsonOmitemptyTag() && isOptional { + if r.genCfg.IsEnableClientJsonOmitemptyTag() && isOptional { jsonTag = fmt.Sprintf(`json:"%s,omitempty"`, selection.Alias) } tags := []string{