Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotated optional fields with omitempty by using new optional config value #308

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ When releasing a new version:
### 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.

### Bug fixes:
Expand Down
3 changes: 3 additions & 0 deletions docs/genqlient.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,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
Expand Down
4 changes: 2 additions & 2 deletions generate/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,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 == "" {
Expand Down
7 changes: 7 additions & 0 deletions generate/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.)
Expand Down
23 changes: 22 additions & 1 deletion generate/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import (
"strings"
"testing"

"github.com/Khan/genqlient/internal/testutil"
"gopkg.in/yaml.v2"

"github.com/Khan/genqlient/internal/testutil"
)

const (
Expand Down Expand Up @@ -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"
Expand Down
Loading
Loading