Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
neelance committed Mar 27, 2017
1 parent d09dd54 commit bd742d8
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 66 deletions.
10 changes: 5 additions & 5 deletions internal/exec/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ type appliedSelectionSet struct {
type appliedSelection interface{}

type appliedFieldSelection struct {
fieldExec
req *Request
alias string
args map[string]interface{}
packedArgs reflect.Value
sels []appliedSelection
exec *fieldExec
}

type appliedTypeAssertion struct {
Expand All @@ -109,8 +109,8 @@ type appliedTypeAssertion struct {
}

type typenameFieldSelection struct {
objectExec
alias string
oe *objectExec
}

type metaFieldSelection struct {
Expand All @@ -134,8 +134,8 @@ func applySelectionSet(r *Request, e *objectExec, selSet *query.SelectionSet) (s
switch field.Name.Name {
case "__typename":
sels = append(sels, &typenameFieldSelection{
alias: field.Alias.Name,
oe: e,
objectExec: *e,
alias: field.Alias.Name,
})

case "__schema":
Expand Down Expand Up @@ -183,12 +183,12 @@ func applySelectionSet(r *Request, e *objectExec, selSet *query.SelectionSet) (s
}

sels = append(sels, &appliedFieldSelection{
fieldExec: *fe,
req: r,
alias: field.Alias.Name,
args: args,
packedArgs: packedArgs,
sels: applyField(r, fe.valueExec, field.SelSet),
exec: fe,
})
}

Expand Down
120 changes: 61 additions & 59 deletions internal/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,29 @@ import (

func execSelection(ctx context.Context, sel appliedSelection, resolver reflect.Value, results map[string]interface{}) {
switch sel := sel.(type) {
case *appliedFieldSelection:
execFieldSelection(ctx, sel, resolver, results)

case *typenameFieldSelection:
if len(sel.typeAssertions) == 0 {
results[sel.alias] = sel.name
return
}
for name, a := range sel.typeAssertions {
out := resolver.Method(a.methodIndex).Call(nil)
if out[1].Bool() {
results[sel.alias] = name
return
}
}

case *metaFieldSelection:
subresults := make(map[string]interface{})
for _, subsel := range sel.sels {
execSelection(ctx, subsel, sel.resolver, subresults)
}
results[sel.alias] = subresults

case *appliedTypeAssertion:
out := resolver.Method(sel.methodIndex).Call(nil)
if !out[1].Bool() {
Expand All @@ -18,37 +41,12 @@ func execSelection(ctx context.Context, sel appliedSelection, resolver reflect.V
execSelection(ctx, sel, out[0], results)
}

case *appliedFieldSelection:
sel.execSelection(ctx, resolver, results)

case *typenameFieldSelection:
results[sel.alias] = typenameOf(sel.oe, resolver)

case *metaFieldSelection:
results[sel.alias] = schemaExec.exec(ctx, sel.sels, sel.resolver)

default:
panic("unreachable")
}
}

func typenameOf(e *objectExec, resolver reflect.Value) interface{} {
if len(e.typeAssertions) == 0 {
return e.name
}

for name, a := range e.typeAssertions {
out := resolver.Method(a.methodIndex).Call(nil)
if out[1].Bool() {
return name
}
}

return nil
}

func (afs *appliedFieldSelection) execSelection(ctx context.Context, resolver reflect.Value, results map[string]interface{}) {
fe := afs.exec
func execFieldSelection(ctx context.Context, afs *appliedFieldSelection, resolver reflect.Value, results map[string]interface{}) {
do := func(applyLimiter bool) interface{} {
if applyLimiter {
afs.req.Limiter <- struct{}{}
Expand All @@ -57,7 +55,7 @@ func (afs *appliedFieldSelection) execSelection(ctx context.Context, resolver re
var result reflect.Value
var err *errors.QueryError

traceCtx, finish := afs.req.Tracer.TraceField(ctx, fe.traceLabel, fe.typeName, fe.field.Name, fe.trivial, afs.args)
traceCtx, finish := afs.req.Tracer.TraceField(ctx, afs.traceLabel, afs.typeName, afs.field.Name, afs.trivial, afs.args)
defer func() {
finish(err)
}()
Expand All @@ -74,15 +72,15 @@ func (afs *appliedFieldSelection) execSelection(ctx context.Context, resolver re
}

var in []reflect.Value
if fe.hasContext {
if afs.hasContext {
in = append(in, reflect.ValueOf(traceCtx))
}
if fe.argsPacker != nil {
if afs.argsPacker != nil {
in = append(in, afs.packedArgs)
}
out := resolver.Method(fe.methodIndex).Call(in)
out := resolver.Method(afs.methodIndex).Call(in)
result = out[0]
if fe.hasError && !out[1].IsNil() {
if afs.hasError && !out[1].IsNil() {
resolverErr := out[1].Interface().(error)
err := errors.Errorf("%s", resolverErr)
err.ResolverError = resolverErr
Expand All @@ -100,10 +98,10 @@ func (afs *appliedFieldSelection) execSelection(ctx context.Context, resolver re
return nil // TODO handle non-nil
}

return fe.valueExec.exec(traceCtx, afs.sels, result)
return execSelectionSet(traceCtx, afs.sels, afs.valueExec, result)
}

if fe.trivial {
if afs.trivial {
results[afs.alias] = do(false)
return
}
Expand All @@ -117,34 +115,38 @@ func (afs *appliedFieldSelection) execSelection(ctx context.Context, resolver re
results[afs.alias] = result
}

func (e *objectExec) exec(ctx context.Context, sels []appliedSelection, resolver reflect.Value) interface{} {
if resolver.IsNil() {
if e.nonNull {
panic(errors.Errorf("got nil for non-null %q", e.name))
}
return nil
}
results := make(map[string]interface{})
for _, sel := range sels {
execSelection(ctx, sel, resolver, results)
}
return results
}

func (e *listExec) exec(ctx context.Context, sels []appliedSelection, resolver reflect.Value) interface{} {
if !e.nonNull {
func execSelectionSet(ctx context.Context, sels []appliedSelection, e iExec, resolver reflect.Value) interface{} {
switch e := e.(type) {
case *objectExec:
if resolver.IsNil() {
if e.nonNull {
panic(errors.Errorf("got nil for non-null %q", e.name))
}
return nil
}
resolver = resolver.Elem()
}
l := make([]interface{}, resolver.Len())
for i := range l {
l[i] = e.elem.exec(ctx, sels, resolver.Index(i))
}
return l
}
results := make(map[string]interface{})
for _, sel := range sels {
execSelection(ctx, sel, resolver, results)
}
return results

case *listExec:
if !e.nonNull {
if resolver.IsNil() {
return nil
}
resolver = resolver.Elem()
}
l := make([]interface{}, resolver.Len())
for i := range l {
l[i] = execSelectionSet(ctx, sels, e.elem, resolver.Index(i))
}
return l

case *scalarExec:
return resolver.Interface()

func (e *scalarExec) exec(ctx context.Context, sels []appliedSelection, resolver reflect.Value) interface{} {
return resolver.Interface()
default:
panic("unreachable")
}
}
7 changes: 6 additions & 1 deletion internal/exec/introspection.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ func IntrospectSchema(s *schema.Schema) interface{} {
Tracer: trace.NoopTracer{},
}
sels := applySelectionSet(r, schemaExec, introspectionQuery.Operations.Get("IntrospectionQuery").SelSet)
return schemaExec.exec(context.Background(), sels, reflect.ValueOf(introspection.WrapSchema(r.Schema)))
resolver := reflect.ValueOf(introspection.WrapSchema(r.Schema))
results := make(map[string]interface{})
for _, sel := range sels {
execSelection(context.Background(), sel, resolver, results)
}
return results
}

var introspectionQuery *query.Document
Expand Down
6 changes: 5 additions & 1 deletion internal/exec/make.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Exec struct {
}

type iExec interface {
exec(ctx context.Context, sels []appliedSelection, resolver reflect.Value) interface{}
isExec()
}

type objectExec struct {
Expand Down Expand Up @@ -52,6 +52,10 @@ type listExec struct {

type scalarExec struct{}

func (*objectExec) isExec() {}
func (*listExec) isExec() {}
func (*scalarExec) isExec() {}

func Make(s *schema.Schema, resolver interface{}) (*Exec, error) {
b := newExecBuilder(s)

Expand Down

0 comments on commit bd742d8

Please sign in to comment.