From bef6c0a960bb9646f617af8c337b17b6c3e63da1 Mon Sep 17 00:00:00 2001 From: Christoph Kraemer Date: Sun, 10 Mar 2019 17:15:19 -0700 Subject: [PATCH 1/2] Fix directives on args with custom type --- codegen/args.gotpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen/args.gotpl b/codegen/args.gotpl index cab7327fe85..4c7212182c8 100644 --- a/codegen/args.gotpl +++ b/codegen/args.gotpl @@ -24,7 +24,7 @@ func (ec *executionContext) {{ $name }}(ctx context.Context, rawArgs map[string] if err != nil { return nil, err } - if data, ok := tmp.({{ $arg.TypeReference.GO }}) ; ok { + if data, ok := tmp.({{ $arg.TypeReference.GO | ref }}) ; ok { arg{{$i}} = data } else { return nil, fmt.Errorf(`unexpected type %T from directive, should be {{ $arg.TypeReference.GO }}`, tmp) From d02736dcdd9860685c2ea0c34a9a7e7626316d0f Mon Sep 17 00:00:00 2001 From: Christoph Kraemer Date: Sun, 10 Mar 2019 22:08:58 -0700 Subject: [PATCH 2/2] Added test for fix directives on args with custom type --- codegen/testserver/directive_test.go | 18 ++++++ codegen/testserver/generated.go | 93 ++++++++++++++++++++++++++++ codegen/testserver/resolver.go | 3 + codegen/testserver/schema.graphql | 2 + codegen/testserver/stub.go | 4 ++ 5 files changed, 120 insertions(+) diff --git a/codegen/testserver/directive_test.go b/codegen/testserver/directive_test.go index cdb10632e2e..494be75f959 100644 --- a/codegen/testserver/directive_test.go +++ b/codegen/testserver/directive_test.go @@ -34,6 +34,11 @@ func TestDirectives(t *testing.T) { return &s, nil } + resolvers.QueryResolver.DirectiveInputType = func(ctx context.Context, arg InnerInput) (i *string, e error) { + s := "Ok" + return &s, nil + } + srv := httptest.NewServer( handler.GraphQL( NewExecutableSchema(Config{ @@ -90,6 +95,9 @@ func TestDirectives(t *testing.T) { } return nil, fmt.Errorf("unsupported type %T", res) }, + Custom: func(ctx context.Context, obj interface{}, next graphql.Resolver) (interface{}, error) { + return next(ctx) + }, }, }), handler.ResolverMiddleware(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { @@ -206,5 +214,15 @@ func TestDirectives(t *testing.T) { require.Nil(t, err) require.Equal(t, "Ok", *resp.DirectiveInputNullable) }) + t.Run("when arg has directive", func(t *testing.T) { + var resp struct { + DirectiveInputType *string + } + + err := c.Post(`query { directiveInputType(arg: {id: 1}) }`, &resp) + + require.Nil(t, err) + require.Equal(t, "Ok", *resp.DirectiveInputType) + }) }) } diff --git a/codegen/testserver/generated.go b/codegen/testserver/generated.go index eb87e3f064f..26f9b277cff 100644 --- a/codegen/testserver/generated.go +++ b/codegen/testserver/generated.go @@ -47,6 +47,8 @@ type ResolverRoot interface { } type DirectiveRoot struct { + Custom func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) + Length func(ctx context.Context, obj interface{}, next graphql.Resolver, min int, max *int) (res interface{}, err error) Range func(ctx context.Context, obj interface{}, next graphql.Resolver, min *int, max *int) (res interface{}, err error) @@ -135,6 +137,7 @@ type ComplexityRoot struct { DirectiveNullableArg func(childComplexity int, arg *int, arg2 *int) int DirectiveInputNullable func(childComplexity int, arg *InputDirectives) int DirectiveInput func(childComplexity int, arg InputDirectives) int + DirectiveInputType func(childComplexity int, arg InnerInput) int InputSlice func(childComplexity int, arg []string) int ShapeUnion func(childComplexity int) int Autobind func(childComplexity int) int @@ -214,6 +217,7 @@ type QueryResolver interface { DirectiveNullableArg(ctx context.Context, arg *int, arg2 *int) (*string, error) DirectiveInputNullable(ctx context.Context, arg *InputDirectives) (*string, error) DirectiveInput(ctx context.Context, arg InputDirectives) (*string, error) + DirectiveInputType(ctx context.Context, arg InnerInput) (*string, error) InputSlice(ctx context.Context, arg []string) (bool, error) ShapeUnion(ctx context.Context) (ShapeUnion, error) Autobind(ctx context.Context) (*Autobind, error) @@ -594,6 +598,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.DirectiveInput(childComplexity, args["arg"].(InputDirectives)), true + case "Query.DirectiveInputType": + if e.complexity.Query.DirectiveInputType == nil { + break + } + + args, err := ec.field_Query_directiveInputType_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.DirectiveInputType(childComplexity, args["arg"].(InnerInput)), true + case "Query.InputSlice": if e.complexity.Query.InputSlice == nil { break @@ -855,6 +871,13 @@ func (ec *executionContext) FieldMiddleware(ctx context.Context, obj interface{} rctx := graphql.GetResolverContext(ctx) for _, d := range rctx.Field.Definition.Directives { switch d.Name { + case "custom": + if ec.directives.Custom != nil { + n := next + next = func(ctx context.Context) (interface{}, error) { + return ec.directives.Custom(ctx, obj, n) + } + } case "length": if ec.directives.Length != nil { rawArgs := d.ArgumentMap(ec.Variables) @@ -943,6 +966,7 @@ scalar DefaultScalarImplementation directiveNullableArg(arg: Int @range(min:0), arg2: Int @range): String directiveInputNullable(arg: InputDirectives): String directiveInput(arg: InputDirectives!): String + directiveInputType(arg: InnerInput! @custom): String inputSlice(arg: [String!]!): Boolean! shapeUnion: ShapeUnion! autobind: Autobind @@ -1054,6 +1078,7 @@ type EmbeddedPointer { directive @length(min: Int!, max: Int) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION directive @range(min: Int = 0, max: Int) on ARGUMENT_DEFINITION +directive @custom on ARGUMENT_DEFINITION enum Status { OK @@ -1286,6 +1311,33 @@ func (ec *executionContext) field_Query_directiveInputNullable_args(ctx context. return args, nil } +func (ec *executionContext) field_Query_directiveInputType_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 InnerInput + if tmp, ok := rawArgs["arg"]; ok { + getArg0 := func(ctx context.Context) (interface{}, error) { + return ec.unmarshalNInnerInput2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚐInnerInput(ctx, tmp) + } + getArg1 := func(ctx context.Context) (res interface{}, err error) { + n := getArg0 + return ec.directives.Custom(ctx, tmp, n) + } + + tmp, err = getArg1(ctx) + if err != nil { + return nil, err + } + if data, ok := tmp.(InnerInput); ok { + arg0 = data + } else { + return nil, fmt.Errorf(`unexpected type %T from directive, should be github.com/99designs/gqlgen/codegen/testserver.InnerInput`, tmp) + } + } + args["arg"] = arg0 + return args, nil +} + func (ec *executionContext) field_Query_directiveInput_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -2799,6 +2851,36 @@ func (ec *executionContext) _Query_directiveInput(ctx context.Context, field gra return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } +func (ec *executionContext) _Query_directiveInputType(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, + } + ctx = graphql.WithResolverContext(ctx, rctx) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Query_directiveInputType_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + rctx.Args = args + 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().DirectiveInputType(rctx, args["arg"].(InnerInput)) + }) + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + func (ec *executionContext) _Query_inputSlice(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { ctx = ec.Tracer.StartFieldExecution(ctx, field) defer func() { ec.Tracer.EndFieldExecution(ctx) }() @@ -5282,6 +5364,17 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr res = ec._Query_directiveInput(ctx, field) return res }) + case "directiveInputType": + 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_directiveInputType(ctx, field) + return res + }) case "inputSlice": field := field out.Concurrently(i, func() (res graphql.Marshaler) { diff --git a/codegen/testserver/resolver.go b/codegen/testserver/resolver.go index 4c1e2294063..8a7ed32cee3 100644 --- a/codegen/testserver/resolver.go +++ b/codegen/testserver/resolver.go @@ -101,6 +101,9 @@ func (r *queryResolver) DirectiveInputNullable(ctx context.Context, arg *InputDi func (r *queryResolver) DirectiveInput(ctx context.Context, arg InputDirectives) (*string, error) { panic("not implemented") } +func (r *queryResolver) DirectiveInputType(ctx context.Context, arg InnerInput) (*string, error) { + panic("not implemented") +} func (r *queryResolver) InputSlice(ctx context.Context, arg []string) (bool, error) { panic("not implemented") } diff --git a/codegen/testserver/schema.graphql b/codegen/testserver/schema.graphql index 5ec9de8d065..0b135308f2a 100644 --- a/codegen/testserver/schema.graphql +++ b/codegen/testserver/schema.graphql @@ -15,6 +15,7 @@ type Query { directiveNullableArg(arg: Int @range(min:0), arg2: Int @range): String directiveInputNullable(arg: InputDirectives): String directiveInput(arg: InputDirectives!): String + directiveInputType(arg: InnerInput! @custom): String inputSlice(arg: [String!]!): Boolean! shapeUnion: ShapeUnion! autobind: Autobind @@ -126,6 +127,7 @@ type EmbeddedPointer { directive @length(min: Int!, max: Int) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION directive @range(min: Int = 0, max: Int) on ARGUMENT_DEFINITION +directive @custom on ARGUMENT_DEFINITION enum Status { OK diff --git a/codegen/testserver/stub.go b/codegen/testserver/stub.go index 4388ad0dd69..2da85a43473 100644 --- a/codegen/testserver/stub.go +++ b/codegen/testserver/stub.go @@ -37,6 +37,7 @@ type Stub struct { DirectiveNullableArg func(ctx context.Context, arg *int, arg2 *int) (*string, error) DirectiveInputNullable func(ctx context.Context, arg *InputDirectives) (*string, error) DirectiveInput func(ctx context.Context, arg InputDirectives) (*string, error) + DirectiveInputType func(ctx context.Context, arg InnerInput) (*string, error) InputSlice func(ctx context.Context, arg []string) (bool, error) ShapeUnion func(ctx context.Context) (ShapeUnion, error) Autobind func(ctx context.Context) (*Autobind, error) @@ -144,6 +145,9 @@ func (r *stubQuery) DirectiveInputNullable(ctx context.Context, arg *InputDirect func (r *stubQuery) DirectiveInput(ctx context.Context, arg InputDirectives) (*string, error) { return r.QueryResolver.DirectiveInput(ctx, arg) } +func (r *stubQuery) DirectiveInputType(ctx context.Context, arg InnerInput) (*string, error) { + return r.QueryResolver.DirectiveInputType(ctx, arg) +} func (r *stubQuery) InputSlice(ctx context.Context, arg []string) (bool, error) { return r.QueryResolver.InputSlice(ctx, arg) }