mirror of
https://github.com/42wim/matterbridge.git
synced 2024-12-20 16:02:01 -08:00
157 lines
3.7 KiB
Go
157 lines
3.7 KiB
Go
|
package query
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"text/scanner"
|
||
|
|
||
|
"github.com/graph-gophers/graphql-go/errors"
|
||
|
"github.com/graph-gophers/graphql-go/internal/common"
|
||
|
"github.com/graph-gophers/graphql-go/types"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
Query types.OperationType = "QUERY"
|
||
|
Mutation types.OperationType = "MUTATION"
|
||
|
Subscription types.OperationType = "SUBSCRIPTION"
|
||
|
)
|
||
|
|
||
|
func Parse(queryString string) (*types.ExecutableDefinition, *errors.QueryError) {
|
||
|
l := common.NewLexer(queryString, false)
|
||
|
|
||
|
var execDef *types.ExecutableDefinition
|
||
|
err := l.CatchSyntaxError(func() { execDef = parseExecutableDefinition(l) })
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return execDef, nil
|
||
|
}
|
||
|
|
||
|
func parseExecutableDefinition(l *common.Lexer) *types.ExecutableDefinition {
|
||
|
ed := &types.ExecutableDefinition{}
|
||
|
l.ConsumeWhitespace()
|
||
|
for l.Peek() != scanner.EOF {
|
||
|
if l.Peek() == '{' {
|
||
|
op := &types.OperationDefinition{Type: Query, Loc: l.Location()}
|
||
|
op.Selections = parseSelectionSet(l)
|
||
|
ed.Operations = append(ed.Operations, op)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
loc := l.Location()
|
||
|
switch x := l.ConsumeIdent(); x {
|
||
|
case "query":
|
||
|
op := parseOperation(l, Query)
|
||
|
op.Loc = loc
|
||
|
ed.Operations = append(ed.Operations, op)
|
||
|
|
||
|
case "mutation":
|
||
|
ed.Operations = append(ed.Operations, parseOperation(l, Mutation))
|
||
|
|
||
|
case "subscription":
|
||
|
ed.Operations = append(ed.Operations, parseOperation(l, Subscription))
|
||
|
|
||
|
case "fragment":
|
||
|
frag := parseFragment(l)
|
||
|
frag.Loc = loc
|
||
|
ed.Fragments = append(ed.Fragments, frag)
|
||
|
|
||
|
default:
|
||
|
l.SyntaxError(fmt.Sprintf(`unexpected %q, expecting "fragment"`, x))
|
||
|
}
|
||
|
}
|
||
|
return ed
|
||
|
}
|
||
|
|
||
|
func parseOperation(l *common.Lexer, opType types.OperationType) *types.OperationDefinition {
|
||
|
op := &types.OperationDefinition{Type: opType}
|
||
|
op.Name.Loc = l.Location()
|
||
|
if l.Peek() == scanner.Ident {
|
||
|
op.Name = l.ConsumeIdentWithLoc()
|
||
|
}
|
||
|
op.Directives = common.ParseDirectives(l)
|
||
|
if l.Peek() == '(' {
|
||
|
l.ConsumeToken('(')
|
||
|
for l.Peek() != ')' {
|
||
|
loc := l.Location()
|
||
|
l.ConsumeToken('$')
|
||
|
iv := common.ParseInputValue(l)
|
||
|
iv.Loc = loc
|
||
|
op.Vars = append(op.Vars, iv)
|
||
|
}
|
||
|
l.ConsumeToken(')')
|
||
|
}
|
||
|
op.Selections = parseSelectionSet(l)
|
||
|
return op
|
||
|
}
|
||
|
|
||
|
func parseFragment(l *common.Lexer) *types.FragmentDefinition {
|
||
|
f := &types.FragmentDefinition{}
|
||
|
f.Name = l.ConsumeIdentWithLoc()
|
||
|
l.ConsumeKeyword("on")
|
||
|
f.On = types.TypeName{Ident: l.ConsumeIdentWithLoc()}
|
||
|
f.Directives = common.ParseDirectives(l)
|
||
|
f.Selections = parseSelectionSet(l)
|
||
|
return f
|
||
|
}
|
||
|
|
||
|
func parseSelectionSet(l *common.Lexer) []types.Selection {
|
||
|
var sels []types.Selection
|
||
|
l.ConsumeToken('{')
|
||
|
for l.Peek() != '}' {
|
||
|
sels = append(sels, parseSelection(l))
|
||
|
}
|
||
|
l.ConsumeToken('}')
|
||
|
return sels
|
||
|
}
|
||
|
|
||
|
func parseSelection(l *common.Lexer) types.Selection {
|
||
|
if l.Peek() == '.' {
|
||
|
return parseSpread(l)
|
||
|
}
|
||
|
return parseFieldDef(l)
|
||
|
}
|
||
|
|
||
|
func parseFieldDef(l *common.Lexer) *types.Field {
|
||
|
f := &types.Field{}
|
||
|
f.Alias = l.ConsumeIdentWithLoc()
|
||
|
f.Name = f.Alias
|
||
|
if l.Peek() == ':' {
|
||
|
l.ConsumeToken(':')
|
||
|
f.Name = l.ConsumeIdentWithLoc()
|
||
|
}
|
||
|
if l.Peek() == '(' {
|
||
|
f.Arguments = common.ParseArgumentList(l)
|
||
|
}
|
||
|
f.Directives = common.ParseDirectives(l)
|
||
|
if l.Peek() == '{' {
|
||
|
f.SelectionSetLoc = l.Location()
|
||
|
f.SelectionSet = parseSelectionSet(l)
|
||
|
}
|
||
|
return f
|
||
|
}
|
||
|
|
||
|
func parseSpread(l *common.Lexer) types.Selection {
|
||
|
loc := l.Location()
|
||
|
l.ConsumeToken('.')
|
||
|
l.ConsumeToken('.')
|
||
|
l.ConsumeToken('.')
|
||
|
|
||
|
f := &types.InlineFragment{Loc: loc}
|
||
|
if l.Peek() == scanner.Ident {
|
||
|
ident := l.ConsumeIdentWithLoc()
|
||
|
if ident.Name != "on" {
|
||
|
fs := &types.FragmentSpread{
|
||
|
Name: ident,
|
||
|
Loc: loc,
|
||
|
}
|
||
|
fs.Directives = common.ParseDirectives(l)
|
||
|
return fs
|
||
|
}
|
||
|
f.On = types.TypeName{Ident: l.ConsumeIdentWithLoc()}
|
||
|
}
|
||
|
f.Directives = common.ParseDirectives(l)
|
||
|
f.Selections = parseSelectionSet(l)
|
||
|
return f
|
||
|
}
|