Skip to content

Commit

Permalink
executor: updates thunk return signature
Browse files Browse the repository at this point in the history
Now thunks matches the return `Resolve(...) (interface{}, error)` signature
for consistency.
  • Loading branch information
chris-ramon committed Sep 10, 2018
1 parent 75ee0d1 commit a6c7dac
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 51 deletions.
12 changes: 9 additions & 3 deletions executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -728,18 +728,24 @@ func completeThunkValueCatchingError(eCtx *executionContext, returnType Type, fi
}
}()

propertyFn, ok := result.(func() interface{})
propertyFn, ok := result.(func() (interface{}, error))
if !ok {
err := gqlerrors.NewFormattedError("Error resolving func. Expected `func() interface{}` signature")
err := gqlerrors.NewFormattedError("Error resolving func. Expected `func() (interface{}, error)` signature")
panic(gqlerrors.FormatError(err))
}
fnResult, err := propertyFn()
if err != nil {
panic(gqlerrors.FormatError(err))
}
result = propertyFn()

result = fnResult

if returnType, ok := returnType.(*NonNull); ok {
completed := completeValue(eCtx, returnType, fieldASTs, info, path, result)
return completed
}
completed = completeValue(eCtx, returnType, fieldASTs, info, path, result)

return completed
}

Expand Down
107 changes: 106 additions & 1 deletion executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1846,7 +1846,7 @@ func TestThunkResultsProcessedCorrectly(t *testing.T) {
bar.BazA = "A"
bar.BazB = "B"

thunk := func() interface{} { return &bar }
thunk := func() (interface{}, error) { return &bar, nil }
return thunk, nil
},
},
Expand Down Expand Up @@ -1907,6 +1907,111 @@ func TestThunkResultsProcessedCorrectly(t *testing.T) {
}
}

func TestThunkErrorsAreHandledCorrectly(t *testing.T) {
var bazCError = errors.New("barC error")
barType := graphql.NewObject(graphql.ObjectConfig{
Name: "Bar",
Fields: graphql.Fields{
"bazA": &graphql.Field{
Type: graphql.String,
},
"bazB": &graphql.Field{
Type: graphql.String,
},
"bazC": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
thunk := func() (interface{}, error) {
return nil, bazCError
}
return thunk, nil
},
},
},
})

fooType := graphql.NewObject(graphql.ObjectConfig{
Name: "Foo",
Fields: graphql.Fields{
"bar": &graphql.Field{
Type: barType,
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
var bar struct {
BazA string
BazB string
}
bar.BazA = "A"
bar.BazB = "B"

thunk := func() (interface{}, error) {
return &bar, nil
}
return thunk, nil
},
},
},
})

queryType := graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"foo": &graphql.Field{
Type: fooType,
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
var foo struct{}
return foo, nil
},
},
},
})

schema, err := graphql.NewSchema(graphql.SchemaConfig{
Query: queryType,
})

if err != nil {
t.Fatalf("unexpected error, got: %v", err)
}

query := "{ foo { bar { bazA bazB bazC } } }"
result := graphql.Do(graphql.Params{
Schema: schema,
RequestString: query,
})

foo := result.Data.(map[string]interface{})["foo"].(map[string]interface{})
bar, ok := foo["bar"].(map[string]interface{})

if !ok {
t.Errorf("expected bar to be a map[string]interface{}: actual = %v", reflect.TypeOf(foo["bar"]))
} else {
if got, want := bar["bazA"], "A"; got != want {
t.Errorf("foo.bar.bazA: got=%v, want=%v", got, want)
}
if got, want := bar["bazB"], "B"; got != want {
t.Errorf("foo.bar.bazB: got=%v, want=%v", got, want)
}
if got := bar["bazC"]; got != nil {
t.Errorf("foo.bar.bazC: got=%v, want=nil", got)
}
var errs = result.Errors
if len(errs) != 1 {
t.Fatalf("expected 1 error, got %v", result.Errors)
}
if got, want := errs[0].Message, bazCError.Error(); got != want {
t.Errorf("expected error: %v, got=%v, want=%v", got, want)
}
}

if t.Failed() {
b, err := json.Marshal(result.Data)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
t.Log(string(b))
}
}

