Skip to content

Commit

Permalink
refactoring: calculate "implemented by" in schema package
Browse files Browse the repository at this point in the history
  • Loading branch information
neelance committed Oct 19, 2016
1 parent 1cac7e5 commit 99a3752
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 22 deletions.
29 changes: 11 additions & 18 deletions internal/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,8 @@ var scalarTypes = map[string]iExec{
var scalarTypeNames = []string{"Int", "Float", "String", "Boolean", "ID"}

func Make(s *schema.Schema, resolver interface{}) (*Exec, error) {
implementsMap := make(map[string][]string)
for _, t := range s.Types {
if obj, ok := t.(*schema.Object); ok && obj.Implements != "" {
implementsMap[obj.Implements] = append(implementsMap[obj.Implements], obj.Name)
}
}

t := s.Types[s.EntryPoints["query"]]
e, err := makeExec(s, t, reflect.TypeOf(resolver), implementsMap, make(map[typeRefMapKey]*typeRefExec))
e, err := makeExec(s, t, reflect.TypeOf(resolver), make(map[typeRefMapKey]*typeRefExec))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -65,7 +58,7 @@ func (e *Exec) Exec(document *query.Document, variables map[string]interface{},
return res, nil
}

func makeExec(s *schema.Schema, t schema.Type, resolverType reflect.Type, implementsMap map[string][]string, typeRefMap map[typeRefMapKey]*typeRefExec) (iExec, error) {
func makeExec(s *schema.Schema, t schema.Type, resolverType reflect.Type, typeRefMap map[typeRefMapKey]*typeRefExec) (iExec, error) {
switch t := t.(type) {
case *schema.Object:
fields := make(map[string]*fieldExec)
Expand All @@ -80,7 +73,7 @@ func makeExec(s *schema.Schema, t schema.Type, resolverType reflect.Type, implem
return nil, fmt.Errorf("method %q of %s must have exactly one return value", m.Name, resolverType)
}

ve, err := makeExec(s, f.Type, m.Type.Out(0), implementsMap, typeRefMap)
ve, err := makeExec(s, f.Type, m.Type.Out(0), typeRefMap)
if err != nil {
return nil, err
}
Expand All @@ -91,7 +84,7 @@ func makeExec(s *schema.Schema, t schema.Type, resolverType reflect.Type, implem
}
}

typeAssertions, err := makeTypeAssertions(s, t.Name, implementsMap[t.Name], resolverType, implementsMap, typeRefMap)
typeAssertions, err := makeTypeAssertions(s, t.Name, t.ImplementedBy, resolverType, typeRefMap)
if err != nil {
return nil, err
}
Expand All @@ -102,7 +95,7 @@ func makeExec(s *schema.Schema, t schema.Type, resolverType reflect.Type, implem
}, nil

case *schema.Union:
typeAssertions, err := makeTypeAssertions(s, t.Name, t.Types, resolverType, implementsMap, typeRefMap)
typeAssertions, err := makeTypeAssertions(s, t.Name, t.Types, resolverType, typeRefMap)
if err != nil {
return nil, err
}
Expand All @@ -118,7 +111,7 @@ func makeExec(s *schema.Schema, t schema.Type, resolverType reflect.Type, implem
if resolverType.Kind() != reflect.Slice {
return nil, fmt.Errorf("%s is not a slice", resolverType)
}
e, err := makeExec(s, t.Elem, resolverType.Elem(), implementsMap, typeRefMap)
e, err := makeExec(s, t.Elem, resolverType.Elem(), typeRefMap)
if err != nil {
return nil, err
}
Expand All @@ -130,22 +123,22 @@ func makeExec(s *schema.Schema, t schema.Type, resolverType reflect.Type, implem
if scalar, ok := scalarTypes[t.Name]; ok {
return scalar, nil
}
e, err := resolveType(s, t.Name, resolverType, implementsMap, typeRefMap)
e, err := resolveType(s, t.Name, resolverType, typeRefMap)
return e, err

default:
panic("invalid type")
}
}

func makeTypeAssertions(s *schema.Schema, typeName string, impls []string, resolverType reflect.Type, implementsMap map[string][]string, typeRefMap map[typeRefMapKey]*typeRefExec) (map[string]*typeAssertExec, error) {
func makeTypeAssertions(s *schema.Schema, typeName string, impls []string, resolverType reflect.Type, typeRefMap map[typeRefMapKey]*typeRefExec) (map[string]*typeAssertExec, error) {
typeAssertions := make(map[string]*typeAssertExec)
for _, impl := range impls {
methodIndex := findMethod(resolverType, "to"+impl)
if methodIndex == -1 {
return nil, fmt.Errorf("%s does not resolve %q: missing method %q to convert to %q", resolverType, typeName, "to"+impl, impl)
}
e, err := resolveType(s, impl, resolverType.Method(methodIndex).Type.Out(0), implementsMap, typeRefMap)
e, err := resolveType(s, impl, resolverType.Method(methodIndex).Type.Out(0), typeRefMap)
if err != nil {
return nil, err
}
Expand All @@ -157,7 +150,7 @@ func makeTypeAssertions(s *schema.Schema, typeName string, impls []string, resol
return typeAssertions, nil
}

func resolveType(s *schema.Schema, name string, resolverType reflect.Type, implementsMap map[string][]string, typeRefMap map[typeRefMapKey]*typeRefExec) (*typeRefExec, error) {
func resolveType(s *schema.Schema, name string, resolverType reflect.Type, typeRefMap map[typeRefMapKey]*typeRefExec) (*typeRefExec, error) {
refT, ok := s.Types[name]
if !ok {
return nil, fmt.Errorf("type %q not found", name)
Expand All @@ -168,7 +161,7 @@ func resolveType(s *schema.Schema, name string, resolverType reflect.Type, imple
e = &typeRefExec{}
typeRefMap[k] = e
var err error
e.iExec, err = makeExec(s, refT, resolverType, implementsMap, typeRefMap)
e.iExec, err = makeExec(s, refT, resolverType, typeRefMap)
if err != nil {
return nil, err
}
Expand Down
24 changes: 20 additions & 4 deletions internal/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@ import (
type Schema struct {
EntryPoints map[string]string
Types map[string]Type
Interfaces map[string]*Object
}

type Type interface {
isType()
}

type Object struct {
Name string
Implements string
Fields map[string]*Field
Name string
Implements string
ImplementedBy []string
Fields map[string]*Field
}

type Union struct {
Expand Down Expand Up @@ -77,13 +79,26 @@ func Parse(schemaString string, filename string) (res *Schema, errRes error) {
}
}()

return parseSchema(lexer.New(sc)), nil
s := parseSchema(lexer.New(sc))

for _, t := range s.Types {
if obj, ok := t.(*Object); ok && obj.Implements != "" {
intf, ok := s.Interfaces[obj.Implements]
if !ok {
return nil, fmt.Errorf("interface %q not found", obj.Implements)
}
intf.ImplementedBy = append(intf.ImplementedBy, obj.Name)
}
}

return s, nil
}

func parseSchema(l *lexer.Lexer) *Schema {
s := &Schema{
EntryPoints: make(map[string]string),
Types: make(map[string]Type),
Interfaces: make(map[string]*Object),
}

for l.Peek() != scanner.EOF {
Expand All @@ -103,6 +118,7 @@ func parseSchema(l *lexer.Lexer) *Schema {
case "interface":
obj := parseTypeDecl(l) // TODO
s.Types[obj.Name] = obj
s.Interfaces[obj.Name] = obj
case "union":
union := parseUnionDecl(l)
s.Types[union.Name] = union
Expand Down

0 comments on commit 99a3752

Please sign in to comment.