From aa868e8d461160e65058b1976484dcb74e264b0b Mon Sep 17 00:00:00 2001 From: Richard Musiol Date: Sat, 18 Mar 2017 13:54:06 +0100 Subject: [PATCH] resolve fragments early --- internal/exec/exec.go | 29 +++++------------- internal/query/query.go | 66 +++++++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 31 deletions(-) diff --git a/internal/exec/exec.go b/internal/exec/exec.go index 7fc23087920..23681144edb 100644 --- a/internal/exec/exec.go +++ b/internal/exec/exec.go @@ -494,36 +494,21 @@ func (e *objectExec) execSelectionSet(ctx context.Context, r *request, selSet *q switch sel := sel.(type) { case *query.Field: - if skipByDirective(r, sel.Directives) { + field := sel + if skipByDirective(r, field.Directives) { continue } - execSel(func() { - e.execField(ctx, r, sel, resolver, addResult) + e.execField(ctx, r, field, resolver, addResult) }) - case *query.FragmentSpread: - if skipByDirective(r, sel.Directives) { - continue - } - - fs := sel - execSel(func() { - frag, ok := r.doc.Fragments[fs.Name] - if !ok { - panic(fmt.Errorf("fragment %q not found", fs.Name)) // TODO proper error handling - } - e.execFragment(ctx, r, &frag.Fragment, resolver, addResult) - }) - - case *query.InlineFragment: - if skipByDirective(r, sel.Directives) { + case *query.Fragment: + frag := sel + if skipByDirective(r, frag.Directives) { continue } - - frag := sel execSel(func() { - e.execFragment(ctx, r, &frag.Fragment, resolver, addResult) + e.execFragment(ctx, r, frag, resolver, addResult) }) default: diff --git a/internal/query/query.go b/internal/query/query.go index cb9a6f91c8b..1583122c0c9 100644 --- a/internal/query/query.go +++ b/internal/query/query.go @@ -35,8 +35,9 @@ type NamedFragment struct { } type Fragment struct { - On string - SelSet *SelectionSet + On string + SelSet *SelectionSet + Directives map[string]common.DirectiveArgs } type SelectionSet struct { @@ -60,14 +61,9 @@ type FragmentSpread struct { Directives map[string]common.DirectiveArgs } -type InlineFragment struct { - Fragment - Directives map[string]common.DirectiveArgs -} - func (Field) isSelection() {} +func (Fragment) isSelection() {} func (FragmentSpread) isSelection() {} -func (InlineFragment) isSelection() {} func Parse(queryString string) (*Document, *errors.QueryError) { sc := &scanner.Scanner{ @@ -84,9 +80,61 @@ func Parse(queryString string) (*Document, *errors.QueryError) { return nil, err } + for _, op := range doc.Operations { + if err := resolveSelSet(doc, op.SelSet); err != nil { + return nil, err + } + } + + for _, f := range doc.Fragments { + if err := resolveSelSet(doc, f.Fragment.SelSet); err != nil { + return nil, err + } + } + return doc, nil } +func resolveSelSet(doc *Document, selSet *SelectionSet) *errors.QueryError { + var err *errors.QueryError + for i, sel := range selSet.Selections { + selSet.Selections[i], err = resolveSelection(doc, sel) + if err != nil { + return err + } + } + return nil +} + +func resolveSelection(doc *Document, sel Selection) (Selection, *errors.QueryError) { + switch sel := sel.(type) { + case *Field: + if sel.SelSet != nil { + if err := resolveSelSet(doc, sel.SelSet); err != nil { + return nil, err + } + } + return sel, nil + + case *FragmentSpread: + frag, ok := doc.Fragments[sel.Name] + if !ok { + return nil, errors.Errorf("fragment %q not found", sel.Name) + } + return &Fragment{ + On: frag.On, + SelSet: frag.SelSet, + Directives: sel.Directives, + }, nil + + case *Fragment: + return sel, nil + + default: + panic("unreachable") + } +} + func parseDocument(l *lexer.Lexer) *Document { d := &Document{ Operations: make(map[string]*Operation), @@ -189,7 +237,7 @@ func parseSpread(l *lexer.Lexer) Selection { ident := l.ConsumeIdent() if ident == "on" { - f := &InlineFragment{} + f := &Fragment{} f.On = l.ConsumeIdent() f.Directives = common.ParseDirectives(l) f.SelSet = parseSelectionSet(l)