From 8fa26b4cd59e2ccd16cb851bf474d9c34fef57dd Mon Sep 17 00:00:00 2001 From: Stephano Somphanthabansouk Date: Wed, 25 Jan 2023 19:53:18 -0500 Subject: [PATCH] fix #2524 basic alias `Byte` was not binded properly --- _examples/scalars/.gqlgen.yml | 4 + _examples/scalars/external/model.go | 2 +- _examples/scalars/generated.go | 238 ++++++++++++++++++++++++++++ _examples/scalars/model/model.go | 22 +++ _examples/scalars/resolvers.go | 3 + _examples/scalars/scalar_test.go | 13 ++ _examples/scalars/schema.graphql | 5 + internal/code/compare.go | 2 +- 8 files changed, 287 insertions(+), 2 deletions(-) diff --git a/_examples/scalars/.gqlgen.yml b/_examples/scalars/.gqlgen.yml index 7980904575d..d649467226b 100644 --- a/_examples/scalars/.gqlgen.yml +++ b/_examples/scalars/.gqlgen.yml @@ -18,3 +18,7 @@ models: model: github.com/99designs/gqlgen/_examples/scalars/model.Banned DarkMode: model: github.com/99designs/gqlgen/_examples/scalars/model.Preferences + Bytes: + model: "github.com/99designs/gqlgen/codegen/testserver/singlefile.Bytes" + Runes: + model: "github.com/99designs/gqlgen/_examples/scalars/model.Runes" diff --git a/_examples/scalars/external/model.go b/_examples/scalars/external/model.go index 58046d786e2..71e2a5c8688 100644 --- a/_examples/scalars/external/model.go +++ b/_examples/scalars/external/model.go @@ -3,7 +3,7 @@ package external type ( ObjectID int Manufacturer string // remote named string - Count uint32 // remote named uint32 + Count uint8 // remote named uint8 ) const ( diff --git a/_examples/scalars/generated.go b/_examples/scalars/generated.go index ae294173ce4..a9238fd4c44 100644 --- a/_examples/scalars/generated.go +++ b/_examples/scalars/generated.go @@ -15,6 +15,7 @@ import ( "github.com/99designs/gqlgen/_examples/scalars/external" "github.com/99designs/gqlgen/_examples/scalars/model" + "github.com/99designs/gqlgen/codegen/testserver/singlefile" "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/introspection" gqlparser "github.com/vektah/gqlparser/v2" @@ -73,6 +74,9 @@ type ComplexityRoot struct { Name func(childComplexity int) int PrimitiveResolver func(childComplexity int) int PtrPrefs func(childComplexity int) int + SomeBytes func(childComplexity int) int + SomeOtherBytes func(childComplexity int) int + SomeRunes func(childComplexity int) int Tier func(childComplexity int) int ValPrefs func(childComplexity int) int Weddings func(childComplexity int) int @@ -252,6 +256,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.User.PtrPrefs(childComplexity), true + case "User.someBytes": + if e.complexity.User.SomeBytes == nil { + break + } + + return e.complexity.User.SomeBytes(childComplexity), true + + case "User.someOtherBytes": + if e.complexity.User.SomeOtherBytes == nil { + break + } + + return e.complexity.User.SomeOtherBytes(childComplexity), true + + case "User.someRunes": + if e.complexity.User.SomeRunes == nil { + break + } + + return e.complexity.User.SomeRunes(childComplexity), true + case "User.tier": if e.complexity.User.Tier == nil { break @@ -607,6 +632,12 @@ func (ec *executionContext) fieldContext_Query_user(ctx context.Context, field g return ec.fieldContext_User_cars(ctx, field) case "weddings": return ec.fieldContext_User_weddings(ctx, field) + case "someBytes": + return ec.fieldContext_User_someBytes(ctx, field) + case "someOtherBytes": + return ec.fieldContext_User_someOtherBytes(ctx, field) + case "someRunes": + return ec.fieldContext_User_someRunes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, @@ -697,6 +728,12 @@ func (ec *executionContext) fieldContext_Query_search(ctx context.Context, field return ec.fieldContext_User_cars(ctx, field) case "weddings": return ec.fieldContext_User_weddings(ctx, field) + case "someBytes": + return ec.fieldContext_User_someBytes(ctx, field) + case "someOtherBytes": + return ec.fieldContext_User_someOtherBytes(ctx, field) + case "someRunes": + return ec.fieldContext_User_someRunes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, @@ -787,6 +824,12 @@ func (ec *executionContext) fieldContext_Query_userByTier(ctx context.Context, f return ec.fieldContext_User_cars(ctx, field) case "weddings": return ec.fieldContext_User_weddings(ctx, field) + case "someBytes": + return ec.fieldContext_User_someBytes(ctx, field) + case "someOtherBytes": + return ec.fieldContext_User_someOtherBytes(ctx, field) + case "someRunes": + return ec.fieldContext_User_someRunes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, @@ -1668,6 +1711,138 @@ func (ec *executionContext) fieldContext_User_weddings(ctx context.Context, fiel return fc, nil } +func (ec *executionContext) _User_someBytes(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_User_someBytes(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SomeBytes, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]byte) + fc.Result = res + return ec.marshalNBytes2ᚕbyte(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_User_someBytes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "User", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Bytes does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _User_someOtherBytes(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_User_someOtherBytes(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SomeOtherBytes, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]byte) + fc.Result = res + return ec.marshalNBytes2ᚕbyte(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_User_someOtherBytes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "User", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Bytes does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _User_someRunes(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_User_someRunes(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SomeRunes, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]rune) + fc.Result = res + return ec.marshalNRunes2ᚕrune(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_User_someRunes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "User", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Runes does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { fc, err := ec.fieldContext___Directive_name(ctx, field) if err != nil { @@ -3757,6 +3932,27 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj out.Values[i] = ec._User_weddings(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "someBytes": + + out.Values[i] = ec._User_someBytes(ctx, field, obj) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "someOtherBytes": + + out.Values[i] = ec._User_someOtherBytes(ctx, field, obj) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "someRunes": + + out.Values[i] = ec._User_someRunes(ctx, field, obj) + if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } @@ -4129,6 +4325,27 @@ func (ec *executionContext) marshalNBoolean2githubᚗcomᚋ99designsᚋgqlgenᚋ return res } +func (ec *executionContext) unmarshalNBytes2ᚕbyte(ctx context.Context, v interface{}) ([]byte, error) { + res, err := singlefile.UnmarshalBytes(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNBytes2ᚕbyte(ctx context.Context, sel ast.SelectionSet, v []byte) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + res := singlefile.MarshalBytes(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + func (ec *executionContext) unmarshalNDarkMode2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋ_examplesᚋscalarsᚋmodelᚐPrefs(ctx context.Context, v interface{}) (*model.Prefs, error) { res, err := model.UnmarshalPreferences(v) return res, graphql.ErrorOnPath(ctx, err) @@ -4236,6 +4453,27 @@ func (ec *executionContext) marshalNPoint2ᚖgithubᚗcomᚋ99designsᚋgqlgen return v } +func (ec *executionContext) unmarshalNRunes2ᚕrune(ctx context.Context, v interface{}) ([]rune, error) { + res, err := model.UnmarshalRunes(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNRunes2ᚕrune(ctx context.Context, sel ast.SelectionSet, v []rune) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + res := model.MarshalRunes(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + func (ec *executionContext) unmarshalNString2githubᚗcomᚋ99designsᚋgqlgenᚋ_examplesᚋscalarsᚋexternalᚐManufacturer(ctx context.Context, v interface{}) (external.Manufacturer, error) { res, err := graphql.UnmarshalString(v) return external.Manufacturer(res), graphql.ErrorOnPath(ctx, err) diff --git a/_examples/scalars/model/model.go b/_examples/scalars/model/model.go index 12a871a6972..b34235f13ad 100644 --- a/_examples/scalars/model/model.go +++ b/_examples/scalars/model/model.go @@ -56,6 +56,9 @@ type User struct { Children uint Cars external.Count Weddings Sum + SomeBytes []byte + SomeOtherBytes []byte + SomeRunes []rune } // Point is serialized as a simple array, eg [1, 2] @@ -204,3 +207,22 @@ func UnmarshalPreferences(v interface{}) (*Prefs, error) { } return &Prefs{DarkMode: tmp}, nil } + +func MarshalRunes(r []rune) graphql.Marshaler { + return graphql.WriterFunc(func(w io.Writer) { + _, _ = fmt.Fprintf(w, "%q", string(r)) + }) +} + +func UnmarshalRunes(v interface{}) ([]rune, error) { + switch v := v.(type) { + case string: + return []rune(v), nil + case *string: + return []rune(*v), nil + case []rune: + return v, nil + default: + return nil, fmt.Errorf("%T is not []rune", v) + } +} diff --git a/_examples/scalars/resolvers.go b/_examples/scalars/resolvers.go index 5f533bb4af5..11ebade0e62 100644 --- a/_examples/scalars/resolvers.go +++ b/_examples/scalars/resolvers.go @@ -40,6 +40,9 @@ func (r *queryResolver) User(ctx context.Context, id external.ObjectID) (*model. Children: 3, Cars: 5, Weddings: 2, + SomeBytes: []byte("abcdef"), + SomeOtherBytes: []byte{97, 98, 99, 100, 101, 102}, + SomeRunes: []rune{'H', 'e', 'l', 'l', 'o', ' ', '世', '界'}, }, nil } diff --git a/_examples/scalars/scalar_test.go b/_examples/scalars/scalar_test.go index 9255e68a4d3..fc37e98cad9 100644 --- a/_examples/scalars/scalar_test.go +++ b/_examples/scalars/scalar_test.go @@ -25,6 +25,9 @@ type RawUser struct { Children int Cars int Weddings int + SomeBytes string + SomeOtherBytes string + SomeRunes string } func TestScalars(t *testing.T) { @@ -90,6 +93,16 @@ func TestScalars(t *testing.T) { require.Equal(t, 2, resp.User.Weddings) }) + t.Run("basic alias byte and rune", func(t *testing.T) { + var resp struct{ User RawUser } + + err := c.Post(`{ user(id:"=1=") { someBytes someOtherBytes someRunes } }`, &resp) + require.NoError(t, err) + require.Equal(t, "abcdef", resp.User.SomeBytes) + require.Equal(t, "abcdef", resp.User.SomeOtherBytes) + require.Equal(t, "Hello 世界", resp.User.SomeRunes) + }) + t.Run("custom error messages", func(t *testing.T) { var resp struct{ Search []RawUser } diff --git a/_examples/scalars/schema.graphql b/_examples/scalars/schema.graphql index a3b3a490bee..9750eb3adf4 100644 --- a/_examples/scalars/schema.graphql +++ b/_examples/scalars/schema.graphql @@ -22,6 +22,9 @@ type User { children: Int! cars: Int! weddings: Int! + someBytes: Bytes! + someOtherBytes: Bytes! + someRunes: Runes! } type Address { @@ -45,3 +48,5 @@ scalar Timestamp scalar Point scalar Banned scalar DarkMode +scalar Bytes +scalar Runes diff --git a/internal/code/compare.go b/internal/code/compare.go index d6174acbeb1..16afc256d7d 100644 --- a/internal/code/compare.go +++ b/internal/code/compare.go @@ -40,7 +40,7 @@ func CompatibleTypes(expected types.Type, actual types.Type) error { case *types.Basic: if actualBasic, ok := actual.(*types.Basic); ok { - if similarBasicKind(actualBasic.Kind()) != expected.Kind() { + if actualBasic.Kind() != expected.Kind() && similarBasicKind(actualBasic.Kind()) != expected.Kind() { return fmt.Errorf("basic kind differs, %s != %s", expected.Name(), actualBasic.Name()) }