Skip to content

Commit

Permalink
Omittable input fields (#2585)
Browse files Browse the repository at this point in the history
  • Loading branch information
Desuuuu committed Apr 28, 2023
1 parent 2ad08ff commit 239b97e
Show file tree
Hide file tree
Showing 53 changed files with 2,080 additions and 124 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ directive @goModel(model: String, models: [String!]) on OBJECT
| INTERFACE
| UNION

directive @goField(forceResolver: Boolean, name: String) on INPUT_FIELD_DEFINITION
directive @goField(forceResolver: Boolean, name: String, omittable: Boolean) on INPUT_FIELD_DEFINITION
| FIELD_DEFINITION

type User @goModel(model: "github.com/you/pkg/model.User") {
Expand Down
6 changes: 4 additions & 2 deletions _examples/config/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion _examples/config/schema.graphql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
directive @goModel(model: String, models: [String!]) on OBJECT | INPUT_OBJECT | SCALAR | ENUM | INTERFACE | UNION
directive @goField(forceResolver: Boolean, name: String) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
directive @goField(forceResolver: Boolean, name: String, omittable: Boolean) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION

type Query {
todos: [Todo!]!
Expand Down
13 changes: 13 additions & 0 deletions _examples/federation/accounts/gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ resolver:
# Optional: turn on to use []Thing instead of []*Thing
# omit_slice_element_pointers: false

# Optional: turn off to make struct-type struct fields not use pointers
# e.g. type Thing struct { FieldA OtherThing } instead of { FieldA *OtherThing }
# struct_fields_always_pointers: true

# Optional: turn off to make resolvers return values instead of pointers for structs
# resolvers_always_return_pointers: true

# Optional: turn on to return pointers instead of values in unmarshalInput
# return_pointers_in_unmarshalinput: false

# Optional: wrap nullable input fields with Omittable
# nullable_input_omittable: true

# Optional: set to speed up generation time by not performing a final validation pass.
# skip_validation: true

Expand Down
13 changes: 13 additions & 0 deletions _examples/federation/products/gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ resolver:
# Optional: turn on to use []Thing instead of []*Thing
# omit_slice_element_pointers: false

# Optional: turn off to make struct-type struct fields not use pointers
# e.g. type Thing struct { FieldA OtherThing } instead of { FieldA *OtherThing }
# struct_fields_always_pointers: true

# Optional: turn off to make resolvers return values instead of pointers for structs
# resolvers_always_return_pointers: true

# Optional: turn on to return pointers instead of values in unmarshalInput
# return_pointers_in_unmarshalinput: false

# Optional: wrap nullable input fields with Omittable
# nullable_input_omittable: true

# Optional: set to speed up generation time by not performing a final validation pass.
# skip_validation: true

Expand Down
13 changes: 13 additions & 0 deletions _examples/federation/reviews/gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ resolver:
# Optional: turn on to use []Thing instead of []*Thing
# omit_slice_element_pointers: false

# Optional: turn off to make struct-type struct fields not use pointers
# e.g. type Thing struct { FieldA OtherThing } instead of { FieldA *OtherThing }
# struct_fields_always_pointers: true

# Optional: turn off to make resolvers return values instead of pointers for structs
# resolvers_always_return_pointers: true

# Optional: turn on to return pointers instead of values in unmarshalInput
# return_pointers_in_unmarshalinput: false

# Optional: wrap nullable input fields with Omittable
# nullable_input_omittable: true

# Optional: set to speed up generation time by not performing a final validation pass.
# skip_validation: true

Expand Down
6 changes: 4 additions & 2 deletions _examples/fileupload/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions _examples/scalars/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions _examples/starwars/generated/exec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions _examples/todo/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion _examples/websocket-initfunc/server/gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ resolver:
dir: graph
package: graph

# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models
# Optional: turn on use `gqlgen:"fieldName"` tags in your models
# struct_tag: json

# Optional: turn on to use []Thing instead of []*Thing
Expand All @@ -36,6 +36,12 @@ resolver:
# Optional: turn off to make resolvers return values instead of pointers for structs
# resolvers_always_return_pointers: true

# Optional: turn on to return pointers instead of values in unmarshalInput
# return_pointers_in_unmarshalinput: false

# Optional: wrap nullable input fields with Omittable
# nullable_input_omittable: true

# Optional: set to speed up generation time by not performing a final validation pass.
# skip_validation: true

Expand Down
13 changes: 13 additions & 0 deletions api/testdata/default/gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ resolver:
# Optional: turn on to use []Thing instead of []*Thing
# omit_slice_element_pointers: false

# Optional: turn off to make struct-type struct fields not use pointers
# e.g. type Thing struct { FieldA OtherThing } instead of { FieldA *OtherThing }
# struct_fields_always_pointers: true

# Optional: turn off to make resolvers return values instead of pointers for structs
# resolvers_always_return_pointers: true

# Optional: turn on to return pointers instead of values in unmarshalInput
# return_pointers_in_unmarshalinput: false

# Optional: wrap nullable input fields with Omittable
# nullable_input_omittable: true

# Optional: set to speed up generation time by not performing a final validation pass.
# skip_validation: true

Expand Down
6 changes: 4 additions & 2 deletions api/testdata/default/graph/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions api/testdata/federation2/gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ resolver:
# Optional: turn on to use []Thing instead of []*Thing
# omit_slice_element_pointers: false

# Optional: turn off to make struct-type struct fields not use pointers
# e.g. type Thing struct { FieldA OtherThing } instead of { FieldA *OtherThing }
# struct_fields_always_pointers: true

# Optional: turn off to make resolvers return values instead of pointers for structs
# resolvers_always_return_pointers: true

# Optional: turn on to return pointers instead of values in unmarshalInput
# return_pointers_in_unmarshalinput: false

# Optional: wrap nullable input fields with Omittable
# nullable_input_omittable: true

# Optional: set to speed up generation time by not performing a final validation pass.
# skip_validation: true

Expand Down
6 changes: 4 additions & 2 deletions api/testdata/federation2/graph/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions codegen/config/binder.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Binder struct {
pkgs *code.Packages
schema *ast.Schema
cfg *Config
tctx *types.Context
References []*TypeReference
SawInvalid bool
objectCache map[string]map[string]types.Object
Expand Down Expand Up @@ -81,6 +82,14 @@ func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) {
return obj.Type(), nil
}

func (b *Binder) InstantiateType(orig types.Type, targs []types.Type) (types.Type, error) {
if b.tctx == nil {
b.tctx = types.NewContext()
}

return types.Instantiate(b.tctx, orig, targs, false)
}

var (
MapType = types.NewMap(types.Typ[types.String], types.NewInterfaceType(nil, nil).Complete())
InterfaceType = types.NewInterfaceType(nil, nil)
Expand Down Expand Up @@ -191,6 +200,7 @@ type TypeReference struct {
Marshaler *types.Func // When using external marshalling functions this will point to the Marshal function
Unmarshaler *types.Func // When using external marshalling functions this will point to the Unmarshal function
IsMarshaler bool // Does the type implement graphql.Marshaler and graphql.Unmarshaler
IsOmittable bool // Is the type wrapped with Omittable
IsContext bool // Is the Marshaler/Unmarshaller the context version; applies to either the method or interface variety.
PointersInUmarshalInput bool // Inverse values and pointers in return.
}
Expand Down Expand Up @@ -318,7 +328,35 @@ func isIntf(t types.Type) bool {
return ok
}

func unwrapOmittable(t types.Type) (types.Type, bool) {
if t == nil {
return t, false
}
named, ok := t.(*types.Named)
if !ok {
return t, false
}
if named.Origin().String() != "github.com/99designs/gqlgen/graphql.Omittable[T any]" {
return t, false
}
return named.TypeArgs().At(0), true
}

func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret *TypeReference, err error) {
if innerType, ok := unwrapOmittable(bindTarget); ok {
if schemaType.NonNull {
return nil, fmt.Errorf("%s is wrapped with Omittable but non-null", schemaType.Name())
}

ref, err := b.TypeReference(schemaType, innerType)
if err != nil {
return nil, err
}

ref.IsOmittable = true
return ref, err
}

if !isValid(bindTarget) {
b.SawInvalid = true
return nil, fmt.Errorf("%s has an invalid type", schemaType.Name())
Expand Down

0 comments on commit 239b97e

Please sign in to comment.