Skip to content

Commit cd6ef8d

Browse files
authored
Merge pull request graphql-go#393 from graphql-go/367-with-bfs-thunk-return-signature
executor: thunks return signature improvement
2 parents b3d68b1 + fc3fae5 commit cd6ef8d

File tree

3 files changed

+162
-51
lines changed

3 files changed

+162
-51
lines changed

executor.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -728,18 +728,24 @@ func completeThunkValueCatchingError(eCtx *executionContext, returnType Type, fi
728728
}
729729
}()
730730

731-
propertyFn, ok := result.(func() interface{})
731+
propertyFn, ok := result.(func() (interface{}, error))
732732
if !ok {
733-
err := gqlerrors.NewFormattedError("Error resolving func. Expected `func() interface{}` signature")
733+
err := gqlerrors.NewFormattedError("Error resolving func. Expected `func() (interface{}, error)` signature")
734+
panic(gqlerrors.FormatError(err))
735+
}
736+
fnResult, err := propertyFn()
737+
if err != nil {
734738
panic(gqlerrors.FormatError(err))
735739
}
736-
result = propertyFn()
740+
741+
result = fnResult
737742

738743
if returnType, ok := returnType.(*NonNull); ok {
739744
completed := completeValue(eCtx, returnType, fieldASTs, info, path, result)
740745
return completed
741746
}
742747
completed = completeValue(eCtx, returnType, fieldASTs, info, path, result)
748+
743749
return completed
744750
}
745751

executor_test.go

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1846,7 +1846,7 @@ func TestThunkResultsProcessedCorrectly(t *testing.T) {
18461846
bar.BazA = "A"
18471847
bar.BazB = "B"
18481848

1849-
thunk := func() interface{} { return &bar }
1849+
thunk := func() (interface{}, error) { return &bar, nil }
18501850
return thunk, nil
18511851
},
18521852
},
@@ -1907,6 +1907,111 @@ func TestThunkResultsProcessedCorrectly(t *testing.T) {
19071907
}
19081908
}
19091909

