From 3276c7824ad7f9de4ae0b83f00517e6eeb7ec623 Mon Sep 17 00:00:00 2001 From: Adam Scarr Date: Sun, 11 Feb 2018 20:34:14 +1100 Subject: [PATCH] Do not bind to unexported vars or methods --- example/todo/generated.go | 6 +++--- example/todo/schema.graphql | 2 +- example/todo/todo.go | 25 +++++++++++++--------- example/todo/todo_test.go | 41 ++++++++++++++++++++++--------------- extractor.go | 8 ++++++++ 5 files changed, 52 insertions(+), 30 deletions(-) diff --git a/example/todo/generated.go b/example/todo/generated.go index 5f7fffc8b4b..2727fc3903c 100644 --- a/example/todo/generated.go +++ b/example/todo/generated.go @@ -261,9 +261,9 @@ func (ec *executionContext) _todo(sel []query.Selection, it *Todo) jsonw.Writer switch field.Name { case "id": - res := it.ID + res := it.ID() - out.Values[i] = jsonw.Int(res) + out.Values[i] = jsonw.String(res) case "text": res := it.Text @@ -705,7 +705,7 @@ func (ec *executionContext) ___Type(sel []query.Selection, it *introspection.Typ return out } -var parsedSchema = schema.MustParse("schema {\n\tquery: MyQuery\n\tmutation: MyMutation\n}\n\ntype MyQuery {\n\ttodo(id: Int!): Todo\n\tlastTodo: Todo\n\ttodos: [Todo!]!\n}\n\ntype MyMutation {\n\tcreateTodo(text: String!): Todo!\n\tupdateTodo(id: Int!, changes: TodoInput!): Todo\n}\n\ntype Todo {\n\tid: Int!\n\ttext: String!\n\tdone: Boolean!\n}\n\ninput TodoInput {\n\ttext: String\n\tdone: Boolean\n}\n") +var parsedSchema = schema.MustParse("schema {\n\tquery: MyQuery\n\tmutation: MyMutation\n}\n\ntype MyQuery {\n\ttodo(id: Int!): Todo\n\tlastTodo: Todo\n\ttodos: [Todo!]!\n}\n\ntype MyMutation {\n\tcreateTodo(text: String!): Todo!\n\tupdateTodo(id: Int!, changes: TodoInput!): Todo\n}\n\ntype Todo {\n\tid: ID!\n\ttext: String!\n\tdone: Boolean!\n}\n\ninput TodoInput {\n\ttext: String\n\tdone: Boolean\n}\n") func (ec *executionContext) introspectSchema() *introspection.Schema { return introspection.WrapSchema(parsedSchema) diff --git a/example/todo/schema.graphql b/example/todo/schema.graphql index 8f71e76e9d3..477809565d0 100644 --- a/example/todo/schema.graphql +++ b/example/todo/schema.graphql @@ -15,7 +15,7 @@ type MyMutation { } type Todo { - id: Int! + id: ID! text: String! done: Boolean! } diff --git a/example/todo/todo.go b/example/todo/todo.go index 9e7c69a2408..26b3ca151e2 100644 --- a/example/todo/todo.go +++ b/example/todo/todo.go @@ -7,14 +7,19 @@ import ( "errors" "time" + "strconv" + "github.com/mitchellh/mapstructure" ) type Todo struct { - ID int - Text string - Done bool - UserID int + id int + Text string + Done bool +} + +func (t *Todo) ID() string { + return "t" + strconv.Itoa(t.id) } type todoResolver struct { @@ -25,9 +30,9 @@ type todoResolver struct { func New() *todoResolver { return &todoResolver{ todos: []Todo{ - {ID: 1, Text: "A todo not to forget", Done: false, UserID: 1}, - {ID: 2, Text: "This is the most important", Done: false, UserID: 1}, - {ID: 3, Text: "Please do this or else", Done: false, UserID: 1}, + {id: 1, Text: "A todo not to forget", Done: false}, + {id: 2, Text: "This is the most important", Done: false}, + {id: 3, Text: "Please do this or else", Done: false}, }, lastID: 3, } @@ -36,7 +41,7 @@ func New() *todoResolver { func (r *todoResolver) MyQuery_todo(ctx context.Context, id int) (*Todo, error) { time.Sleep(220 * time.Millisecond) for _, todo := range r.todos { - if todo.ID == id { + if todo.id == id { return &todo, nil } } @@ -58,7 +63,7 @@ func (r *todoResolver) MyMutation_createTodo(ctx context.Context, text string) ( newID := r.id() newTodo := Todo{ - ID: newID, + id: newID, Text: text, Done: false, } @@ -74,7 +79,7 @@ func (r *todoResolver) MyMutation_updateTodo(ctx context.Context, id int, change var affectedTodo *Todo for i := 0; i < len(r.todos); i++ { - if r.todos[i].ID == id { + if r.todos[i].id == id { affectedTodo = &r.todos[i] break } diff --git a/example/todo/todo_test.go b/example/todo/todo_test.go index 6fa91ba45f0..2bf7718a7c3 100644 --- a/example/todo/todo_test.go +++ b/example/todo/todo_test.go @@ -17,16 +17,16 @@ func TestTodo(t *testing.T) { t.Run("create a new todo", func(t *testing.T) { var resp struct { - CreateTodo Todo + CreateTodo struct{ ID string } } c.MustPost(`mutation { createTodo(text:"Fery important") { id } }`, &resp) - require.Equal(t, 4, resp.CreateTodo.ID) + require.Equal(t, "t4", resp.CreateTodo.ID) }) t.Run("update the todo text", func(t *testing.T) { var resp struct { - UpdateTodo Todo + UpdateTodo struct{ Text string } } c.MustPost(`mutation { updateTodo(id: 4, changes:{text:"Very important"}) { text } }`, &resp) @@ -35,7 +35,7 @@ func TestTodo(t *testing.T) { t.Run("update the todo status", func(t *testing.T) { var resp struct { - UpdateTodo Todo + UpdateTodo struct{ Text string } } c.MustPost(`mutation { updateTodo(id: 4, changes:{done:true}) { text } }`, &resp) @@ -44,23 +44,32 @@ func TestTodo(t *testing.T) { t.Run("select with alias", func(t *testing.T) { var resp struct { - A Todo - B Todo + A struct{ Text string } + B struct{ ID string } } c.MustPost(`{ a: todo(id:1) { text } b: todo(id:2) { id } }`, &resp) require.Equal(t, "A todo not to forget", resp.A.Text) - require.Equal(t, 0, resp.A.ID) - - require.Equal(t, "", resp.B.Text) - require.Equal(t, 2, resp.B.ID) + require.Equal(t, "t2", resp.B.ID) }) t.Run("select all", func(t *testing.T) { var resp struct { - Todo Todo - LastTodo Todo - Todos []Todo + Todo struct { + ID string + Text string + Done bool + } + LastTodo struct { + ID string + Text string + Done bool + } + Todos []struct { + ID string + Text string + Done bool + } } c.MustPost(`{ todo(id:1) { id done text } @@ -68,11 +77,11 @@ func TestTodo(t *testing.T) { todos { id text done } }`, &resp) - require.Equal(t, 1, resp.Todo.ID) - require.Equal(t, 4, resp.LastTodo.ID) + require.Equal(t, "t1", resp.Todo.ID) + require.Equal(t, "t4", resp.LastTodo.ID) require.Len(t, resp.Todos, 4) require.Equal(t, "Very important", resp.LastTodo.Text) - require.Equal(t, 4, resp.LastTodo.ID) + require.Equal(t, "t4", resp.LastTodo.ID) }) t.Run("introspection", func(t *testing.T) { diff --git a/extractor.go b/extractor.go index 8cea02e0072..8d454a023e5 100644 --- a/extractor.go +++ b/extractor.go @@ -323,6 +323,10 @@ func (e *extractor) findBindTargets(t types.Type, object *object) bool { case *types.Named: for i := 0; i < t.NumMethods(); i++ { method := t.Method(i) + if !method.Exported() { + continue + } + if methodField := object.GetField(method.Name()); methodField != nil { methodField.MethodName = "it." + method.Name() sig := method.Type().(*types.Signature) @@ -362,6 +366,10 @@ func (e *extractor) findBindTargets(t types.Type, object *object) bool { field := t.Field(i) // Todo: struct tags, name and - at least + if !field.Exported() { + continue + } + // Todo: check for type matches before binding too? if objectField := object.GetField(field.Name()); objectField != nil { objectField.VarName = "it." + field.Name()