From cab4babec38b23dc30f0ecfc53a92a1c2dce41fd Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 12 May 2019 13:14:04 +1000 Subject: [PATCH 1/3] Test mapping object types onto go primitives --- codegen/testserver/generated.go | 218 +++++++++++++++++++ codegen/testserver/gqlgen.yml | 2 + codegen/testserver/models.go | 6 + codegen/testserver/primitive_objects.graphql | 8 + codegen/testserver/primitive_objects_test.go | 40 ++++ codegen/testserver/resolver.go | 12 + codegen/testserver/stub.go | 16 ++ 7 files changed, 302 insertions(+) create mode 100644 codegen/testserver/primitive_objects.graphql create mode 100644 codegen/testserver/primitive_objects_test.go diff --git a/codegen/testserver/generated.go b/codegen/testserver/generated.go index 85025fdf429..41051b8e35b 100644 --- a/codegen/testserver/generated.go +++ b/codegen/testserver/generated.go @@ -42,6 +42,7 @@ type ResolverRoot interface { ModelMethods() ModelMethodsResolver OverlappingFields() OverlappingFieldsResolver Panics() PanicsResolver + Primitive() PrimitiveResolver Query() QueryResolver Subscription() SubscriptionResolver User() UserResolver @@ -164,6 +165,11 @@ type ComplexityRoot struct { FieldScalarMarshal func(childComplexity int) int } + Primitive struct { + Squared func(childComplexity int) int + Value func(childComplexity int) int + } + Query struct { Autobind func(childComplexity int) int Collision func(childComplexity int) int @@ -187,6 +193,7 @@ type ComplexityRoot struct { OptionalUnion func(childComplexity int) int Overlapping func(childComplexity int) int Panics func(childComplexity int) int + PrimitiveObject func(childComplexity int) int Recursive func(childComplexity int, input *RecursiveInputSlice) int ScalarSlice func(childComplexity int) int ShapeUnion func(childComplexity int) int @@ -260,6 +267,9 @@ type PanicsResolver interface { ArgUnmarshal(ctx context.Context, obj *Panics, u []MarshalPanic) (bool, error) } +type PrimitiveResolver interface { + Value(ctx context.Context, obj *Primitive) (int, error) +} type QueryResolver interface { InvalidIdentifier(ctx context.Context) (*invalid_packagename.InvalidIdentifier, error) Collision(ctx context.Context) (*introspection1.It, error) @@ -285,6 +295,7 @@ type QueryResolver interface { Overlapping(ctx context.Context) (*OverlappingFields, error) MapStringInterface(ctx context.Context, in map[string]interface{}) (map[string]interface{}, error) Panics(ctx context.Context) (*Panics, error) + PrimitiveObject(ctx context.Context) ([]Primitive, error) DefaultScalar(ctx context.Context, arg string) (string, error) Slices(ctx context.Context) (*Slices, error) ScalarSlice(ctx context.Context) ([]byte, error) @@ -598,6 +609,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Panics.FieldScalarMarshal(childComplexity), true + case "Primitive.squared": + if e.complexity.Primitive.Squared == nil { + break + } + + return e.complexity.Primitive.Squared(childComplexity), true + + case "Primitive.value": + if e.complexity.Primitive.Value == nil { + break + } + + return e.complexity.Primitive.Value(childComplexity), true + case "Query.autobind": if e.complexity.Query.Autobind == nil { break @@ -812,6 +837,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.Panics(childComplexity), true + case "Query.primitiveObject": + if e.complexity.Query.PrimitiveObject == nil { + break + } + + return e.complexity.Query.PrimitiveObject(childComplexity), true + case "Query.recursive": if e.complexity.Query.Recursive == nil { break @@ -1221,6 +1253,15 @@ type Panics { } scalar MarshalPanic +`}, + &ast.Source{Name: "primitive_objects.graphql", Input: `extend type Query { + primitiveObject: [Primitive!]! +} + +type Primitive { + value: Int! + squared: Int! +} `}, &ast.Source{Name: "scalar_default.graphql", Input: `extend type Query { defaultScalar(arg: DefaultScalarImplementation! = "default"): DefaultScalarImplementation! @@ -3208,6 +3249,60 @@ func (ec *executionContext) _Panics_argUnmarshal(ctx context.Context, field grap return ec.marshalNBoolean2bool(ctx, field.Selections, res) } +func (ec *executionContext) _Primitive_value(ctx context.Context, field graphql.CollectedField, obj *Primitive) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Primitive", + Field: field, + Args: nil, + IsMethod: true, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Primitive().Value(rctx, obj) + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _Primitive_squared(ctx context.Context, field graphql.CollectedField, obj *Primitive) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Primitive", + Field: field, + Args: nil, + IsMethod: true, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Squared(), nil + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNInt2int(ctx, field.Selections, res) +} + func (ec *executionContext) _Query_invalidIdentifier(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { ctx = ec.Tracer.StartFieldExecution(ctx, field) defer func() { ec.Tracer.EndFieldExecution(ctx) }() @@ -3883,6 +3978,33 @@ func (ec *executionContext) _Query_panics(ctx context.Context, field graphql.Col return ec.marshalOPanics2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPanics(ctx, field.Selections, res) } +func (ec *executionContext) _Query_primitiveObject(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().PrimitiveObject(rctx) + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]Primitive) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNPrimitive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitive(ctx, field.Selections, res) +} + func (ec *executionContext) _Query_defaultScalar(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { ctx = ec.Tracer.StartFieldExecution(ctx, field) defer func() { ec.Tracer.EndFieldExecution(ctx) }() @@ -6623,6 +6745,47 @@ func (ec *executionContext) _Panics(ctx context.Context, sel ast.SelectionSet, o return out } +var primitiveImplementors = []string{"Primitive"} + +func (ec *executionContext) _Primitive(ctx context.Context, sel ast.SelectionSet, obj *Primitive) graphql.Marshaler { + fields := graphql.CollectFields(ec.RequestContext, sel, primitiveImplementors) + + out := graphql.NewFieldSet(fields) + invalid := false + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Primitive") + case "value": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Primitive_value(ctx, field, obj) + if res == graphql.Null { + invalid = true + } + return res + }) + case "squared": + out.Values[i] = ec._Primitive_squared(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalid = true + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalid { + return graphql.Null + } + return out +} + var queryImplementors = []string{"Query"} func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { @@ -6917,6 +7080,20 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr res = ec._Query_panics(ctx, field) return res }) + case "primitiveObject": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_primitiveObject(ctx, field) + if res == graphql.Null { + invalid = true + } + return res + }) case "defaultScalar": field := field out.Concurrently(i, func() (res graphql.Marshaler) { @@ -7771,6 +7948,47 @@ func (ec *executionContext) marshalNMarshalPanic2ᚕgithubᚗcomᚋ99designsᚋg return ret } +func (ec *executionContext) marshalNPrimitive2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitive(ctx context.Context, sel ast.SelectionSet, v Primitive) graphql.Marshaler { + return ec._Primitive(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPrimitive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitive(ctx context.Context, sel ast.SelectionSet, v []Primitive) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + rctx := &graphql.ResolverContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithResolverContext(ctx, rctx) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPrimitive2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitive(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + func (ec *executionContext) unmarshalNRecursiveInputSlice2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐRecursiveInputSlice(ctx context.Context, v interface{}) (RecursiveInputSlice, error) { return ec.unmarshalInputRecursiveInputSlice(ctx, v) } diff --git a/codegen/testserver/gqlgen.yml b/codegen/testserver/gqlgen.yml index 83555211939..959caaf98d9 100644 --- a/codegen/testserver/gqlgen.yml +++ b/codegen/testserver/gqlgen.yml @@ -56,6 +56,8 @@ models: model: "github.com/99designs/gqlgen/codegen/testserver.MarshalPanic" Autobind: model: "github.com/99designs/gqlgen/codegen/testserver.Autobind" + Primitive: + model: "github.com/99designs/gqlgen/codegen/testserver.Primitive" MapStringInterfaceInput: model: "map[string]interface{}" MapStringInterfaceType: diff --git a/codegen/testserver/models.go b/codegen/testserver/models.go index 3ee710a50fc..2f2ebeebaff 100644 --- a/codegen/testserver/models.go +++ b/codegen/testserver/models.go @@ -84,3 +84,9 @@ const ( FallbackToStringEncodingB FallbackToStringEncoding = "B" FallbackToStringEncodingC FallbackToStringEncoding = "C" ) + +type Primitive int + +func (p Primitive) Squared() int { + return int(p) * int(p) +} diff --git a/codegen/testserver/primitive_objects.graphql b/codegen/testserver/primitive_objects.graphql new file mode 100644 index 00000000000..e7dc49aa9b9 --- /dev/null +++ b/codegen/testserver/primitive_objects.graphql @@ -0,0 +1,8 @@ +extend type Query { + primitiveObject: [Primitive!]! +} + +type Primitive { + value: Int! + squared: Int! +} diff --git a/codegen/testserver/primitive_objects_test.go b/codegen/testserver/primitive_objects_test.go new file mode 100644 index 00000000000..f1b77643e86 --- /dev/null +++ b/codegen/testserver/primitive_objects_test.go @@ -0,0 +1,40 @@ +package testserver + +import ( + "context" + "net/http/httptest" + "testing" + + "github.com/99designs/gqlgen/client" + "github.com/99designs/gqlgen/handler" + "github.com/stretchr/testify/assert" +) + +func TestPrimitiveObjects(t *testing.T) { + resolvers := &Stub{} + resolvers.QueryResolver.PrimitiveObject = func(ctx context.Context) (out []Primitive, e error) { + return []Primitive{2, 4}, nil + } + + resolvers.PrimitiveResolver.Value = func(ctx context.Context, obj *Primitive) (i int, e error) { + return int(*obj), nil + } + + srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(Config{Resolvers: resolvers}))) + c := client.New(srv.URL) + + t.Run("can fetch value", func(t *testing.T) { + var resp struct { + PrimitiveObject []struct { + Value int + Squared int + } + } + c.MustPost(`query { primitiveObject { value, squared } }`, &resp) + + assert.Equal(t, 2, resp.PrimitiveObject[0].Value) + assert.Equal(t, 4, resp.PrimitiveObject[0].Squared) + assert.Equal(t, 4, resp.PrimitiveObject[1].Value) + assert.Equal(t, 16, resp.PrimitiveObject[1].Squared) + }) +} diff --git a/codegen/testserver/resolver.go b/codegen/testserver/resolver.go index e752629b677..f706d36b5ad 100644 --- a/codegen/testserver/resolver.go +++ b/codegen/testserver/resolver.go @@ -23,6 +23,9 @@ func (r *Resolver) OverlappingFields() OverlappingFieldsResolver { func (r *Resolver) Panics() PanicsResolver { return &panicsResolver{r} } +func (r *Resolver) Primitive() PrimitiveResolver { + return &primitiveResolver{r} +} func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } @@ -60,6 +63,12 @@ func (r *panicsResolver) ArgUnmarshal(ctx context.Context, obj *Panics, u []Mars panic("not implemented") } +type primitiveResolver struct{ *Resolver } + +func (r *primitiveResolver) Value(ctx context.Context, obj *Primitive) (int, error) { + panic("not implemented") +} + type queryResolver struct{ *Resolver } func (r *queryResolver) InvalidIdentifier(ctx context.Context) (*invalid_packagename.InvalidIdentifier, error) { @@ -134,6 +143,9 @@ func (r *queryResolver) MapStringInterface(ctx context.Context, in map[string]in func (r *queryResolver) Panics(ctx context.Context) (*Panics, error) { panic("not implemented") } +func (r *queryResolver) PrimitiveObject(ctx context.Context) ([]Primitive, error) { + panic("not implemented") +} func (r *queryResolver) DefaultScalar(ctx context.Context, arg string) (string, error) { panic("not implemented") } diff --git a/codegen/testserver/stub.go b/codegen/testserver/stub.go index eaebd12d323..24e38004d85 100644 --- a/codegen/testserver/stub.go +++ b/codegen/testserver/stub.go @@ -23,6 +23,9 @@ type Stub struct { FieldScalarMarshal func(ctx context.Context, obj *Panics) ([]MarshalPanic, error) ArgUnmarshal func(ctx context.Context, obj *Panics, u []MarshalPanic) (bool, error) } + PrimitiveResolver struct { + Value func(ctx context.Context, obj *Primitive) (int, error) + } QueryResolver struct { InvalidIdentifier func(ctx context.Context) (*invalid_packagename.InvalidIdentifier, error) Collision func(ctx context.Context) (*introspection1.It, error) @@ -48,6 +51,7 @@ type Stub struct { Overlapping func(ctx context.Context) (*OverlappingFields, error) MapStringInterface func(ctx context.Context, in map[string]interface{}) (map[string]interface{}, error) Panics func(ctx context.Context) (*Panics, error) + PrimitiveObject func(ctx context.Context) ([]Primitive, error) DefaultScalar func(ctx context.Context, arg string) (string, error) Slices func(ctx context.Context) (*Slices, error) ScalarSlice func(ctx context.Context) ([]byte, error) @@ -76,6 +80,9 @@ func (r *Stub) OverlappingFields() OverlappingFieldsResolver { func (r *Stub) Panics() PanicsResolver { return &stubPanics{r} } +func (r *Stub) Primitive() PrimitiveResolver { + return &stubPrimitive{r} +} func (r *Stub) Query() QueryResolver { return &stubQuery{r} } @@ -113,6 +120,12 @@ func (r *stubPanics) ArgUnmarshal(ctx context.Context, obj *Panics, u []MarshalP return r.PanicsResolver.ArgUnmarshal(ctx, obj, u) } +type stubPrimitive struct{ *Stub } + +func (r *stubPrimitive) Value(ctx context.Context, obj *Primitive) (int, error) { + return r.PrimitiveResolver.Value(ctx, obj) +} + type stubQuery struct{ *Stub } func (r *stubQuery) InvalidIdentifier(ctx context.Context) (*invalid_packagename.InvalidIdentifier, error) { @@ -187,6 +200,9 @@ func (r *stubQuery) MapStringInterface(ctx context.Context, in map[string]interf func (r *stubQuery) Panics(ctx context.Context) (*Panics, error) { return r.QueryResolver.Panics(ctx) } +func (r *stubQuery) PrimitiveObject(ctx context.Context) ([]Primitive, error) { + return r.QueryResolver.PrimitiveObject(ctx) +} func (r *stubQuery) DefaultScalar(ctx context.Context, arg string) (string, error) { return r.QueryResolver.DefaultScalar(ctx, arg) } From b0cd95a19710fd92ab9e76422591ac9f0c5a6f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Mur=C3=A9?= Date: Tue, 14 May 2019 02:01:43 +0200 Subject: [PATCH 2/3] Test mapping object types onto go string --- codegen/testserver/generated.go | 273 +++++++++++++++++++ codegen/testserver/gqlgen.yml | 2 + codegen/testserver/models.go | 6 + codegen/testserver/primitive_objects.graphql | 7 + codegen/testserver/primitive_objects_test.go | 36 +++ codegen/testserver/resolver.go | 15 + codegen/testserver/stub.go | 20 ++ 7 files changed, 359 insertions(+) diff --git a/codegen/testserver/generated.go b/codegen/testserver/generated.go index 41051b8e35b..39f45f0aa79 100644 --- a/codegen/testserver/generated.go +++ b/codegen/testserver/generated.go @@ -43,6 +43,7 @@ type ResolverRoot interface { OverlappingFields() OverlappingFieldsResolver Panics() PanicsResolver Primitive() PrimitiveResolver + PrimitiveString() PrimitiveStringResolver Query() QueryResolver Subscription() SubscriptionResolver User() UserResolver @@ -170,6 +171,12 @@ type ComplexityRoot struct { Value func(childComplexity int) int } + PrimitiveString struct { + Doubled func(childComplexity int) int + Len func(childComplexity int) int + Value func(childComplexity int) int + } + Query struct { Autobind func(childComplexity int) int Collision func(childComplexity int) int @@ -194,6 +201,7 @@ type ComplexityRoot struct { Overlapping func(childComplexity int) int Panics func(childComplexity int) int PrimitiveObject func(childComplexity int) int + PrimitiveStringObject func(childComplexity int) int Recursive func(childComplexity int, input *RecursiveInputSlice) int ScalarSlice func(childComplexity int) int ShapeUnion func(childComplexity int) int @@ -270,6 +278,11 @@ type PanicsResolver interface { type PrimitiveResolver interface { Value(ctx context.Context, obj *Primitive) (int, error) } +type PrimitiveStringResolver interface { + Value(ctx context.Context, obj *PrimitiveString) (string, error) + + Len(ctx context.Context, obj *PrimitiveString) (int, error) +} type QueryResolver interface { InvalidIdentifier(ctx context.Context) (*invalid_packagename.InvalidIdentifier, error) Collision(ctx context.Context) (*introspection1.It, error) @@ -296,6 +309,7 @@ type QueryResolver interface { MapStringInterface(ctx context.Context, in map[string]interface{}) (map[string]interface{}, error) Panics(ctx context.Context) (*Panics, error) PrimitiveObject(ctx context.Context) ([]Primitive, error) + PrimitiveStringObject(ctx context.Context) ([]PrimitiveString, error) DefaultScalar(ctx context.Context, arg string) (string, error) Slices(ctx context.Context) (*Slices, error) ScalarSlice(ctx context.Context) ([]byte, error) @@ -623,6 +637,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Primitive.Value(childComplexity), true + case "PrimitiveString.doubled": + if e.complexity.PrimitiveString.Doubled == nil { + break + } + + return e.complexity.PrimitiveString.Doubled(childComplexity), true + + case "PrimitiveString.len": + if e.complexity.PrimitiveString.Len == nil { + break + } + + return e.complexity.PrimitiveString.Len(childComplexity), true + + case "PrimitiveString.value": + if e.complexity.PrimitiveString.Value == nil { + break + } + + return e.complexity.PrimitiveString.Value(childComplexity), true + case "Query.autobind": if e.complexity.Query.Autobind == nil { break @@ -844,6 +879,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.PrimitiveObject(childComplexity), true + case "Query.primitiveStringObject": + if e.complexity.Query.PrimitiveStringObject == nil { + break + } + + return e.complexity.Query.PrimitiveStringObject(childComplexity), true + case "Query.recursive": if e.complexity.Query.Recursive == nil { break @@ -1256,12 +1298,19 @@ scalar MarshalPanic `}, &ast.Source{Name: "primitive_objects.graphql", Input: `extend type Query { primitiveObject: [Primitive!]! + primitiveStringObject: [PrimitiveString!]! } type Primitive { value: Int! squared: Int! } + +type PrimitiveString { + value: String! + doubled: String! + len: Int! +} `}, &ast.Source{Name: "scalar_default.graphql", Input: `extend type Query { defaultScalar(arg: DefaultScalarImplementation! = "default"): DefaultScalarImplementation! @@ -3303,6 +3352,87 @@ func (ec *executionContext) _Primitive_squared(ctx context.Context, field graphq return ec.marshalNInt2int(ctx, field.Selections, res) } +func (ec *executionContext) _PrimitiveString_value(ctx context.Context, field graphql.CollectedField, obj *PrimitiveString) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "PrimitiveString", + Field: field, + Args: nil, + IsMethod: true, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PrimitiveString().Value(rctx, obj) + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PrimitiveString_doubled(ctx context.Context, field graphql.CollectedField, obj *PrimitiveString) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "PrimitiveString", + Field: field, + Args: nil, + IsMethod: true, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Doubled(), nil + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PrimitiveString_len(ctx context.Context, field graphql.CollectedField, obj *PrimitiveString) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "PrimitiveString", + Field: field, + Args: nil, + IsMethod: true, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PrimitiveString().Len(rctx, obj) + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNInt2int(ctx, field.Selections, res) +} + func (ec *executionContext) _Query_invalidIdentifier(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { ctx = ec.Tracer.StartFieldExecution(ctx, field) defer func() { ec.Tracer.EndFieldExecution(ctx) }() @@ -4005,6 +4135,33 @@ func (ec *executionContext) _Query_primitiveObject(ctx context.Context, field gr return ec.marshalNPrimitive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitive(ctx, field.Selections, res) } +func (ec *executionContext) _Query_primitiveStringObject(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().PrimitiveStringObject(rctx) + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]PrimitiveString) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNPrimitiveString2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitiveString(ctx, field.Selections, res) +} + func (ec *executionContext) _Query_defaultScalar(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { ctx = ec.Tracer.StartFieldExecution(ctx, field) defer func() { ec.Tracer.EndFieldExecution(ctx) }() @@ -6786,6 +6943,61 @@ func (ec *executionContext) _Primitive(ctx context.Context, sel ast.SelectionSet return out } +var primitiveStringImplementors = []string{"PrimitiveString"} + +func (ec *executionContext) _PrimitiveString(ctx context.Context, sel ast.SelectionSet, obj *PrimitiveString) graphql.Marshaler { + fields := graphql.CollectFields(ec.RequestContext, sel, primitiveStringImplementors) + + out := graphql.NewFieldSet(fields) + invalid := false + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PrimitiveString") + case "value": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PrimitiveString_value(ctx, field, obj) + if res == graphql.Null { + invalid = true + } + return res + }) + case "doubled": + out.Values[i] = ec._PrimitiveString_doubled(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalid = true + } + case "len": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PrimitiveString_len(ctx, field, obj) + if res == graphql.Null { + invalid = true + } + return res + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalid { + return graphql.Null + } + return out +} + var queryImplementors = []string{"Query"} func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { @@ -7094,6 +7306,20 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } return res }) + case "primitiveStringObject": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_primitiveStringObject(ctx, field) + if res == graphql.Null { + invalid = true + } + return res + }) case "defaultScalar": field := field out.Concurrently(i, func() (res graphql.Marshaler) { @@ -7989,6 +8215,53 @@ func (ec *executionContext) marshalNPrimitive2ᚕgithubᚗcomᚋ99designsᚋgqlg return ret } +func (ec *executionContext) marshalNPrimitiveString2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitiveString(ctx context.Context, sel ast.SelectionSet, v PrimitiveString) graphql.Marshaler { + res := graphql.MarshalString(string(v)) + if res == graphql.Null { + if !ec.HasError(graphql.GetResolverContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) marshalNPrimitiveString2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitiveString(ctx context.Context, sel ast.SelectionSet, v []PrimitiveString) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + rctx := &graphql.ResolverContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithResolverContext(ctx, rctx) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPrimitiveString2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitiveString(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + func (ec *executionContext) unmarshalNRecursiveInputSlice2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐRecursiveInputSlice(ctx context.Context, v interface{}) (RecursiveInputSlice, error) { return ec.unmarshalInputRecursiveInputSlice(ctx, v) } diff --git a/codegen/testserver/gqlgen.yml b/codegen/testserver/gqlgen.yml index 959caaf98d9..0d34d21e71f 100644 --- a/codegen/testserver/gqlgen.yml +++ b/codegen/testserver/gqlgen.yml @@ -58,6 +58,8 @@ models: model: "github.com/99designs/gqlgen/codegen/testserver.Autobind" Primitive: model: "github.com/99designs/gqlgen/codegen/testserver.Primitive" + PrimitiveString: + model: "github.com/99designs/gqlgen/codegen/testserver.PrimitiveString" MapStringInterfaceInput: model: "map[string]interface{}" MapStringInterfaceType: diff --git a/codegen/testserver/models.go b/codegen/testserver/models.go index 2f2ebeebaff..dfc39bb3685 100644 --- a/codegen/testserver/models.go +++ b/codegen/testserver/models.go @@ -90,3 +90,9 @@ type Primitive int func (p Primitive) Squared() int { return int(p) * int(p) } + +type PrimitiveString string + +func (s PrimitiveString) Doubled() string { + return string(s) + string(s) +} diff --git a/codegen/testserver/primitive_objects.graphql b/codegen/testserver/primitive_objects.graphql index e7dc49aa9b9..c53702c2c89 100644 --- a/codegen/testserver/primitive_objects.graphql +++ b/codegen/testserver/primitive_objects.graphql @@ -1,8 +1,15 @@ extend type Query { primitiveObject: [Primitive!]! + primitiveStringObject: [PrimitiveString!]! } type Primitive { value: Int! squared: Int! } + +type PrimitiveString { + value: String! + doubled: String! + len: Int! +} diff --git a/codegen/testserver/primitive_objects_test.go b/codegen/testserver/primitive_objects_test.go index f1b77643e86..f3b46c2bb88 100644 --- a/codegen/testserver/primitive_objects_test.go +++ b/codegen/testserver/primitive_objects_test.go @@ -38,3 +38,39 @@ func TestPrimitiveObjects(t *testing.T) { assert.Equal(t, 16, resp.PrimitiveObject[1].Squared) }) } + +func TestPrimitiveStringObjects(t *testing.T) { + resolvers := &Stub{} + resolvers.QueryResolver.PrimitiveStringObject = func(ctx context.Context) (out []PrimitiveString, e error) { + return []PrimitiveString{"hello", "world"}, nil + } + + resolvers.PrimitiveStringResolver.Value = func(ctx context.Context, obj *PrimitiveString) (i string, e error) { + return string(*obj), nil + } + + resolvers.PrimitiveStringResolver.Len = func(ctx context.Context, obj *PrimitiveString) (i int, e error) { + return len(string(*obj)), nil + } + + srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(Config{Resolvers: resolvers}))) + c := client.New(srv.URL) + + t.Run("can fetch value", func(t *testing.T) { + var resp struct { + PrimitiveStringObject []struct { + Value string + Doubled string + Len int + } + } + c.MustPost(`query { primitiveStringObject { value, doubled, len } }`, &resp) + + assert.Equal(t, "hello", resp.PrimitiveStringObject[0].Value) + assert.Equal(t, "hellohello", resp.PrimitiveStringObject[0].Doubled) + assert.Equal(t, 5, resp.PrimitiveStringObject[0].Len) + assert.Equal(t, "world", resp.PrimitiveStringObject[1].Value) + assert.Equal(t, "worldworld", resp.PrimitiveStringObject[1].Doubled) + assert.Equal(t, 5, resp.PrimitiveStringObject[1].Len) + }) +} diff --git a/codegen/testserver/resolver.go b/codegen/testserver/resolver.go index f706d36b5ad..d8ebabcd148 100644 --- a/codegen/testserver/resolver.go +++ b/codegen/testserver/resolver.go @@ -26,6 +26,9 @@ func (r *Resolver) Panics() PanicsResolver { func (r *Resolver) Primitive() PrimitiveResolver { return &primitiveResolver{r} } +func (r *Resolver) PrimitiveString() PrimitiveStringResolver { + return &primitiveStringResolver{r} +} func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } @@ -69,6 +72,15 @@ func (r *primitiveResolver) Value(ctx context.Context, obj *Primitive) (int, err panic("not implemented") } +type primitiveStringResolver struct{ *Resolver } + +func (r *primitiveStringResolver) Value(ctx context.Context, obj *PrimitiveString) (string, error) { + panic("not implemented") +} +func (r *primitiveStringResolver) Len(ctx context.Context, obj *PrimitiveString) (int, error) { + panic("not implemented") +} + type queryResolver struct{ *Resolver } func (r *queryResolver) InvalidIdentifier(ctx context.Context) (*invalid_packagename.InvalidIdentifier, error) { @@ -146,6 +158,9 @@ func (r *queryResolver) Panics(ctx context.Context) (*Panics, error) { func (r *queryResolver) PrimitiveObject(ctx context.Context) ([]Primitive, error) { panic("not implemented") } +func (r *queryResolver) PrimitiveStringObject(ctx context.Context) ([]PrimitiveString, error) { + panic("not implemented") +} func (r *queryResolver) DefaultScalar(ctx context.Context, arg string) (string, error) { panic("not implemented") } diff --git a/codegen/testserver/stub.go b/codegen/testserver/stub.go index 24e38004d85..ba4d5fd6cb5 100644 --- a/codegen/testserver/stub.go +++ b/codegen/testserver/stub.go @@ -26,6 +26,10 @@ type Stub struct { PrimitiveResolver struct { Value func(ctx context.Context, obj *Primitive) (int, error) } + PrimitiveStringResolver struct { + Value func(ctx context.Context, obj *PrimitiveString) (string, error) + Len func(ctx context.Context, obj *PrimitiveString) (int, error) + } QueryResolver struct { InvalidIdentifier func(ctx context.Context) (*invalid_packagename.InvalidIdentifier, error) Collision func(ctx context.Context) (*introspection1.It, error) @@ -52,6 +56,7 @@ type Stub struct { MapStringInterface func(ctx context.Context, in map[string]interface{}) (map[string]interface{}, error) Panics func(ctx context.Context) (*Panics, error) PrimitiveObject func(ctx context.Context) ([]Primitive, error) + PrimitiveStringObject func(ctx context.Context) ([]PrimitiveString, error) DefaultScalar func(ctx context.Context, arg string) (string, error) Slices func(ctx context.Context) (*Slices, error) ScalarSlice func(ctx context.Context) ([]byte, error) @@ -83,6 +88,9 @@ func (r *Stub) Panics() PanicsResolver { func (r *Stub) Primitive() PrimitiveResolver { return &stubPrimitive{r} } +func (r *Stub) PrimitiveString() PrimitiveStringResolver { + return &stubPrimitiveString{r} +} func (r *Stub) Query() QueryResolver { return &stubQuery{r} } @@ -126,6 +134,15 @@ func (r *stubPrimitive) Value(ctx context.Context, obj *Primitive) (int, error) return r.PrimitiveResolver.Value(ctx, obj) } +type stubPrimitiveString struct{ *Stub } + +func (r *stubPrimitiveString) Value(ctx context.Context, obj *PrimitiveString) (string, error) { + return r.PrimitiveStringResolver.Value(ctx, obj) +} +func (r *stubPrimitiveString) Len(ctx context.Context, obj *PrimitiveString) (int, error) { + return r.PrimitiveStringResolver.Len(ctx, obj) +} + type stubQuery struct{ *Stub } func (r *stubQuery) InvalidIdentifier(ctx context.Context) (*invalid_packagename.InvalidIdentifier, error) { @@ -203,6 +220,9 @@ func (r *stubQuery) Panics(ctx context.Context) (*Panics, error) { func (r *stubQuery) PrimitiveObject(ctx context.Context) ([]Primitive, error) { return r.QueryResolver.PrimitiveObject(ctx) } +func (r *stubQuery) PrimitiveStringObject(ctx context.Context) ([]PrimitiveString, error) { + return r.QueryResolver.PrimitiveStringObject(ctx) +} func (r *stubQuery) DefaultScalar(ctx context.Context, arg string) (string, error) { return r.QueryResolver.DefaultScalar(ctx, arg) } From a5120054d3bafebd6bbb9557e6b4e773c40d6693 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 15 May 2019 11:12:52 +1000 Subject: [PATCH 3/3] fix binding to primitive non leaf types --- codegen/config/binder.go | 2 +- codegen/testserver/generated.go | 8 +------- codegen/testserver/primitive_objects_test.go | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/codegen/config/binder.go b/codegen/config/binder.go index 41c3efef269..bfd12bbce15 100644 --- a/codegen/config/binder.go +++ b/codegen/config/binder.go @@ -349,7 +349,7 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret } else if hasMethod(obj.Type(), "MarshalGQL") && hasMethod(obj.Type(), "UnmarshalGQL") { ref.GO = obj.Type() ref.IsMarshaler = true - } else if underlying := basicUnderlying(obj.Type()); underlying != nil && underlying.Kind() == types.String { + } else if underlying := basicUnderlying(obj.Type()); def.IsLeafType() && underlying != nil && underlying.Kind() == types.String { // Special case for named types wrapping strings. Used by default enum implementations. ref.GO = obj.Type() diff --git a/codegen/testserver/generated.go b/codegen/testserver/generated.go index 39f45f0aa79..a3f26e4f569 100644 --- a/codegen/testserver/generated.go +++ b/codegen/testserver/generated.go @@ -8216,13 +8216,7 @@ func (ec *executionContext) marshalNPrimitive2ᚕgithubᚗcomᚋ99designsᚋgqlg } func (ec *executionContext) marshalNPrimitiveString2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitiveString(ctx context.Context, sel ast.SelectionSet, v PrimitiveString) graphql.Marshaler { - res := graphql.MarshalString(string(v)) - if res == graphql.Null { - if !ec.HasError(graphql.GetResolverContext(ctx)) { - ec.Errorf(ctx, "must not be null") - } - } - return res + return ec._PrimitiveString(ctx, sel, &v) } func (ec *executionContext) marshalNPrimitiveString2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐPrimitiveString(ctx context.Context, sel ast.SelectionSet, v []PrimitiveString) graphql.Marshaler { diff --git a/codegen/testserver/primitive_objects_test.go b/codegen/testserver/primitive_objects_test.go index f3b46c2bb88..6ceef5c8f7d 100644 --- a/codegen/testserver/primitive_objects_test.go +++ b/codegen/testserver/primitive_objects_test.go @@ -61,7 +61,7 @@ func TestPrimitiveStringObjects(t *testing.T) { PrimitiveStringObject []struct { Value string Doubled string - Len int + Len int } } c.MustPost(`query { primitiveStringObject { value, doubled, len } }`, &resp)