diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index f8c928a5..a0d704e2 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.20', '1.21', '1.22' ] + go: [ '1.18', '1.19', '1.20', '1.21' ] steps: - name: Set up Go diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index ee43b5fb..ba5c15f5 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -33,6 +33,7 @@ In addition to several new features and bugfixes, along with this release comes ### New features: - The new `optional: generic` allows using a generic type to represent optionality. See the [documentation](genqlient.yaml) for details. +- The new `optional: pointer_omitempty` allows using a pointer that is also annotated with `omitempty`. See the [documentation](genqlient.yaml) for details. - For schemas with enum values that differ only in casing, it's now possible to disable smart-casing in genqlient.yaml; see the [documentation](genqlient.yaml) for `casing` for details. - genqlient now supports .graphqls and .gql file extensions for schemas and queries. - More accurately guess the package name for generated code (and warn if the config option -- now almost never needed -- looks wrong). diff --git a/docs/genqlient.yaml b/docs/genqlient.yaml index 55178a29..3f4a1d6a 100644 --- a/docs/genqlient.yaml +++ b/docs/genqlient.yaml @@ -112,6 +112,9 @@ use_extensions: boolean # pointers-to-slices, so the GraphQL type `[String]` will map to the Go # type `[]*string`, not `*[]*string`; GraphQL null and empty list simply # map to Go nil- and empty-slice. +# - pointer_omitempty: optional fields are generated as pointers, as described above. +# Additionally, the fields are annotated with omitempty. Fields that are not defined, +# will not be exposed. # - generic: optional fields are generated as type parameters to a generic type # specified by `optional_generic_type`. E.g. fields with GraphQL type `String` # will map to the Go type `generic.Type[string]`. This is useful if you have a diff --git a/generate/config.go b/generate/config.go index bca64945..88cd176b 100644 --- a/generate/config.go +++ b/generate/config.go @@ -205,8 +205,8 @@ func (c *Config) ValidateAndFillDefaults(baseDir string) error { c.ContextType = "context.Context" } - if c.Optional != "" && c.Optional != "value" && c.Optional != "pointer" && c.Optional != "generic" { - return errorf(nil, "optional must be one of: 'value' (default), 'pointer', or 'generic'") + if c.Optional != "" && c.Optional != "value" && c.Optional != "pointer" && c.Optional != "pointer_omitempty" && c.Optional != "generic" { + return errorf(nil, "optional must be one of: 'value' (default), 'pointer', 'pointer_omitempty' or 'generic'") } if c.Optional == "generic" && c.OptionalGenericType == "" { diff --git a/generate/convert.go b/generate/convert.go index 3e3dc03f..c0fbbcee 100644 --- a/generate/convert.go +++ b/generate/convert.go @@ -257,6 +257,13 @@ func (g *generator) convertType( oe := true options.Omitempty = &oe } + } else if !options.PointerIsFalse() && (options.GetPointer() || !typ.NonNull) && g.Config.Optional == "pointer_omitempty" { + goTyp = &goPointerType{Elem: goTyp} + + if options.Omitempty == nil { + oe := true + options.Omitempty = &oe + } } else if !options.PointerIsFalse() && (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.) diff --git a/generate/generate_test.go b/generate/generate_test.go index 21dcaae2..e5f0ba04 100644 --- a/generate/generate_test.go +++ b/generate/generate_test.go @@ -9,8 +9,9 @@ import ( "strings" "testing" - "github.com/Khan/genqlient/internal/testutil" "gopkg.in/yaml.v2" + + "github.com/Khan/genqlient/internal/testutil" ) const ( @@ -240,6 +241,26 @@ func TestGenerateWithConfig(t *testing.T) { Enums: map[string]CasingAlgorithm{"Role": CasingRaw}, }, }}, + {"OptionalPointerOmitEmpty", "", []string{ + "InputObject.graphql", + "Pointers.graphql", + "Omitempty.graphql", + "ListInput.graphql", + }, &Config{ + Optional: "pointer_omitempty", + Bindings: map[string]*TypeBinding{ + "Date": { + Type: "time.Time", + Marshaler: "github.com/Khan/genqlient/internal/testutil.MarshalDate", + Unmarshaler: "github.com/Khan/genqlient/internal/testutil.UnmarshalDate", + }, + "DateTime": { + Type: "time.Time", + Marshaler: "github.com/Khan/genqlient/internal/testutil.MarshalDate", + Unmarshaler: "github.com/Khan/genqlient/internal/testutil.UnmarshalDate", + }, + }, + }}, } sourceFilename := "SimpleQuery.graphql" diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-OptionalPointerOmitEmpty-testdata-queries-generated.go b/generate/testdata/snapshots/TestGenerateWithConfig-OptionalPointerOmitEmpty-testdata-queries-generated.go new file mode 100644 index 00000000..87b8a605 --- /dev/null +++ b/generate/testdata/snapshots/TestGenerateWithConfig-OptionalPointerOmitEmpty-testdata-queries-generated.go @@ -0,0 +1,875 @@ +// Code generated by github.com/Khan/genqlient, DO NOT EDIT. + +package queries + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/Khan/genqlient/graphql" + "github.com/Khan/genqlient/internal/testutil" +) + +// InputObjectQueryResponse is returned by InputObjectQuery on success. +type InputObjectQueryResponse 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 *InputObjectQueryUser `json:"user"` +} + +// GetUser returns InputObjectQueryResponse.User, and is useful for accessing the field via an interface. +func (v *InputObjectQueryResponse) GetUser() *InputObjectQueryUser { return v.User } + +// InputObjectQueryUser includes the requested fields of the GraphQL type User. +// The GraphQL type's documentation follows. +// +// A User is a user! +type InputObjectQueryUser struct { + // id is the user's ID. + // + // It is stable, unique, and opaque, like all good IDs. + Id string `json:"id"` +} + +// GetId returns InputObjectQueryUser.Id, and is useful for accessing the field via an interface. +func (v *InputObjectQueryUser) GetId() string { return v.Id } + +// 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 } + +// OmitEmptyQueryResponse is returned by OmitEmptyQuery on success. +type OmitEmptyQueryResponse 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 *OmitEmptyQueryUser `json:"user"` + Users []*OmitEmptyQueryUsersUser `json:"users"` + MaybeConvert *time.Time `json:"-"` + Convert2 *time.Time `json:"-"` +} + +// GetUser returns OmitEmptyQueryResponse.User, and is useful for accessing the field via an interface. +func (v *OmitEmptyQueryResponse) GetUser() *OmitEmptyQueryUser { return v.User } + +// GetUsers returns OmitEmptyQueryResponse.Users, and is useful for accessing the field via an interface. +func (v *OmitEmptyQueryResponse) GetUsers() []*OmitEmptyQueryUsersUser { return v.Users } + +// GetMaybeConvert returns OmitEmptyQueryResponse.MaybeConvert, and is useful for accessing the field via an interface. +func (v *OmitEmptyQueryResponse) GetMaybeConvert() *time.Time { return v.MaybeConvert } + +// GetConvert2 returns OmitEmptyQueryResponse.Convert2, and is useful for accessing the field via an interface. +func (v *OmitEmptyQueryResponse) GetConvert2() *time.Time { return v.Convert2 } + +func (v *OmitEmptyQueryResponse) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *OmitEmptyQueryResponse + MaybeConvert json.RawMessage `json:"maybeConvert"` + Convert2 json.RawMessage `json:"convert2"` + graphql.NoUnmarshalJSON + } + firstPass.OmitEmptyQueryResponse = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + { + dst := &v.MaybeConvert + src := firstPass.MaybeConvert + if len(src) != 0 && string(src) != "null" { + *dst = new(time.Time) + err = testutil.UnmarshalDate( + src, *dst) + if err != nil { + return fmt.Errorf( + "unable to unmarshal OmitEmptyQueryResponse.MaybeConvert: %w", err) + } + } + } + + { + dst := &v.Convert2 + src := firstPass.Convert2 + if len(src) != 0 && string(src) != "null" { + *dst = new(time.Time) + err = testutil.UnmarshalDate( + src, *dst) + if err != nil { + return fmt.Errorf( + "unable to unmarshal OmitEmptyQueryResponse.Convert2: %w", err) + } + } + } + return nil +} + +type __premarshalOmitEmptyQueryResponse struct { + User *OmitEmptyQueryUser `json:"user"` + + Users []*OmitEmptyQueryUsersUser `json:"users"` + + MaybeConvert json.RawMessage `json:"maybeConvert"` + + Convert2 json.RawMessage `json:"convert2"` +} + +func (v *OmitEmptyQueryResponse) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *OmitEmptyQueryResponse) __premarshalJSON() (*__premarshalOmitEmptyQueryResponse, error) { + var retval __premarshalOmitEmptyQueryResponse + + retval.User = v.User + retval.Users = v.Users + { + + dst := &retval.MaybeConvert + src := v.MaybeConvert + if src != nil { + var err error + *dst, err = testutil.MarshalDate( + src) + if err != nil { + return nil, fmt.Errorf( + "unable to marshal OmitEmptyQueryResponse.MaybeConvert: %w", err) + } + } + } + { + + dst := &retval.Convert2 + src := v.Convert2 + if src != nil { + var err error + *dst, err = testutil.MarshalDate( + src) + if err != nil { + return nil, fmt.Errorf( + "unable to marshal OmitEmptyQueryResponse.Convert2: %w", err) + } + } + } + return &retval, nil +} + +// OmitEmptyQueryUser includes the requested fields of the GraphQL type User. +// The GraphQL type's documentation follows. +// +// A User is a user! +type OmitEmptyQueryUser struct { + // id is the user's ID. + // + // It is stable, unique, and opaque, like all good IDs. + Id string `json:"id"` +} + +// GetId returns OmitEmptyQueryUser.Id, and is useful for accessing the field via an interface. +func (v *OmitEmptyQueryUser) GetId() string { return v.Id } + +// OmitEmptyQueryUsersUser includes the requested fields of the GraphQL type User. +// The GraphQL type's documentation follows. +// +// A User is a user! +type OmitEmptyQueryUsersUser struct { + // id is the user's ID. + // + // It is stable, unique, and opaque, like all good IDs. + Id string `json:"id"` +} + +// GetId returns OmitEmptyQueryUsersUser.Id, and is useful for accessing the field via an interface. +func (v *OmitEmptyQueryUsersUser) GetId() string { return v.Id } + +// PointersQueryOtherUser includes the requested fields of the GraphQL type User. +// The GraphQL type's documentation follows. +// +// A User is a user! +type PointersQueryOtherUser struct { + // id is the user's ID. + // + // It is stable, unique, and opaque, like all good IDs. + Id string `json:"id"` +} + +// GetId returns PointersQueryOtherUser.Id, and is useful for accessing the field via an interface. +func (v *PointersQueryOtherUser) GetId() string { return v.Id } + +// PointersQueryResponse is returned by PointersQuery on success. +type PointersQueryResponse 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 *PointersQueryUser `json:"user"` + // user looks up a user by some stuff. + // + // See UserQueryInput for what stuff is supported. + // If query is null, returns the current user. + OtherUser *PointersQueryOtherUser `json:"otherUser"` + MaybeConvert *time.Time `json:"-"` +} + +// GetUser returns PointersQueryResponse.User, and is useful for accessing the field via an interface. +func (v *PointersQueryResponse) GetUser() *PointersQueryUser { return v.User } + +// GetOtherUser returns PointersQueryResponse.OtherUser, and is useful for accessing the field via an interface. +func (v *PointersQueryResponse) GetOtherUser() *PointersQueryOtherUser { return v.OtherUser } + +// GetMaybeConvert returns PointersQueryResponse.MaybeConvert, and is useful for accessing the field via an interface. +func (v *PointersQueryResponse) GetMaybeConvert() *time.Time { return v.MaybeConvert } + +func (v *PointersQueryResponse) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *PointersQueryResponse + MaybeConvert json.RawMessage `json:"maybeConvert"` + graphql.NoUnmarshalJSON + } + firstPass.PointersQueryResponse = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + { + dst := &v.MaybeConvert + src := firstPass.MaybeConvert + if len(src) != 0 && string(src) != "null" { + *dst = new(time.Time) + err = testutil.UnmarshalDate( + src, *dst) + if err != nil { + return fmt.Errorf( + "unable to unmarshal PointersQueryResponse.MaybeConvert: %w", err) + } + } + } + return nil +} + +type __premarshalPointersQueryResponse struct { + User *PointersQueryUser `json:"user"` + + OtherUser *PointersQueryOtherUser `json:"otherUser"` + + MaybeConvert json.RawMessage `json:"maybeConvert"` +} + +func (v *PointersQueryResponse) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *PointersQueryResponse) __premarshalJSON() (*__premarshalPointersQueryResponse, error) { + var retval __premarshalPointersQueryResponse + + retval.User = v.User + retval.OtherUser = v.OtherUser + { + + dst := &retval.MaybeConvert + src := v.MaybeConvert + if src != nil { + var err error + *dst, err = testutil.MarshalDate( + src) + if err != nil { + return nil, fmt.Errorf( + "unable to marshal PointersQueryResponse.MaybeConvert: %w", err) + } + } + } + return &retval, nil +} + +// PointersQueryUser includes the requested fields of the GraphQL type User. +// The GraphQL type's documentation follows. +// +// A User is a user! +type PointersQueryUser struct { + // id is the user's ID. + // + // It is stable, unique, and opaque, like all good IDs. + Id *string `json:"id"` + Roles []*Role `json:"roles"` + Name *string `json:"name"` + Emails []*string `json:"emails"` + EmailsNoPtr []string `json:"emailsNoPtr"` +} + +// GetId returns PointersQueryUser.Id, and is useful for accessing the field via an interface. +func (v *PointersQueryUser) GetId() *string { return v.Id } + +// GetRoles returns PointersQueryUser.Roles, and is useful for accessing the field via an interface. +func (v *PointersQueryUser) GetRoles() []*Role { return v.Roles } + +// GetName returns PointersQueryUser.Name, and is useful for accessing the field via an interface. +func (v *PointersQueryUser) GetName() *string { return v.Name } + +// GetEmails returns PointersQueryUser.Emails, and is useful for accessing the field via an interface. +func (v *PointersQueryUser) GetEmails() []*string { return v.Emails } + +// GetEmailsNoPtr returns PointersQueryUser.EmailsNoPtr, and is useful for accessing the field via an interface. +func (v *PointersQueryUser) GetEmailsNoPtr() []string { return v.EmailsNoPtr } + +type PokemonInput struct { + Species string `json:"species"` + Level int `json:"level"` +} + +// GetSpecies returns PokemonInput.Species, and is useful for accessing the field via an interface. +func (v *PokemonInput) GetSpecies() string { return v.Species } + +// GetLevel returns PokemonInput.Level, and is useful for accessing the field via an interface. +func (v *PokemonInput) GetLevel() int { return v.Level } + +// Role is a type a user may have. +type Role string + +const ( + // What is a student? + // + // A student is primarily a person enrolled in a school or other educational institution and who is under learning with goals of acquiring knowledge, developing professions and achieving employment at desired field. In the broader sense, a student is anyone who applies themselves to the intensive intellectual engagement with some matter necessary to master it as part of some practical affair in which such mastery is basic or decisive. + // + // (from [Wikipedia](https://en.wikipedia.org/wiki/Student)) + RoleStudent Role = "STUDENT" + // Teacher is a teacher, who teaches the students. + RoleTeacher Role = "TEACHER" +) + +// UserQueryInput is the argument to Query.users. +// +// Ideally this would support anything and everything! +// Or maybe ideally it wouldn't. +// Really I'm just talking to make this documentation longer. +type UserQueryInput struct { + Email *string `json:"email,omitempty"` + Name *string `json:"name,omitempty"` + // id looks the user up by ID. It's a great way to look up users. + Id *string `json:"id,omitempty"` + Role *Role `json:"role,omitempty"` + Names []*string `json:"names,omitempty"` + HasPokemon *PokemonInput `json:"hasPokemon,omitempty"` + Birthdate *time.Time `json:"-"` +} + +// GetEmail returns UserQueryInput.Email, and is useful for accessing the field via an interface. +func (v *UserQueryInput) GetEmail() *string { return v.Email } + +// GetName returns UserQueryInput.Name, and is useful for accessing the field via an interface. +func (v *UserQueryInput) GetName() *string { return v.Name } + +// GetId returns UserQueryInput.Id, and is useful for accessing the field via an interface. +func (v *UserQueryInput) GetId() *string { return v.Id } + +// GetRole returns UserQueryInput.Role, and is useful for accessing the field via an interface. +func (v *UserQueryInput) GetRole() *Role { return v.Role } + +// GetNames returns UserQueryInput.Names, and is useful for accessing the field via an interface. +func (v *UserQueryInput) GetNames() []*string { return v.Names } + +// GetHasPokemon returns UserQueryInput.HasPokemon, and is useful for accessing the field via an interface. +func (v *UserQueryInput) GetHasPokemon() *PokemonInput { return v.HasPokemon } + +// GetBirthdate returns UserQueryInput.Birthdate, and is useful for accessing the field via an interface. +func (v *UserQueryInput) GetBirthdate() *time.Time { return v.Birthdate } + +func (v *UserQueryInput) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *UserQueryInput + Birthdate json.RawMessage `json:"birthdate"` + graphql.NoUnmarshalJSON + } + firstPass.UserQueryInput = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + { + dst := &v.Birthdate + src := firstPass.Birthdate + if len(src) != 0 && string(src) != "null" { + *dst = new(time.Time) + err = testutil.UnmarshalDate( + src, *dst) + if err != nil { + return fmt.Errorf( + "unable to unmarshal UserQueryInput.Birthdate: %w", err) + } + } + } + return nil +} + +type __premarshalUserQueryInput struct { + Email *string `json:"email,omitempty"` + + Name *string `json:"name,omitempty"` + + Id *string `json:"id,omitempty"` + + Role *Role `json:"role,omitempty"` + + Names []*string `json:"names,omitempty"` + + HasPokemon *PokemonInput `json:"hasPokemon,omitempty"` + + Birthdate json.RawMessage `json:"birthdate,omitempty"` +} + +func (v *UserQueryInput) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *UserQueryInput) __premarshalJSON() (*__premarshalUserQueryInput, error) { + var retval __premarshalUserQueryInput + + retval.Email = v.Email + retval.Name = v.Name + retval.Id = v.Id + retval.Role = v.Role + retval.Names = v.Names + retval.HasPokemon = v.HasPokemon + { + + dst := &retval.Birthdate + src := v.Birthdate + if src != nil { + var err error + *dst, err = testutil.MarshalDate( + src) + if err != nil { + return nil, fmt.Errorf( + "unable to marshal UserQueryInput.Birthdate: %w", err) + } + } + } + return &retval, nil +} + +// __InputObjectQueryInput is used internally by genqlient +type __InputObjectQueryInput struct { + Query *UserQueryInput `json:"query,omitempty"` +} + +// GetQuery returns __InputObjectQueryInput.Query, and is useful for accessing the field via an interface. +func (v *__InputObjectQueryInput) GetQuery() *UserQueryInput { return v.Query } + +// __ListInputQueryInput is used internally by genqlient +type __ListInputQueryInput struct { + Names []*string `json:"names,omitempty"` +} + +// GetNames returns __ListInputQueryInput.Names, and is useful for accessing the field via an interface. +func (v *__ListInputQueryInput) GetNames() []*string { return v.Names } + +// __OmitEmptyQueryInput is used internally by genqlient +type __OmitEmptyQueryInput struct { + Query *UserQueryInput `json:"query,omitempty"` + Queries []*UserQueryInput `json:"queries,omitempty"` + Dt *time.Time `json:"-"` + Tz *string `json:"tz,omitempty"` + TzNoOmitEmpty *string `json:"tzNoOmitEmpty"` +} + +// GetQuery returns __OmitEmptyQueryInput.Query, and is useful for accessing the field via an interface. +func (v *__OmitEmptyQueryInput) GetQuery() *UserQueryInput { return v.Query } + +// GetQueries returns __OmitEmptyQueryInput.Queries, and is useful for accessing the field via an interface. +func (v *__OmitEmptyQueryInput) GetQueries() []*UserQueryInput { return v.Queries } + +// GetDt returns __OmitEmptyQueryInput.Dt, and is useful for accessing the field via an interface. +func (v *__OmitEmptyQueryInput) GetDt() *time.Time { return v.Dt } + +// GetTz returns __OmitEmptyQueryInput.Tz, and is useful for accessing the field via an interface. +func (v *__OmitEmptyQueryInput) GetTz() *string { return v.Tz } + +// GetTzNoOmitEmpty returns __OmitEmptyQueryInput.TzNoOmitEmpty, and is useful for accessing the field via an interface. +func (v *__OmitEmptyQueryInput) GetTzNoOmitEmpty() *string { return v.TzNoOmitEmpty } + +func (v *__OmitEmptyQueryInput) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *__OmitEmptyQueryInput + Dt json.RawMessage `json:"dt"` + graphql.NoUnmarshalJSON + } + firstPass.__OmitEmptyQueryInput = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + { + dst := &v.Dt + src := firstPass.Dt + if len(src) != 0 && string(src) != "null" { + *dst = new(time.Time) + err = testutil.UnmarshalDate( + src, *dst) + if err != nil { + return fmt.Errorf( + "unable to unmarshal __OmitEmptyQueryInput.Dt: %w", err) + } + } + } + return nil +} + +type __premarshal__OmitEmptyQueryInput struct { + Query *UserQueryInput `json:"query,omitempty"` + + Queries []*UserQueryInput `json:"queries,omitempty"` + + Dt json.RawMessage `json:"dt,omitempty"` + + Tz *string `json:"tz,omitempty"` + + TzNoOmitEmpty *string `json:"tzNoOmitEmpty"` +} + +func (v *__OmitEmptyQueryInput) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *__OmitEmptyQueryInput) __premarshalJSON() (*__premarshal__OmitEmptyQueryInput, error) { + var retval __premarshal__OmitEmptyQueryInput + + retval.Query = v.Query + retval.Queries = v.Queries + { + + dst := &retval.Dt + src := v.Dt + if src != nil { + var err error + *dst, err = testutil.MarshalDate( + src) + if err != nil { + return nil, fmt.Errorf( + "unable to marshal __OmitEmptyQueryInput.Dt: %w", err) + } + } + } + retval.Tz = v.Tz + retval.TzNoOmitEmpty = v.TzNoOmitEmpty + return &retval, nil +} + +// __PointersQueryInput is used internally by genqlient +type __PointersQueryInput struct { + Query *UserQueryInput `json:"query,omitempty"` + Dt time.Time `json:"-"` + Tz *string `json:"tz,omitempty"` +} + +// GetQuery returns __PointersQueryInput.Query, and is useful for accessing the field via an interface. +func (v *__PointersQueryInput) GetQuery() *UserQueryInput { return v.Query } + +// GetDt returns __PointersQueryInput.Dt, and is useful for accessing the field via an interface. +func (v *__PointersQueryInput) GetDt() time.Time { return v.Dt } + +// GetTz returns __PointersQueryInput.Tz, and is useful for accessing the field via an interface. +func (v *__PointersQueryInput) GetTz() *string { return v.Tz } + +func (v *__PointersQueryInput) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *__PointersQueryInput + Dt json.RawMessage `json:"dt"` + graphql.NoUnmarshalJSON + } + firstPass.__PointersQueryInput = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + { + dst := &v.Dt + src := firstPass.Dt + if len(src) != 0 && string(src) != "null" { + err = testutil.UnmarshalDate( + src, dst) + if err != nil { + return fmt.Errorf( + "unable to unmarshal __PointersQueryInput.Dt: %w", err) + } + } + } + return nil +} + +type __premarshal__PointersQueryInput struct { + Query *UserQueryInput `json:"query,omitempty"` + + Dt json.RawMessage `json:"dt"` + + Tz *string `json:"tz,omitempty"` +} + +func (v *__PointersQueryInput) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *__PointersQueryInput) __premarshalJSON() (*__premarshal__PointersQueryInput, error) { + var retval __premarshal__PointersQueryInput + + retval.Query = v.Query + { + + dst := &retval.Dt + src := v.Dt + var err error + *dst, err = testutil.MarshalDate( + &src) + if err != nil { + return nil, fmt.Errorf( + "unable to marshal __PointersQueryInput.Dt: %w", err) + } + } + retval.Tz = v.Tz + return &retval, nil +} + +// The query or mutation executed by InputObjectQuery. +const InputObjectQuery_Operation = ` +query InputObjectQuery ($query: UserQueryInput) { + user(query: $query) { + id + } +} +` + +func InputObjectQuery( + ctx_ context.Context, + client_ graphql.Client, + query *UserQueryInput, +) (*InputObjectQueryResponse, error) { + req_ := &graphql.Request{ + OpName: "InputObjectQuery", + Query: InputObjectQuery_Operation, + Variables: &__InputObjectQueryInput{ + Query: query, + }, + } + var err_ error + + var data_ InputObjectQueryResponse + resp_ := &graphql.Response{Data: &data_} + + err_ = client_.MakeRequest( + ctx_, + req_, + resp_, + ) + + return &data_, err_ +} + +// The query or mutation executed by ListInputQuery. +const ListInputQuery_Operation = ` +query ListInputQuery ($names: [String]) { + user(query: {names:$names}) { + id + } +} +` + +func ListInputQuery( + ctx_ context.Context, + client_ graphql.Client, + names []*string, +) (*ListInputQueryResponse, error) { + req_ := &graphql.Request{ + OpName: "ListInputQuery", + Query: ListInputQuery_Operation, + Variables: &__ListInputQueryInput{ + Names: names, + }, + } + var err_ error + + var data_ ListInputQueryResponse + resp_ := &graphql.Response{Data: &data_} + + err_ = client_.MakeRequest( + ctx_, + req_, + resp_, + ) + + return &data_, err_ +} + +// The query or mutation executed by OmitEmptyQuery. +const OmitEmptyQuery_Operation = ` +query OmitEmptyQuery ($query: UserQueryInput, $queries: [UserQueryInput], $dt: DateTime, $tz: String, $tzNoOmitEmpty: String) { + user(query: $query) { + id + } + users(query: $queries) { + id + } + maybeConvert(dt: $dt, tz: $tz) + convert2: maybeConvert(dt: $dt, tz: $tzNoOmitEmpty) +} +` + +func OmitEmptyQuery( + ctx_ context.Context, + client_ graphql.Client, + query *UserQueryInput, + queries []*UserQueryInput, + dt *time.Time, + tz *string, + tzNoOmitEmpty *string, +) (*OmitEmptyQueryResponse, error) { + req_ := &graphql.Request{ + OpName: "OmitEmptyQuery", + Query: OmitEmptyQuery_Operation, + Variables: &__OmitEmptyQueryInput{ + Query: query, + Queries: queries, + Dt: dt, + Tz: tz, + TzNoOmitEmpty: tzNoOmitEmpty, + }, + } + var err_ error + + var data_ OmitEmptyQueryResponse + resp_ := &graphql.Response{Data: &data_} + + err_ = client_.MakeRequest( + ctx_, + req_, + resp_, + ) + + return &data_, err_ +} + +// The query or mutation executed by PointersQuery. +const PointersQuery_Operation = ` +query PointersQuery ($query: UserQueryInput, $dt: DateTime, $tz: String) { + user(query: $query) { + id + roles + name + emails + emailsNoPtr: emails + } + otherUser: user(query: $query) { + id + } + maybeConvert(dt: $dt, tz: $tz) +} +` + +func PointersQuery( + ctx_ context.Context, + client_ graphql.Client, + query *UserQueryInput, + dt time.Time, + tz *string, +) (*PointersQueryResponse, error) { + req_ := &graphql.Request{ + OpName: "PointersQuery", + Query: PointersQuery_Operation, + Variables: &__PointersQueryInput{ + Query: query, + Dt: dt, + Tz: tz, + }, + } + var err_ error + + var data_ PointersQueryResponse + resp_ := &graphql.Response{Data: &data_} + + err_ = client_.MakeRequest( + ctx_, + req_, + resp_, + ) + + return &data_, err_ +} + diff --git a/generate/testdata/snapshots/TestInvalidConfigs-InvalidOptional.yaml b/generate/testdata/snapshots/TestInvalidConfigs-InvalidOptional.yaml index b6addeb0..dcba4ddf 100644 --- a/generate/testdata/snapshots/TestInvalidConfigs-InvalidOptional.yaml +++ b/generate/testdata/snapshots/TestInvalidConfigs-InvalidOptional.yaml @@ -1 +1 @@ -invalid config file testdata/invalidConfig/InvalidOptional.yaml: optional must be one of: 'value' (default), 'pointer', or 'generic' +invalid config file testdata/invalidConfig/InvalidOptional.yaml: optional must be one of: 'value' (default), 'pointer', 'pointer_omitempty' or 'generic'