diff --git a/example/todo/generated.go b/example/todo/generated.go index 52a22e61ee9..29681516cbd 100644 --- a/example/todo/generated.go +++ b/example/todo/generated.go @@ -40,6 +40,8 @@ type ResolverRoot interface { type DirectiveRoot struct { HasRole func(ctx context.Context, obj interface{}, next graphql.Resolver, role Role) (res interface{}, err error) + + User func(ctx context.Context, obj interface{}, next graphql.Resolver, id int) (res interface{}, err error) } type ComplexityRoot struct { @@ -165,7 +167,7 @@ func (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinitio ec := executionContext{graphql.GetRequestContext(ctx), e} buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { - data := ec._MyQuery(ctx, op.SelectionSet) + data := ec._MyQueryMiddleware(ctx, op) var buf bytes.Buffer data.MarshalGQL(&buf) return buf.Bytes() @@ -182,7 +184,7 @@ func (e *executableSchema) Mutation(ctx context.Context, op *ast.OperationDefini ec := executionContext{graphql.GetRequestContext(ctx), e} buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { - data := ec._MyMutation(ctx, op.SelectionSet) + data := ec._MyMutationMiddleware(ctx, op) var buf bytes.Buffer data.MarshalGQL(&buf) return buf.Bytes() @@ -204,6 +206,70 @@ type executionContext struct { *executableSchema } +func (ec *executionContext) _MyQueryMiddleware(ctx context.Context, obj *ast.OperationDefinition) graphql.Marshaler { + + next := func(ctx context.Context) (interface{}, error) { + return ec._MyQuery(ctx, obj.SelectionSet), nil + } + for _, d := range obj.Directives { + switch d.Name { + case "user": + rawArgs := d.ArgumentMap(ec.Variables) + args, err := ec.dir_user_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + n := next + next = func(ctx context.Context) (interface{}, error) { + return ec.directives.User(ctx, obj, n, args["id"].(int)) + } + } + } + tmp, err := next(ctx) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if data, ok := tmp.(graphql.Marshaler); ok { + return data + } + ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp) + return graphql.Null +} + +func (ec *executionContext) _MyMutationMiddleware(ctx context.Context, obj *ast.OperationDefinition) graphql.Marshaler { + + next := func(ctx context.Context) (interface{}, error) { + return ec._MyMutation(ctx, obj.SelectionSet), nil + } + for _, d := range obj.Directives { + switch d.Name { + case "user": + rawArgs := d.ArgumentMap(ec.Variables) + args, err := ec.dir_user_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + n := next + next = func(ctx context.Context) (interface{}, error) { + return ec.directives.User(ctx, obj, n, args["id"].(int)) + } + } + } + tmp, err := next(ctx) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if data, ok := tmp.(graphql.Marshaler); ok { + return data + } + ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp) + return graphql.Null +} + func (ec *executionContext) FieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) (ret interface{}) { defer func() { if r := recover(); r != nil { @@ -227,6 +293,19 @@ func (ec *executionContext) FieldMiddleware(ctx context.Context, obj interface{} return ec.directives.HasRole(ctx, obj, n, args["role"].(Role)) } } + case "user": + if ec.directives.User != nil { + rawArgs := d.ArgumentMap(ec.Variables) + args, err := ec.dir_user_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return nil + } + n := next + next = func(ctx context.Context) (interface{}, error) { + return ec.directives.User(ctx, obj, n, args["id"].(int)) + } + } } } res, err := ec.ResolverMiddleware(ctx, next) @@ -286,6 +365,7 @@ scalar Map "Prevents access to a field if the user doesnt have the matching role" directive @hasRole(role: Role!) on FIELD_DEFINITION +directive @user(id: ID!) on MUTATION | QUERY enum Role { ADMIN @@ -312,6 +392,20 @@ func (ec *executionContext) dir_hasRole_args(ctx context.Context, rawArgs map[st return args, nil } +func (ec *executionContext) dir_user_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 int + if tmp, ok := rawArgs["id"]; ok { + arg0, err = ec.unmarshalNID2int(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + func (ec *executionContext) field_MyMutation_createTodo_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} diff --git a/example/todo/todo.go b/example/todo/todo.go index 5c2fa129dc8..de106f0cbc7 100644 --- a/example/todo/todo.go +++ b/example/todo/todo.go @@ -15,13 +15,20 @@ import ( var you = &User{ID: 1, Name: "You"} var them = &User{ID: 2, Name: "Them"} +func getUserId(ctx context.Context) int { + if id, ok := ctx.Value("userId").(int); ok { + return id + } + return you.ID +} + func New() Config { c := Config{ Resolvers: &resolvers{ todos: []*Todo{ {ID: 1, Text: "A todo not to forget", Done: false, owner: you}, {ID: 2, Text: "This is the most important", Done: false, owner: you}, - {ID: 3, Text: "Somebody else's todo", Done: true, owner: them}, + {ID: 3, Text: "Somebody else's todo", Done: false, owner: them}, {ID: 4, Text: "Please do this or else", Done: false, owner: you}, }, lastID: 4, @@ -38,13 +45,16 @@ func New() Config { return nil, fmt.Errorf("obj cant be owned") } - if ownable.Owner().ID != you.ID { + if ownable.Owner().ID != getUserId(ctx) { return nil, fmt.Errorf("you dont own that") } } return next(ctx) } + c.Directives.User = func(ctx context.Context, obj interface{}, next graphql.Resolver, id int) (interface{}, error) { + return next(context.WithValue(ctx, "userId", id)) + } return c } diff --git a/example/todo/todo_test.go b/example/todo/todo_test.go index 2b3296d72a8..7a06c7977be 100644 --- a/example/todo/todo_test.go +++ b/example/todo/todo_test.go @@ -55,6 +55,18 @@ func TestTodo(t *testing.T) { require.Equal(t, "Very important", resp.UpdateTodo.Text) }) + t.Run("update the todo status by user id", func(t *testing.T) { + var resp struct { + UpdateTodo struct { + Text string + Done bool + } + } + c.MustPost(`mutation @user(id:2){ updateTodo(id: 3, changes:{done:true}) { text, done } }`, &resp) + + require.Equal(t, "Somebody else's todo", resp.UpdateTodo.Text) + }) + t.Run("select with alias", func(t *testing.T) { var resp struct { A struct{ Text string }