query.go

  1package parser
  2
  3import (
  4	"github.com/vektah/gqlparser/gqlerror"
  5	"github.com/vektah/gqlparser/lexer"
  6
  7	. "github.com/vektah/gqlparser/ast"
  8)
  9
 10func ParseQuery(source *Source) (*QueryDocument, *gqlerror.Error) {
 11	p := parser{
 12		lexer: lexer.New(source),
 13	}
 14	return p.parseQueryDocument(), p.err
 15}
 16
 17func (p *parser) parseQueryDocument() *QueryDocument {
 18	var doc QueryDocument
 19	for p.peek().Kind != lexer.EOF {
 20		if p.err != nil {
 21			return &doc
 22		}
 23		doc.Position = p.peekPos()
 24		switch p.peek().Kind {
 25		case lexer.Name:
 26			switch p.peek().Value {
 27			case "query", "mutation", "subscription":
 28				doc.Operations = append(doc.Operations, p.parseOperationDefinition())
 29			case "fragment":
 30				doc.Fragments = append(doc.Fragments, p.parseFragmentDefinition())
 31			default:
 32				p.unexpectedError()
 33			}
 34		case lexer.BraceL:
 35			doc.Operations = append(doc.Operations, p.parseOperationDefinition())
 36		default:
 37			p.unexpectedError()
 38		}
 39	}
 40
 41	return &doc
 42}
 43
 44func (p *parser) parseOperationDefinition() *OperationDefinition {
 45	if p.peek().Kind == lexer.BraceL {
 46		return &OperationDefinition{
 47			Position:     p.peekPos(),
 48			Operation:    Query,
 49			SelectionSet: p.parseRequiredSelectionSet(),
 50		}
 51	}
 52
 53	var od OperationDefinition
 54	od.Position = p.peekPos()
 55	od.Operation = p.parseOperationType()
 56
 57	if p.peek().Kind == lexer.Name {
 58		od.Name = p.next().Value
 59	}
 60
 61	od.VariableDefinitions = p.parseVariableDefinitions()
 62	od.Directives = p.parseDirectives(false)
 63	od.SelectionSet = p.parseRequiredSelectionSet()
 64
 65	return &od
 66}
 67
 68func (p *parser) parseOperationType() Operation {
 69	tok := p.next()
 70	switch tok.Value {
 71	case "query":
 72		return Query
 73	case "mutation":
 74		return Mutation
 75	case "subscription":
 76		return Subscription
 77	}
 78	p.unexpectedToken(tok)
 79	return ""
 80}
 81
 82func (p *parser) parseVariableDefinitions() VariableDefinitionList {
 83	var defs []*VariableDefinition
 84	p.many(lexer.ParenL, lexer.ParenR, func() {
 85		defs = append(defs, p.parseVariableDefinition())
 86	})
 87
 88	return defs
 89}
 90
 91func (p *parser) parseVariableDefinition() *VariableDefinition {
 92	var def VariableDefinition
 93	def.Position = p.peekPos()
 94	def.Variable = p.parseVariable()
 95
 96	p.expect(lexer.Colon)
 97
 98	def.Type = p.parseTypeReference()
 99
100	if p.skip(lexer.Equals) {
101		def.DefaultValue = p.parseValueLiteral(true)
102	}
103
104	return &def
105}
106
107func (p *parser) parseVariable() string {
108	p.expect(lexer.Dollar)
109	return p.parseName()
110}
111
112func (p *parser) parseOptionalSelectionSet() SelectionSet {
113	var selections []Selection
114	p.some(lexer.BraceL, lexer.BraceR, func() {
115		selections = append(selections, p.parseSelection())
116	})
117
118	return SelectionSet(selections)
119}
120
121func (p *parser) parseRequiredSelectionSet() SelectionSet {
122	if p.peek().Kind != lexer.BraceL {
123		p.error(p.peek(), "Expected %s, found %s", lexer.BraceL, p.peek().Kind.String())
124		return nil
125	}
126
127	var selections []Selection
128	p.some(lexer.BraceL, lexer.BraceR, func() {
129		selections = append(selections, p.parseSelection())
130	})
131
132	return SelectionSet(selections)
133}
134
135func (p *parser) parseSelection() Selection {
136	if p.peek().Kind == lexer.Spread {
137		return p.parseFragment()
138	}
139	return p.parseField()
140}
141
142func (p *parser) parseField() *Field {
143	var field Field
144	field.Position = p.peekPos()
145	field.Alias = p.parseName()
146
147	if p.skip(lexer.Colon) {
148		field.Name = p.parseName()
149	} else {
150		field.Name = field.Alias
151	}
152
153	field.Arguments = p.parseArguments(false)
154	field.Directives = p.parseDirectives(false)
155	if p.peek().Kind == lexer.BraceL {
156		field.SelectionSet = p.parseOptionalSelectionSet()
157	}
158
159	return &field
160}
161
162func (p *parser) parseArguments(isConst bool) ArgumentList {
163	var arguments ArgumentList
164	p.many(lexer.ParenL, lexer.ParenR, func() {
165		arguments = append(arguments, p.parseArgument(isConst))
166	})
167
168	return arguments
169}
170
171func (p *parser) parseArgument(isConst bool) *Argument {
172	arg := Argument{}
173	arg.Position = p.peekPos()
174	arg.Name = p.parseName()
175	p.expect(lexer.Colon)
176
177	arg.Value = p.parseValueLiteral(isConst)
178	return &arg
179}
180
181func (p *parser) parseFragment() Selection {
182	p.expect(lexer.Spread)
183
184	if peek := p.peek(); peek.Kind == lexer.Name && peek.Value != "on" {
185		return &FragmentSpread{
186			Position:   p.peekPos(),
187			Name:       p.parseFragmentName(),
188			Directives: p.parseDirectives(false),
189		}
190	}
191
192	var def InlineFragment
193	def.Position = p.peekPos()
194	if p.peek().Value == "on" {
195		p.next() // "on"
196
197		def.TypeCondition = p.parseName()
198	}
199
200	def.Directives = p.parseDirectives(false)
201	def.SelectionSet = p.parseRequiredSelectionSet()
202	return &def
203}
204
205func (p *parser) parseFragmentDefinition() *FragmentDefinition {
206	var def FragmentDefinition
207	def.Position = p.peekPos()
208	p.expectKeyword("fragment")
209
210	def.Name = p.parseFragmentName()
211	def.VariableDefinition = p.parseVariableDefinitions()
212
213	p.expectKeyword("on")
214
215	def.TypeCondition = p.parseName()
216	def.Directives = p.parseDirectives(false)
217	def.SelectionSet = p.parseRequiredSelectionSet()
218	return &def
219}
220
221func (p *parser) parseFragmentName() string {
222	if p.peek().Value == "on" {
223		p.unexpectedError()
224		return ""
225	}
226
227	return p.parseName()
228}
229
230func (p *parser) parseValueLiteral(isConst bool) *Value {
231	token := p.peek()
232
233	var kind ValueKind
234	switch token.Kind {
235	case lexer.BracketL:
236		return p.parseList(isConst)
237	case lexer.BraceL:
238		return p.parseObject(isConst)
239	case lexer.Dollar:
240		if isConst {
241			p.unexpectedError()
242			return nil
243		}
244		return &Value{Position: &token.Pos, Raw: p.parseVariable(), Kind: Variable}
245	case lexer.Int:
246		kind = IntValue
247	case lexer.Float:
248		kind = FloatValue
249	case lexer.String:
250		kind = StringValue
251	case lexer.BlockString:
252		kind = BlockValue
253	case lexer.Name:
254		switch token.Value {
255		case "true", "false":
256			kind = BooleanValue
257		case "null":
258			kind = NullValue
259		default:
260			kind = EnumValue
261		}
262	default:
263		p.unexpectedError()
264		return nil
265	}
266
267	p.next()
268
269	return &Value{Position: &token.Pos, Raw: token.Value, Kind: kind}
270}
271
272func (p *parser) parseList(isConst bool) *Value {
273	var values ChildValueList
274	pos := p.peekPos()
275	p.many(lexer.BracketL, lexer.BracketR, func() {
276		values = append(values, &ChildValue{Value: p.parseValueLiteral(isConst)})
277	})
278
279	return &Value{Children: values, Kind: ListValue, Position: pos}
280}
281
282func (p *parser) parseObject(isConst bool) *Value {
283	var fields ChildValueList
284	pos := p.peekPos()
285	p.many(lexer.BraceL, lexer.BraceR, func() {
286		fields = append(fields, p.parseObjectField(isConst))
287	})
288
289	return &Value{Children: fields, Kind: ObjectValue, Position: pos}
290}
291
292func (p *parser) parseObjectField(isConst bool) *ChildValue {
293	field := ChildValue{}
294	field.Position = p.peekPos()
295	field.Name = p.parseName()
296
297	p.expect(lexer.Colon)
298
299	field.Value = p.parseValueLiteral(isConst)
300	return &field
301}
302
303func (p *parser) parseDirectives(isConst bool) []*Directive {
304	var directives []*Directive
305
306	for p.peek().Kind == lexer.At {
307		if p.err != nil {
308			break
309		}
310		directives = append(directives, p.parseDirective(isConst))
311	}
312	return directives
313}
314
315func (p *parser) parseDirective(isConst bool) *Directive {
316	p.expect(lexer.At)
317
318	return &Directive{
319		Position:  p.peekPos(),
320		Name:      p.parseName(),
321		Arguments: p.parseArguments(isConst),
322	}
323}
324
325func (p *parser) parseTypeReference() *Type {
326	var typ Type
327
328	if p.skip(lexer.BracketL) {
329		typ.Position = p.peekPos()
330		typ.Elem = p.parseTypeReference()
331		p.expect(lexer.BracketR)
332	} else {
333		typ.Position = p.peekPos()
334		typ.NamedType = p.parseName()
335	}
336
337	if p.skip(lexer.Bang) {
338		typ.Position = p.peekPos()
339		typ.NonNull = true
340	}
341	return &typ
342}
343
344func (p *parser) parseName() string {
345	token := p.expect(lexer.Name)
346
347	return token.Value
348}