Skip to content

Commit

Permalink
add support for union types
Browse files Browse the repository at this point in the history
  • Loading branch information
neelance committed Oct 18, 2016
1 parent d304a41 commit 4057080
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 17 deletions.
48 changes: 46 additions & 2 deletions example/starwars/starwars.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// Source: https://github.com/graphql/graphql.github.io/blob/source/site/_core/swapiSchema.js
package starwars

import "strings"

var Schema = `
schema {
query: Query
Expand Down Expand Up @@ -281,8 +283,24 @@ func (r *Resolver) Reviews(args struct{ Episode string }) []*reviewResolver {
panic("TODO")
}

func (r *Resolver) Search(args struct{ Text string }) []characterResolver {
panic("TODO")
func (r *Resolver) Search(args struct{ Text string }) []searchResultResolver {
var l []searchResultResolver
for _, h := range humans {
if strings.Contains(h.Name, args.Text) {
l = append(l, &humanResolver{h})
}
}
for _, d := range droids {
if strings.Contains(d.Name, args.Text) {
l = append(l, &droidResolver{d})
}
}
for _, s := range starships {
if strings.Contains(s.Name, args.Text) {
l = append(l, &starshipResolver{s})
}
}
return l
}

func (r *Resolver) Character(args struct{ ID string }) characterResolver {
Expand Down Expand Up @@ -379,6 +397,10 @@ func (r *humanResolver) ToDroid() (*droidResolver, bool) {
return nil, false
}

func (r *humanResolver) ToStarship() (*starshipResolver, bool) {
return nil, false
}

type droidResolver struct {
d *droid
}
Expand Down Expand Up @@ -415,6 +437,10 @@ func (r *droidResolver) ToDroid() (*droidResolver, bool) {
return r, true
}

func (r *droidResolver) ToStarship() (*starshipResolver, bool) {
return nil, false
}

type starshipResolver struct {
s *starship
}
Expand All @@ -431,6 +457,24 @@ func (r *starshipResolver) Length(args struct{ Unit string }) float64 {
return convertLength(r.s.Length, args.Unit)
}

func (r *starshipResolver) ToHuman() (*humanResolver, bool) {
return nil, false
}

func (r *starshipResolver) ToDroid() (*droidResolver, bool) {
return nil, false
}

func (r *starshipResolver) ToStarship() (*starshipResolver, bool) {
return r, true
}

type searchResultResolver interface {
ToHuman() (*humanResolver, bool)
ToDroid() (*droidResolver, bool)
ToStarship() (*starshipResolver, bool)
}

func convertLength(meters float64, unit string) float64 {
switch unit {
case "METER":
Expand Down
36 changes: 36 additions & 0 deletions graphql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,42 @@ var tests = []struct {
}
`,
},

{
name: "StarWarsTypeName",
schema: starwars.Schema,
resolver: &starwars.Resolver{},
query: `
{
search(text: "an") {
... on Human {
name
}
... on Droid {
name
}
... on Starship {
name
}
}
}
`,
result: `
{
"search": [
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
},
{
"name": "TIE Advanced x1"
}
]
}
`,
},
}

func TestAll(t *testing.T) {
Expand Down
36 changes: 21 additions & 15 deletions internal/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,27 +54,17 @@ func makeExec(s *schema.Schema, t schema.Type, resolverType reflect.Type, implem
}
}

typeAssertions := make(map[string]*typeAssertExec)
for _, impl := range implementsMap[t.Name] {
methodIndex := findMethod(resolverType, "to"+impl)
if methodIndex == -1 {
panic(fmt.Errorf("%s does not resolve %q: missing method %q to convert to %q", resolverType, t.Name, "to"+impl, impl)) // TODO proper error handling
}
e := resolveType(s, impl, resolverType.Method(methodIndex).Type.Out(0), implementsMap, typeRefMap)
typeAssertions[impl] = &typeAssertExec{
methodIndex: methodIndex,
typeExec: e,
}
}

return &objectExec{
name: t.Name,
fields: fields,
typeAssertions: typeAssertions,
typeAssertions: makeTypeAssertions(s, t.Name, implementsMap[t.Name], resolverType, implementsMap, typeRefMap),
}

case *schema.Union:
return nil // TODO
return &objectExec{
name: t.Name,
typeAssertions: makeTypeAssertions(s, t.Name, t.Types, resolverType, implementsMap, typeRefMap),
}

case *schema.Enum:
return &scalarExec{}
Expand All @@ -95,6 +85,22 @@ func makeExec(s *schema.Schema, t schema.Type, resolverType reflect.Type, implem
}
}

func makeTypeAssertions(s *schema.Schema, typeName string, impls []string, resolverType reflect.Type, implementsMap map[string][]string, typeRefMap map[typeRefMapKey]*typeRefExec) map[string]*typeAssertExec {
typeAssertions := make(map[string]*typeAssertExec)
for _, impl := range impls {
methodIndex := findMethod(resolverType, "to"+impl)
if methodIndex == -1 {
panic(fmt.Errorf("%s does not resolve %q: missing method %q to convert to %q", resolverType, typeName, "to"+impl, impl)) // TODO proper error handling
}
e := resolveType(s, impl, resolverType.Method(methodIndex).Type.Out(0), implementsMap, typeRefMap)
typeAssertions[impl] = &typeAssertExec{
methodIndex: methodIndex,
typeExec: e,
}
}
return typeAssertions
}

func resolveType(s *schema.Schema, name string, resolverType reflect.Type, implementsMap map[string][]string, typeRefMap map[typeRefMapKey]*typeRefExec) *typeRefExec {
refT, ok := s.Types[name]
if !ok {
Expand Down

0 comments on commit 4057080

Please sign in to comment.