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 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,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).
Expand Down
3 changes: 3 additions & 0 deletions docs/genqlient.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,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 @@ -198,8 +198,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 @@ -239,6 +240,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",
},
},
}},
{
"UseStructReference", "", []string{"UseStructReference.graphql"}, &Config{
StructReferences: true,
Expand Down
Loading
Loading