1910+
func TestThunkErrorsAreHandledCorrectly(t *testing.T) {
1911+
var bazCError = errors.New("barC error")
1912+
barType := graphql.NewObject(graphql.ObjectConfig{
1913+
Name: "Bar",
1914+
Fields: graphql.Fields{
1915+
"bazA": &graphql.Field{
1916+
Type: graphql.String,
1917+
},
1918+
"bazB": &graphql.Field{
1919+
Type: graphql.String,
1920+
},
1921+
"bazC": &graphql.Field{
1922+
Type: graphql.String,
1923+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
1924+
thunk := func() (interface{}, error) {
1925+
return nil, bazCError
1926+
}
1927+
return thunk, nil
1928+
},
1929+
},
1930+
},
1931+
})
1932+
1933+
fooType := graphql.NewObject(graphql.ObjectConfig{
1934+
Name: "Foo",
1935+
Fields: graphql.Fields{
1936+
"bar": &graphql.Field{
1937+
Type: barType,
1938+
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
1939+
var bar struct {
1940+
BazA string
1941+
BazB string
1942+
}
1943+
bar.BazA = "A"
1944+
bar.BazB = "B"
1945+
1946+
thunk := func() (interface{}, error) {
1947+
return &bar, nil
1948+
}
1949+
return thunk, nil
1950+
},
1951+
},
1952+
},
1953+
})
1954+
1955+
queryType := graphql.NewObject(graphql.ObjectConfig{
1956+
Name: "Query",
1957+
Fields: graphql.Fields{
1958+
"foo": &graphql.Field{
1959+
Type: fooType,
1960+
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
1961+
var foo struct{}
1962+
return foo, nil
1963+
},
1964+
},
1965+
},
1966+
})
1967+
1968+
schema, err := graphql.NewSchema(graphql.SchemaConfig{
1969+
Query: queryType,
1970+
})
1971+
1972+
if err != nil {
1973+
t.Fatalf("unexpected error, got: %v", err)
1974+
}
1975+
1976+
query := "{ foo { bar { bazA bazB bazC } } }"
1977+
result := graphql.Do(graphql.Params{
1978+
Schema: schema,
1979+
RequestString: query,
1980+
})
1981+
1982+
foo := result.Data.(map[string]interface{})["foo"].(map[string]interface{})
1983+
bar, ok := foo["bar"].(map[string]interface{})
1984+
1985+
if !ok {
1986+
t.Errorf("expected bar to be a map[string]interface{}: actual = %v", reflect.TypeOf(foo["bar"]))
1987+
} else {
1988+
if got, want := bar["bazA"], "A"; got != want {
1989+
t.Errorf("foo.bar.bazA: got=%v, want=%v", got, want)
1990+
}
1991+
if got, want := bar["bazB"], "B"; got != want {
1992+
t.Errorf("foo.bar.bazB: got=%v, want=%v", got, want)
1993+
}
1994+
if got := bar["bazC"]; got != nil {
1995+
t.Errorf("foo.bar.bazC: got=%v, want=nil", got)
1996+
}
1997+
var errs = result.Errors
1998+
if len(errs) != 1 {
1999+
t.Fatalf("expected 1 error, got %v", result.Errors)
2000+
}
2001+
if got, want := errs[0].Message, bazCError.Error(); got != want {
2002+
t.Errorf("expected error: got=%v, want=%v", got, want)
2003+
}
2004+
}
2005+
2006+
if t.Failed() {
2007+
b, err := json.Marshal(result.Data)
2008+
if err != nil {
2009+
t.Fatalf("unexpected error: %v", err)
2010+
}
2011+
t.Log(string(b))
2012+
}
2013+
}
2014+
19102015
func assertJSON(t *testing.T, expected string, actual interface{}) {
19112016
var e interface{}
19122017
if err := json.Unmarshal([]byte(expected), &e); err != nil {

lists_test.go

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,13 @@ func TestLists_ListOfNullableArrayOfFuncContainsValues(t *testing.T) {
169169
ttype := graphql.NewList(graphql.Int)
170170

171171
// `data` is a slice of functions that return values
172-
// Note that its uses the expected signature `func() interface{} {...}`
172+
// Note that its uses the expected signature `func() (interface{}, error) {...}`
173173
data := []interface{}{
174-
func() interface{} {
175-
return 1
174+
func() (interface{}, error) {
175+
return 1, nil
176176
},
177-
func() interface{} {
178-
return 2
177+
func() (interface{}, error) {
178+
return 2, nil
179179
},
180180
}
181181
expected := &graphql.Result{
@@ -193,16 +193,16 @@ func TestLists_ListOfNullableArrayOfFuncContainsNulls(t *testing.T) {
193193
ttype := graphql.NewList(graphql.Int)
194194

195195
// `data` is a slice of functions that return values
196-
// Note that its uses the expected signature `func() interface{} {...}`
196+
// Note that its uses the expected signature `func() (interface{}, error) {...}`
197197
data := []interface{}{
198-
func() interface{} {
199-
return 1
198+
func() (interface{}, error) {
199+
return 1, nil
200200
},
201-
func() interface{} {
202-
return nil
201+
func() (interface{}, error) {
202+
return nil, nil
203203
},
204-
func() interface{} {
205-
return 2
204+
func() (interface{}, error) {
205+
return 2, nil
206206
},
207207
}
208208
expected := &graphql.Result{
@@ -354,13 +354,13 @@ func TestLists_NonNullListOfNullableArrayOfFunc_ContainsValues(t *testing.T) {
354354
ttype := graphql.NewNonNull(graphql.NewList(graphql.Int))
355355

356356
// `data` is a slice of functions that return values
357-
// Note that its uses the expected signature `func() interface{} {...}`
357+
// Note that its uses the expected signature `func() (interface{}, error) {...}`
358358
data := []interface{}{
359-
func() interface{} {
360-
return 1
359+
func() (interface{}, error) {
360+
return 1, nil
361361
},
362-
func() interface{} {
363-
return 2
362+
func() (interface{}, error) {
363+
return 2, nil
364364
},
365365
}
366366
expected := &graphql.Result{
@@ -378,16 +378,16 @@ func TestLists_NonNullListOfNullableArrayOfFunc_ContainsNulls(t *testing.T) {
378378
ttype := graphql.NewNonNull(graphql.NewList(graphql.Int))
379379

380380
// `data` is a slice of functions that return values
381-
// Note that its uses the expected signature `func() interface{} {...}`
381+
// Note that its uses the expected signature `func() (interface{}, error) {...}`
382382
data := []interface{}{
383-
func() interface{} {
384-
return 1
383+
func() (interface{}, error) {
384+
return 1, nil
385385
},
386-
func() interface{} {
387-
return nil
386+
func() (interface{}, error) {
387+
return nil, nil
388388
},
389-
func() interface{} {
390-
return 2
389+
func() (interface{}, error) {
390+
return 2, nil
391391
},
392392
}
393393
expected := &graphql.Result{
@@ -544,11 +544,11 @@ func TestLists_NullableListOfNonNullArrayOfFunc_ContainsValues(t *testing.T) {
544544
// `data` is a slice of functions that return values
545545
// Note that its uses the expected signature `func() interface{} {...}`
546546
data := []interface{}{
547-
func() interface{} {
548-
return 1
547+
func() (interface{}, error) {
548+
return 1, nil
549549
},
550-
func() interface{} {
551-
return 2
550+
func() (interface{}, error) {
551+
return 2, nil
552552
},
553553
}
554554
expected := &graphql.Result{
@@ -566,16 +566,16 @@ func TestLists_NullableListOfNonNullArrayOfFunc_ContainsNulls(t *testing.T) {
566566
ttype := graphql.NewList(graphql.NewNonNull(graphql.Int))
567567

568568
// `data` is a slice of functions that return values
569-
// Note that its uses the expected signature `func() interface{} {...}`
569+
// Note that its uses the expected signature `func() (interface{}, error){...}`
570570
data := []interface{}{
571-
func() interface{} {
572-
return 1
571+
func() (interface{}, error) {
572+
return 1, nil
573573
},
574-
func() interface{} {
575-
return nil
574+
func() (interface{}, error) {
575+
return nil, nil
576576
},
577-
func() interface{} {
578-
return 2
577+
func() (interface{}, error) {
578+
return 2, nil
579579
},
580580
}
581581
expected := &graphql.Result{
@@ -773,13 +773,13 @@ func TestLists_NonNullListOfNonNullArrayOfFunc_ContainsValues(t *testing.T) {
773773
ttype := graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(graphql.Int)))
774774

775775
// `data` is a slice of functions that return values
776-
// Note that its uses the expected signature `func() interface{} {...}`
776+
// Note that its uses the expected signature `func() (interface{}, error) {...}`
777777
data := []interface{}{
778-
func() interface{} {
779-
return 1
778+
func() (interface{}, error) {
779+
return 1, nil
780780
},
781-
func() interface{} {
782-
return 2
781+
func() (interface{}, error) {
782+
return 2, nil
783783
},
784784
}
785785
expected := &graphql.Result{
@@ -797,16 +797,16 @@ func TestLists_NonNullListOfNonNullArrayOfFunc_ContainsNulls(t *testing.T) {
797797
ttype := graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(graphql.Int)))
798798

799799
// `data` is a slice of functions that return values
800-
// Note that its uses the expected signature `func() interface{} {...}`
800+
// Note that its uses the expected signature `func() (interface{}, error) {...}`
801801
data := []interface{}{
802-
func() interface{} {
803-
return 1
802+
func() (interface{}, error) {
803+
return 1, nil
804804
},
805-
func() interface{} {
806-
return nil
805+
func() (interface{}, error) {
806+
return nil, nil
807807
},
808-
func() interface{} {
809-
return 2
808+
func() (interface{}, error) {
809+
return 2, nil
810810
},
811811
}
812812
expected := &graphql.Result{

0 commit comments

Comments
 (0)