Add support for mapping all nullable types as pointers (#198)
This implements the approach suggested in https://github.com/Khan/genqlient/issues/178#issuecomment-1077559343. See the added documentation for the full behavior.
This commit is contained in:
@@ -26,6 +26,7 @@ type Config struct {
|
||||
ContextType string `yaml:"context_type"`
|
||||
ClientGetter string `yaml:"client_getter"`
|
||||
Bindings map[string]*TypeBinding `yaml:"bindings"`
|
||||
Optional string `yaml:"optional"`
|
||||
StructReferences bool `yaml:"use_struct_references"`
|
||||
Extensions bool `yaml:"use_extensions"`
|
||||
|
||||
|
||||
+1
-1
@@ -256,7 +256,7 @@ func (g *generator) convertType(
|
||||
oe := true
|
||||
options.Omitempty = &oe
|
||||
}
|
||||
} else if options.GetPointer() {
|
||||
} else if options.GetPointer() || (!typ.NonNull && g.Config.Optional == "pointer") {
|
||||
// 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.
|
||||
|
||||
+32
-16
@@ -147,55 +147,64 @@ func getDefaultConfig(t *testing.T) *Config {
|
||||
// configurations. It uses snapshots, just like TestGenerate.
|
||||
func TestGenerateWithConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
baseDir string // relative to dataDir
|
||||
config *Config // omits Schema and Operations, set below.
|
||||
name string
|
||||
baseDir string // relative to dataDir
|
||||
operations []string // overrides the default set below
|
||||
config *Config // omits Schema and Operations, set below.
|
||||
}{
|
||||
{"DefaultConfig", "", getDefaultConfig(t)},
|
||||
{"Subpackage", "", &Config{
|
||||
{"DefaultConfig", "", nil, getDefaultConfig(t)},
|
||||
{"Subpackage", "", nil, &Config{
|
||||
Generated: "mypkg/myfile.go",
|
||||
}},
|
||||
{"SubpackageConfig", "mypkg", &Config{
|
||||
{"SubpackageConfig", "mypkg", nil, &Config{
|
||||
Generated: "myfile.go", // (relative to genqlient.yaml)
|
||||
}},
|
||||
{"PackageName", "", &Config{
|
||||
{"PackageName", "", nil, &Config{
|
||||
Generated: "myfile.go",
|
||||
Package: "mypkg",
|
||||
}},
|
||||
{"ExportOperations", "", &Config{
|
||||
{"ExportOperations", "", nil, &Config{
|
||||
Generated: "generated.go",
|
||||
ExportOperations: "operations.json",
|
||||
}},
|
||||
{"CustomContext", "", &Config{
|
||||
{"CustomContext", "", nil, &Config{
|
||||
Generated: "generated.go",
|
||||
ContextType: "github.com/Khan/genqlient/internal/testutil.MyContext",
|
||||
}},
|
||||
{"StructReferences", "", &Config{
|
||||
{"StructReferences", "", nil, &Config{
|
||||
StructReferences: true,
|
||||
Generated: "generated-structrefs.go",
|
||||
}},
|
||||
{"NoContext", "", &Config{
|
||||
{"NoContext", "", nil, &Config{
|
||||
Generated: "generated.go",
|
||||
ContextType: "-",
|
||||
}},
|
||||
{"ClientGetter", "", &Config{
|
||||
{"ClientGetter", "", nil, &Config{
|
||||
Generated: "generated.go",
|
||||
ClientGetter: "github.com/Khan/genqlient/internal/testutil.GetClientFromContext",
|
||||
}},
|
||||
{"ClientGetterCustomContext", "", &Config{
|
||||
{"ClientGetterCustomContext", "", nil, &Config{
|
||||
Generated: "generated.go",
|
||||
ClientGetter: "github.com/Khan/genqlient/internal/testutil.GetClientFromMyContext",
|
||||
ContextType: "github.com/Khan/genqlient/internal/testutil.MyContext",
|
||||
}},
|
||||
{"ClientGetterNoContext", "", &Config{
|
||||
{"ClientGetterNoContext", "", nil, &Config{
|
||||
Generated: "generated.go",
|
||||
ClientGetter: "github.com/Khan/genqlient/internal/testutil.GetClientFromNowhere",
|
||||
ContextType: "-",
|
||||
}},
|
||||
{"Extensions", "", &Config{
|
||||
{"Extensions", "", nil, &Config{
|
||||
Generated: "generated.go",
|
||||
Extensions: true,
|
||||
}},
|
||||
{"OptionalValue", "", []string{"ListInput.graphql", "QueryWithSlices.graphql"}, &Config{
|
||||
Generated: "generated.go",
|
||||
Optional: "value",
|
||||
}},
|
||||
{"OptionalPointer", "", []string{"ListInput.graphql", "QueryWithSlices.graphql"}, &Config{
|
||||
Generated: "generated.go",
|
||||
Optional: "pointer",
|
||||
}},
|
||||
}
|
||||
|
||||
sourceFilename := "SimpleQuery.graphql"
|
||||
@@ -206,7 +215,14 @@ func TestGenerateWithConfig(t *testing.T) {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
err := config.ValidateAndFillDefaults(baseDir)
|
||||
config.Schema = []string{filepath.Join(dataDir, "schema.graphql")}
|
||||
config.Operations = []string{filepath.Join(dataDir, sourceFilename)}
|
||||
if test.operations == nil {
|
||||
config.Operations = []string{filepath.Join(dataDir, sourceFilename)}
|
||||
} else {
|
||||
config.Operations = make([]string, len(test.operations))
|
||||
for i := range test.operations {
|
||||
config.Operations[i] = filepath.Join(dataDir, test.operations[i])
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Vendored
+142
@@ -0,0 +1,142 @@
|
||||
// Code generated by github.com/Khan/genqlient, DO NOT EDIT.
|
||||
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Khan/genqlient/graphql"
|
||||
)
|
||||
|
||||
// ListInputQueryResponse is returned by ListInputQuery on success.
|
||||
type ListInputQueryResponse 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 *ListInputQueryUser `json:"user"`
|
||||
}
|
||||
|
||||
// GetUser returns ListInputQueryResponse.User, and is useful for accessing the field via an interface.
|
||||
func (v *ListInputQueryResponse) GetUser() *ListInputQueryUser { return v.User }
|
||||
|
||||
// ListInputQueryUser includes the requested fields of the GraphQL type User.
|
||||
// The GraphQL type's documentation follows.
|
||||
//
|
||||
// A User is a user!
|
||||
type ListInputQueryUser struct {
|
||||
// id is the user's ID.
|
||||
//
|
||||
// It is stable, unique, and opaque, like all good IDs.
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// GetId returns ListInputQueryUser.Id, and is useful for accessing the field via an interface.
|
||||
func (v *ListInputQueryUser) GetId() string { return v.Id }
|
||||
|
||||
// QueryWithSlicesResponse is returned by QueryWithSlices on success.
|
||||
type QueryWithSlicesResponse 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 *QueryWithSlicesUser `json:"user"`
|
||||
}
|
||||
|
||||
// GetUser returns QueryWithSlicesResponse.User, and is useful for accessing the field via an interface.
|
||||
func (v *QueryWithSlicesResponse) GetUser() *QueryWithSlicesUser { return v.User }
|
||||
|
||||
// QueryWithSlicesUser includes the requested fields of the GraphQL type User.
|
||||
// The GraphQL type's documentation follows.
|
||||
//
|
||||
// A User is a user!
|
||||
type QueryWithSlicesUser struct {
|
||||
Emails []string `json:"emails"`
|
||||
EmailsOrNull []string `json:"emailsOrNull"`
|
||||
EmailsWithNulls []*string `json:"emailsWithNulls"`
|
||||
EmailsWithNullsOrNull []*string `json:"emailsWithNullsOrNull"`
|
||||
}
|
||||
|
||||
// GetEmails returns QueryWithSlicesUser.Emails, and is useful for accessing the field via an interface.
|
||||
func (v *QueryWithSlicesUser) GetEmails() []string { return v.Emails }
|
||||
|
||||
// GetEmailsOrNull returns QueryWithSlicesUser.EmailsOrNull, and is useful for accessing the field via an interface.
|
||||
func (v *QueryWithSlicesUser) GetEmailsOrNull() []string { return v.EmailsOrNull }
|
||||
|
||||
// GetEmailsWithNulls returns QueryWithSlicesUser.EmailsWithNulls, and is useful for accessing the field via an interface.
|
||||
func (v *QueryWithSlicesUser) GetEmailsWithNulls() []*string { return v.EmailsWithNulls }
|
||||
|
||||
// GetEmailsWithNullsOrNull returns QueryWithSlicesUser.EmailsWithNullsOrNull, and is useful for accessing the field via an interface.
|
||||
func (v *QueryWithSlicesUser) GetEmailsWithNullsOrNull() []*string { return v.EmailsWithNullsOrNull }
|
||||
|
||||
// __ListInputQueryInput is used internally by genqlient
|
||||
type __ListInputQueryInput struct {
|
||||
Names []*string `json:"names"`
|
||||
}
|
||||
|
||||
// GetNames returns __ListInputQueryInput.Names, and is useful for accessing the field via an interface.
|
||||
func (v *__ListInputQueryInput) GetNames() []*string { return v.Names }
|
||||
|
||||
func ListInputQuery(
|
||||
ctx context.Context,
|
||||
client graphql.Client,
|
||||
names []*string,
|
||||
) (*ListInputQueryResponse, error) {
|
||||
req := &graphql.Request{
|
||||
OpName: "ListInputQuery",
|
||||
Query: `
|
||||
query ListInputQuery ($names: [String]) {
|
||||
user(query: {names:$names}) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`,
|
||||
Variables: &__ListInputQueryInput{
|
||||
Names: names,
|
||||
},
|
||||
}
|
||||
var err error
|
||||
|
||||
var data ListInputQueryResponse
|
||||
resp := &graphql.Response{Data: &data}
|
||||
|
||||
err = client.MakeRequest(
|
||||
ctx,
|
||||
req,
|
||||
resp,
|
||||
)
|
||||
|
||||
return &data, err
|
||||
}
|
||||
|
||||
func QueryWithSlices(
|
||||
ctx context.Context,
|
||||
client graphql.Client,
|
||||
) (*QueryWithSlicesResponse, error) {
|
||||
req := &graphql.Request{
|
||||
OpName: "QueryWithSlices",
|
||||
Query: `
|
||||
query QueryWithSlices {
|
||||
user {
|
||||
emails
|
||||
emailsOrNull
|
||||
emailsWithNulls
|
||||
emailsWithNullsOrNull
|
||||
}
|
||||
}
|
||||
`,
|
||||
}
|
||||
var err error
|
||||
|
||||
var data QueryWithSlicesResponse
|
||||
resp := &graphql.Response{Data: &data}
|
||||
|
||||
err = client.MakeRequest(
|
||||
ctx,
|
||||
req,
|
||||
resp,
|
||||
)
|
||||
|
||||
return &data, err
|
||||
}
|
||||
|
||||
Vendored
+142
@@ -0,0 +1,142 @@
|
||||
// Code generated by github.com/Khan/genqlient, DO NOT EDIT.
|
||||
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Khan/genqlient/graphql"
|
||||
)
|
||||
|
||||
// ListInputQueryResponse is returned by ListInputQuery on success.
|
||||
type ListInputQueryResponse 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 ListInputQueryUser `json:"user"`
|
||||
}
|
||||
|
||||
// GetUser returns ListInputQueryResponse.User, and is useful for accessing the field via an interface.
|
||||
func (v *ListInputQueryResponse) GetUser() ListInputQueryUser { return v.User }
|
||||
|
||||
// ListInputQueryUser includes the requested fields of the GraphQL type User.
|
||||
// The GraphQL type's documentation follows.
|
||||
//
|
||||
// A User is a user!
|
||||
type ListInputQueryUser struct {
|
||||
// id is the user's ID.
|
||||
//
|
||||
// It is stable, unique, and opaque, like all good IDs.
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// GetId returns ListInputQueryUser.Id, and is useful for accessing the field via an interface.
|
||||
func (v *ListInputQueryUser) GetId() string { return v.Id }
|
||||
|
||||
// QueryWithSlicesResponse is returned by QueryWithSlices on success.
|
||||
type QueryWithSlicesResponse 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 QueryWithSlicesUser `json:"user"`
|
||||
}
|
||||
|
||||
// GetUser returns QueryWithSlicesResponse.User, and is useful for accessing the field via an interface.
|
||||
func (v *QueryWithSlicesResponse) GetUser() QueryWithSlicesUser { return v.User }
|
||||
|
||||
// QueryWithSlicesUser includes the requested fields of the GraphQL type User.
|
||||
// The GraphQL type's documentation follows.
|
||||
//
|
||||
// A User is a user!
|
||||
type QueryWithSlicesUser struct {
|
||||
Emails []string `json:"emails"`
|
||||
EmailsOrNull []string `json:"emailsOrNull"`
|
||||
EmailsWithNulls []string `json:"emailsWithNulls"`
|
||||
EmailsWithNullsOrNull []string `json:"emailsWithNullsOrNull"`
|
||||
}
|
||||
|
||||
// GetEmails returns QueryWithSlicesUser.Emails, and is useful for accessing the field via an interface.
|
||||
func (v *QueryWithSlicesUser) GetEmails() []string { return v.Emails }
|
||||
|
||||
// GetEmailsOrNull returns QueryWithSlicesUser.EmailsOrNull, and is useful for accessing the field via an interface.
|
||||
func (v *QueryWithSlicesUser) GetEmailsOrNull() []string { return v.EmailsOrNull }
|
||||
|
||||
// GetEmailsWithNulls returns QueryWithSlicesUser.EmailsWithNulls, and is useful for accessing the field via an interface.
|
||||
func (v *QueryWithSlicesUser) GetEmailsWithNulls() []string { return v.EmailsWithNulls }
|
||||
|
||||
// GetEmailsWithNullsOrNull returns QueryWithSlicesUser.EmailsWithNullsOrNull, and is useful for accessing the field via an interface.
|
||||
func (v *QueryWithSlicesUser) GetEmailsWithNullsOrNull() []string { return v.EmailsWithNullsOrNull }
|
||||
|
||||
// __ListInputQueryInput is used internally by genqlient
|
||||
type __ListInputQueryInput struct {
|
||||
Names []string `json:"names"`
|
||||
}
|
||||
|
||||
// GetNames returns __ListInputQueryInput.Names, and is useful for accessing the field via an interface.
|
||||
func (v *__ListInputQueryInput) GetNames() []string { return v.Names }
|
||||
|
||||
func ListInputQuery(
|
||||
ctx context.Context,
|
||||
client graphql.Client,
|
||||
names []string,
|
||||
) (*ListInputQueryResponse, error) {
|
||||
req := &graphql.Request{
|
||||
OpName: "ListInputQuery",
|
||||
Query: `
|
||||
query ListInputQuery ($names: [String]) {
|
||||
user(query: {names:$names}) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`,
|
||||
Variables: &__ListInputQueryInput{
|
||||
Names: names,
|
||||
},
|
||||
}
|
||||
var err error
|
||||
|
||||
var data ListInputQueryResponse
|
||||
resp := &graphql.Response{Data: &data}
|
||||
|
||||
err = client.MakeRequest(
|
||||
ctx,
|
||||
req,
|
||||
resp,
|
||||
)
|
||||
|
||||
return &data, err
|
||||
}
|
||||
|
||||
func QueryWithSlices(
|
||||
ctx context.Context,
|
||||
client graphql.Client,
|
||||
) (*QueryWithSlicesResponse, error) {
|
||||
req := &graphql.Request{
|
||||
OpName: "QueryWithSlices",
|
||||
Query: `
|
||||
query QueryWithSlices {
|
||||
user {
|
||||
emails
|
||||
emailsOrNull
|
||||
emailsWithNulls
|
||||
emailsWithNullsOrNull
|
||||
}
|
||||
}
|
||||
`,
|
||||
}
|
||||
var err error
|
||||
|
||||
var data QueryWithSlicesResponse
|
||||
resp := &graphql.Response{Data: &data}
|
||||
|
||||
err = client.MakeRequest(
|
||||
ctx,
|
||||
req,
|
||||
resp,
|
||||
)
|
||||
|
||||
return &data, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user