summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/graph-gophers/graphql-go/internal/query/query.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/graph-gophers/graphql-go/internal/query/query.go')
-rw-r--r--vendor/github.com/graph-gophers/graphql-go/internal/query/query.go156
1 files changed, 156 insertions, 0 deletions
diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/query/query.go b/vendor/github.com/graph-gophers/graphql-go/internal/query/query.go
new file mode 100644
index 00000000..ca0400cd
--- /dev/null
+++ b/vendor/github.com/graph-gophers/graphql-go/internal/query/query.go
@@ -0,0 +1,156 @@
+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
+}