Skip to content

Commit 0dc0116

Browse files
committed
support for inline fragments
1 parent f5e7d07 commit 0dc0116

File tree

3 files changed

+106
-12
lines changed

3 files changed

+106
-12
lines changed

graphql_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,66 @@ var tests = []struct {
411411
}
412412
`,
413413
},
414+
415+
{
416+
name: "StarWarsInlineFragments1",
417+
schema: starwars.Schema,
418+
resolver: &starwars.Resolver{},
419+
query: `
420+
query HeroForEpisode($episode: Episode!) {
421+
hero(episode: $episode) {
422+
name
423+
... on Droid {
424+
primaryFunction
425+
}
426+
... on Human {
427+
height
428+
}
429+
}
430+
}
431+
`,
432+
variables: map[string]interface{}{
433+
"episode": "JEDI",
434+
},
435+
result: `
436+
{
437+
"hero": {
438+
"name": "R2-D2",
439+
"primaryFunction": "Astromech"
440+
}
441+
}
442+
`,
443+
},
444+
445+
{
446+
name: "StarWarsInlineFragments2",
447+
schema: starwars.Schema,
448+
resolver: &starwars.Resolver{},
449+
query: `
450+
query HeroForEpisode($episode: Episode!) {
451+
hero(episode: $episode) {
452+
name
453+
... on Droid {
454+
primaryFunction
455+
}
456+
... on Human {
457+
height
458+
}
459+
}
460+
}
461+
`,
462+
variables: map[string]interface{}{
463+
"episode": "EMPIRE",
464+
},
465+
result: `
466+
{
467+
"hero": {
468+
"name": "Luke Skywalker",
469+
"height": 1.72
470+
}
471+
}
472+
`,
473+
},
414474
}
415475

416476
func TestAll(t *testing.T) {

internal/exec/exec.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,16 @@ func (e *objectExec) execSelectionSet(r *request, selSet *query.SelectionSet, re
206206
if !ok {
207207
panic(fmt.Errorf("fragment %q not found", fs.Name)) // TODO proper error handling
208208
}
209-
e.execFragment(r, frag, resolver, addResult)
209+
e.execFragment(r, &frag.Fragment, resolver, addResult)
210+
wg.Done()
211+
}(sel)
212+
}
213+
214+
case *query.InlineFragment:
215+
if !skipByDirective(r, sel.Directives) {
216+
wg.Add(1)
217+
go func(frag *query.InlineFragment) {
218+
e.execFragment(r, &frag.Fragment, resolver, addResult)
210219
wg.Done()
211220
}(sel)
212221
}

internal/query/query.go

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
type Document struct {
1313
Operations map[string]*Operation
14-
Fragments map[string]*Fragment
14+
Fragments map[string]*NamedFragment
1515
}
1616

1717
type Operation struct {
@@ -33,8 +33,12 @@ type VariableDef struct {
3333
Type string
3434
}
3535

36+
type NamedFragment struct {
37+
Fragment
38+
Name string
39+
}
40+
3641
type Fragment struct {
37-
Name string
3842
On string
3943
SelSet *SelectionSet
4044
}
@@ -65,8 +69,14 @@ type FragmentSpread struct {
6569
Directives map[string]*Directive
6670
}
6771

72+
type InlineFragment struct {
73+
Fragment
74+
Directives map[string]*Directive
75+
}
76+
6877
func (Field) isSelection() {}
6978
func (FragmentSpread) isSelection() {}
79+
func (InlineFragment) isSelection() {}
7080

7181
type Value interface {
7282
isValue()
@@ -105,7 +115,7 @@ func Parse(queryString string) (res *Document, errRes error) {
105115
func parseDocument(l *lexer.Lexer) *Document {
106116
d := &Document{
107117
Operations: make(map[string]*Operation),
108-
Fragments: make(map[string]*Fragment),
118+
Fragments: make(map[string]*NamedFragment),
109119
}
110120
for l.Peek() != scanner.EOF {
111121
if l.Peek() == '{' {
@@ -151,8 +161,8 @@ func parseOperation(l *lexer.Lexer, opType OperationType) *Operation {
151161
return op
152162
}
153163

154-
func parseFragment(l *lexer.Lexer) *Fragment {
155-
f := &Fragment{}
164+
func parseFragment(l *lexer.Lexer) *NamedFragment {
165+
f := &NamedFragment{}
156166
f.Name = l.ConsumeIdent()
157167
l.ConsumeKeyword("on")
158168
f.On = l.ConsumeIdent()
@@ -184,7 +194,7 @@ func parseSelectionSet(l *lexer.Lexer) *SelectionSet {
184194

185195
func parseSelection(l *lexer.Lexer) Selection {
186196
if l.Peek() == '.' {
187-
return parseFragmentSpread(l)
197+
return parseSpread(l)
188198
}
189199
return parseField(l)
190200
}
@@ -238,14 +248,29 @@ func parseDirective(l *lexer.Lexer) *Directive {
238248
return d
239249
}
240250

241-
func parseFragmentSpread(l *lexer.Lexer) *FragmentSpread {
242-
fs := &FragmentSpread{
243-
Directives: make(map[string]*Directive),
244-
}
251+
func parseSpread(l *lexer.Lexer) Selection {
245252
l.ConsumeToken('.')
246253
l.ConsumeToken('.')
247254
l.ConsumeToken('.')
248-
fs.Name = l.ConsumeIdent()
255+
ident := l.ConsumeIdent()
256+
257+
if ident == "on" {
258+
f := &InlineFragment{
259+
Directives: make(map[string]*Directive),
260+
}
261+
f.On = l.ConsumeIdent()
262+
for l.Peek() == '@' {
263+
d := parseDirective(l)
264+
f.Directives[d.Name] = d
265+
}
266+
f.SelSet = parseSelectionSet(l)
267+
return f
268+
}
269+
270+
fs := &FragmentSpread{
271+
Directives: make(map[string]*Directive),
272+
Name: ident,
273+
}
249274
for l.Peek() == '@' {
250275
d := parseDirective(l)
251276
fs.Directives[d.Name] = d

0 commit comments

Comments
 (0)