func assertJSON(t *testing.T, expected string, actual interface{}) {
var e interface{}
if err := json.Unmarshal([]byte(expected), &e); err != nil {
Expand Down
94 changes: 47 additions & 47 deletions lists_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,13 @@ func TestLists_ListOfNullableArrayOfFuncContainsValues(t *testing.T) {
ttype := graphql.NewList(graphql.Int)

// `data` is a slice of functions that return values
// Note that its uses the expected signature `func() interface{} {...}`
// Note that its uses the expected signature `func() (interface{}, error) {...}`
data := []interface{}{
func() interface{} {
return 1
func() (interface{}, error) {
return 1, nil
},
func() interface{} {
return 2
func() (interface{}, error) {
return 2, nil
},
}
expected := &graphql.Result{
Expand All @@ -193,16 +193,16 @@ func TestLists_ListOfNullableArrayOfFuncContainsNulls(t *testing.T) {
ttype := graphql.NewList(graphql.Int)

// `data` is a slice of functions that return values
// Note that its uses the expected signature `func() interface{} {...}`
// Note that its uses the expected signature `func() (interface{}, error) {...}`
data := []interface{}{
func() interface{} {
return 1
func() (interface{}, error) {
return 1, nil
},
func() interface{} {
return nil
func() (interface{}, error) {
return nil, nil
},
func() interface{} {
return 2
func() (interface{}, error) {
return 2, nil
},
}
expected := &graphql.Result{
Expand Down Expand Up @@ -354,13 +354,13 @@ func TestLists_NonNullListOfNullableArrayOfFunc_ContainsValues(t *testing.T) {
ttype := graphql.NewNonNull(graphql.NewList(graphql.Int))

// `data` is a slice of functions that return values
// Note that its uses the expected signature `func() interface{} {...}`
// Note that its uses the expected signature `func() (interface{}, error) {...}`
data := []interface{}{
func() interface{} {
return 1
func() (interface{}, error) {
return 1, nil
},
func() interface{} {
return 2
func() (interface{}, error) {
return 2, nil
},
}
expected := &graphql.Result{
Expand All @@ -378,16 +378,16 @@ func TestLists_NonNullListOfNullableArrayOfFunc_ContainsNulls(t *testing.T) {
ttype := graphql.NewNonNull(graphql.NewList(graphql.Int))

// `data` is a slice of functions that return values
// Note that its uses the expected signature `func() interface{} {...}`
// Note that its uses the expected signature `func() (interface{}, error) {...}`
data := []interface{}{
func() interface{} {
return 1
func() (interface{}, error) {
return 1, nil
},
func() interface{} {
return nil
func() (interface{}, error) {
return nil, nil
},
func() interface{} {
return 2
func() (interface{}, error) {
return 2, nil
},
}
expected := &graphql.Result{
Expand Down Expand Up @@ -544,11 +544,11 @@ func TestLists_NullableListOfNonNullArrayOfFunc_ContainsValues(t *testing.T) {
// `data` is a slice of functions that return values
// Note that its uses the expected signature `func() interface{} {...}`
data := []interface{}{
func() interface{} {
return 1
func() (interface{}, error) {
return 1, nil
},
func() interface{} {
return 2
func() (interface{}, error) {
return 2, nil
},
}
expected := &graphql.Result{
Expand All @@ -566,16 +566,16 @@ func TestLists_NullableListOfNonNullArrayOfFunc_ContainsNulls(t *testing.T) {
ttype := graphql.NewList(graphql.NewNonNull(graphql.Int))

// `data` is a slice of functions that return values
// Note that its uses the expected signature `func() interface{} {...}`
// Note that its uses the expected signature `func() (interface{}, error){...}`
data := []interface{}{
func() interface{} {
return 1
func() (interface{}, error) {
return 1, nil
},
func() interface{} {
return nil
func() (interface{}, error) {
return nil, nil
},
func() interface{} {
return 2
func() (interface{}, error) {
return 2, nil
},
}
expected := &graphql.Result{
Expand Down Expand Up @@ -773,13 +773,13 @@ func TestLists_NonNullListOfNonNullArrayOfFunc_ContainsValues(t *testing.T) {
ttype := graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(graphql.Int)))

// `data` is a slice of functions that return values
// Note that its uses the expected signature `func() interface{} {...}`
// Note that its uses the expected signature `func() (interface{}, error) {...}`
data := []interface{}{
func() interface{} {
return 1
func() (interface{}, error) {
return 1, nil
},
func() interface{} {
return 2
func() (interface{}, error) {
return 2, nil
},
}
expected := &graphql.Result{
Expand All @@ -797,16 +797,16 @@ func TestLists_NonNullListOfNonNullArrayOfFunc_ContainsNulls(t *testing.T) {
ttype := graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(graphql.Int)))

// `data` is a slice of functions that return values
// Note that its uses the expected signature `func() interface{} {...}`
// Note that its uses the expected signature `func() (interface{}, error) {...}`
data := []interface{}{
func() interface{} {
return 1
func() (interface{}, error) {
return 1, nil
},
func() interface{} {
return nil
func() (interface{}, error) {
return nil, nil
},
func() interface{} {
return 2
func() (interface{}, error) {
return 2, nil
},
}
expected := &graphql.Result{
Expand Down

0 comments on commit a6c7dac

Please sign in to comment.