Skip to content

Commit

Permalink
resolve fragments early
Browse files Browse the repository at this point in the history
  • Loading branch information
neelance committed Mar 18, 2017
1 parent adeb53d commit aa868e8
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 31 deletions.
29 changes: 7 additions & 22 deletions internal/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
66 changes: 57 additions & 9 deletions internal/query/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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{
Expand All @@ -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),
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit aa868e8

Please sign in to comment.