diff --git a/docs/genqlient.yaml b/docs/genqlient.yaml index 25aef2e6..f68ff657 100644 --- a/docs/genqlient.yaml +++ b/docs/genqlient.yaml @@ -77,6 +77,17 @@ context_type: context.Context # without making a query. client_getter: "github.com/you/yourpkg.GetClient" + +# If set, fields with a struct type will default to having +# the "pointer: true, omitempty: true" flag. +# +# This can be useful for struct schema where it would be burdensome +# to manually set the flags on a large number of fields. +# +# Defaults to false. +use_struct_references: boolean + + # A map from GraphQL type name to Go fully-qualified type name to override # the Go type genqlient will use for this GraphQL type. # diff --git a/generate/config.go b/generate/config.go index dc88eb55..60fb2c32 100644 --- a/generate/config.go +++ b/generate/config.go @@ -27,6 +27,7 @@ type Config struct { ContextType string `yaml:"context_type"` ClientGetter string `yaml:"client_getter"` Bindings map[string]*TypeBinding `yaml:"bindings"` + StructReferences bool `yaml:"use_struct_references"` // Set to true to use features that aren't fully ready to use. // diff --git a/generate/convert.go b/generate/convert.go index 3841e281..d4a21f1f 100644 --- a/generate/convert.go +++ b/generate/convert.go @@ -244,7 +244,15 @@ func (g *generator) convertType( goTyp, err := g.convertDefinition( namePrefix, def, typ.Position, selectionSet, options, queryOptions) - if options.GetPointer() { + if g.getStructReference(def) { + if options.Pointer == nil || *options.Pointer { + goTyp = &goPointerType{goTyp} + } + if options.Omitempty == nil || *options.Omitempty { + oe := true + options.Omitempty = &oe + } + } else if options.GetPointer() { // Whatever we get, wrap it in a pointer. (Because of the way the // options work, recursing here isn't as connvenient.) // Note this does []*T or [][]*T, not e.g. *[][]T. See #16. @@ -253,6 +261,14 @@ func (g *generator) convertType( return goTyp, err } +// getStructReference decides if a field should be of pointer type and have the omitempty flag set. +func (g *generator) getStructReference( + def *ast.Definition, +) bool { + return g.Config.StructReferences && + (def.Kind == ast.Object || def.Kind == ast.InputObject) +} + // convertDefinition decides the Go type we will generate corresponding to a // particular GraphQL named type. // diff --git a/generate/generate_test.go b/generate/generate_test.go index 8cce225f..f12c31c8 100644 --- a/generate/generate_test.go +++ b/generate/generate_test.go @@ -170,6 +170,10 @@ func TestGenerateWithConfig(t *testing.T) { Generated: "generated.go", ContextType: "github.com/Khan/genqlient/internal/testutil.MyContext", }}, + {"StructReferences", "", &Config{ + StructReferences: true, + Generated: "generated-structrefs.go", + }}, {"NoContext", "", &Config{ Generated: "generated.go", ContextType: "-", diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-StructReferences-testdata-queries-generated-structrefs.go b/generate/testdata/snapshots/TestGenerateWithConfig-StructReferences-testdata-queries-generated-structrefs.go new file mode 100644 index 00000000..e22ee660 --- /dev/null +++ b/generate/testdata/snapshots/TestGenerateWithConfig-StructReferences-testdata-queries-generated-structrefs.go @@ -0,0 +1,59 @@ +package queries + +// Code generated by github.com/Khan/genqlient, DO NOT EDIT. + +import ( + "context" + + "github.com/Khan/genqlient/graphql" +) + +// SimpleQueryResponse is returned by SimpleQuery on success. +type SimpleQueryResponse struct { + // user looks up a user by some stuff. + // + // See UserQueryInput for what stuff is supported. + // If query is null, returns the current user. + User *SimpleQueryUser `json:"user"` +} + +// GetUser returns SimpleQueryResponse.User, and is useful for accessing the field via an interface. +func (v *SimpleQueryResponse) GetUser() *SimpleQueryUser { return v.User } + +// SimpleQueryUser includes the requested fields of the GraphQL type User. +// The GraphQL type's documentation follows. +// +// A User is a user! +type SimpleQueryUser struct { + // id is the user's ID. + // + // It is stable, unique, and opaque, like all good IDs. + Id string `json:"id"` +} + +// GetId returns SimpleQueryUser.Id, and is useful for accessing the field via an interface. +func (v *SimpleQueryUser) GetId() string { return v.Id } + +func SimpleQuery( + ctx context.Context, + client graphql.Client, +) (*SimpleQueryResponse, error) { + var err error + + var retval SimpleQueryResponse + err = client.MakeRequest( + ctx, + "SimpleQuery", + ` +query SimpleQuery { + user { + id + } +} +`, + &retval, + nil, + ) + return &retval, err +} +