1use combine::combinator::{eof, many1, optional, position};
2use combine::{parser, ParseResult, Parser};
3
4use crate::common::Directive;
5use crate::common::{arguments, default_value, directives, parse_type};
6use crate::helpers::{ident, name, punct};
7use crate::query::ast::*;
8use crate::query::error::ParseError;
9use crate::tokenizer::TokenStream;
10
11pub fn field<'a, S>(
12 input: &mut TokenStream<'a>,
13) -> ParseResult<Field<'a, S>, TokenStream<'a>>
14where
15 S: Text<'a>,
16{
17 (
18 position(),
19 name::<'a, S>(),
20 optional(punct(":").with(name::<'a, S>())),
21 parser(arguments),
22 parser(directives),
23 optional(parser(selection_set)),
24 )
25 .map(
26 |(position, name_or_alias, opt_name, arguments, directives, sel)| {
27 let (name, alias) = match opt_name {
28 Some(name) => (name, Some(name_or_alias)),
29 None => (name_or_alias, None),
30 };
31 Field {
32 position,
33 name,
34 alias,
35 arguments,
36 directives,
37 selection_set: sel.unwrap_or_else(|| SelectionSet {
38 span: (position, position),
39 items: Vec::new(),
40 }),
41 }
42 },
43 )
44 .parse_stream(input)
45}
46
47pub fn selection<'a, S>(
48 input: &mut TokenStream<'a>,
49) -> ParseResult<Selection<'a, S>, TokenStream<'a>>
50where
51 S: Text<'a>,
52{
53 parser(field)
54 .map(Selection::Field)
55 .or(punct("...").with(
56 (
57 position(),
58 optional(ident("on").with(name::<'a, S>()).map(TypeCondition::On)),
59 parser(directives),
60 parser(selection_set),
61 )
62 .map(|(position, type_condition, directives, selection_set)| {
63 InlineFragment {
64 position,
65 type_condition,
66 selection_set,
67 directives,
68 }
69 })
70 .map(Selection::InlineFragment)
71 .or((position(), name::<'a, S>(), parser(directives))
72 .map(|(position, fragment_name, directives)| FragmentSpread {
73 position,
74 fragment_name,
75 directives,
76 })
77 .map(Selection::FragmentSpread)),
78 ))
79 .parse_stream(input)
80}
81
82pub fn selection_set<'a, S>(
83 input: &mut TokenStream<'a>,
84) -> ParseResult<SelectionSet<'a, S>, TokenStream<'a>>
85where
86 S: Text<'a>,
87{
88 (
89 position().skip(punct("{")),
90 many1(parser(selection)),
91 position().skip(punct("}")),
92 )
93 .map(|(start, items, end)| SelectionSet {
94 span: (start, end),
95 items,
96 })
97 .parse_stream(input)
98}
99
100pub fn query<'a, T: Text<'a>>(
101 input: &mut TokenStream<'a>,
102) -> ParseResult<Query<'a, T>, TokenStream<'a>>
103where
104 T: Text<'a>,
105{
106 position()
107 .skip(ident("query"))
108 .and(parser(operation_common))
109 .map(
110 |(position, (name, variable_definitions, directives, selection_set))| Query {
111 position,
112 name,
113 selection_set,
114 variable_definitions,
115 directives,
116 },
117 )
118 .parse_stream(input)
119}
120
121#[allow(type_alias_bounds)]
123type OperationCommon<'a, T: Text<'a>> = (
124 Option<T::Value>,
125 Vec<VariableDefinition<'a, T>>,
126 Vec<Directive<'a, T>>,
127 SelectionSet<'a, T>,
128);
129
130pub fn operation_common<'a, T: Text<'a>>(
131 input: &mut TokenStream<'a>,
132) -> ParseResult<OperationCommon<'a, T>, TokenStream<'a>>
133where
134 T: Text<'a>,
135{
136 optional(name::<'a, T>())
137 .and(
138 optional(
139 punct("(")
140 .with(many1(
141 (
142 position(),
143 punct("$").with(name::<'a, T>()).skip(punct(":")),
144 parser(parse_type),
145 optional(punct("=").with(parser(default_value))),
146 )
147 .map(
148 |(position, name, var_type, default_value)| {
149 VariableDefinition {
150 position,
151 name,
152 var_type,
153 default_value,
154 }
155 },
156 ),
157 ))
158 .skip(punct(")")),
159 )
160 .map(|vars| vars.unwrap_or_default()),
161 )
162 .and(parser(directives))
163 .and(parser(selection_set))
164 .map(|(((a, b), c), d)| (a, b, c, d))
165 .parse_stream(input)
166}
167
168pub fn mutation<'a, T: Text<'a>>(
169 input: &mut TokenStream<'a>,
170) -> ParseResult<Mutation<'a, T>, TokenStream<'a>>
171where
172 T: Text<'a>,
173{
174 position()
175 .skip(ident("mutation"))
176 .and(parser(operation_common))
177 .map(
178 |(position, (name, variable_definitions, directives, selection_set))| {
179 Mutation {
180 position,
181 name,
182 selection_set,
183 variable_definitions,
184 directives,
185 }
186 },
187 )
188 .parse_stream(input)
189}
190
191pub fn subscription<'a, T: Text<'a>>(
192 input: &mut TokenStream<'a>,
193) -> ParseResult<Subscription<'a, T>, TokenStream<'a>>
194where
195 T: Text<'a>,
196{
197 position()
198 .skip(ident("subscription"))
199 .and(parser(operation_common))
200 .map(
201 |(position, (name, variable_definitions, directives, selection_set))| {
202 Subscription {
203 position,
204 name,
205 selection_set,
206 variable_definitions,
207 directives,
208 }
209 },
210 )
211 .parse_stream(input)
212}
213
214pub fn operation_definition<'a, S>(
215 input: &mut TokenStream<'a>,
216) -> ParseResult<OperationDefinition<'a, S>, TokenStream<'a>>
217where
218 S: Text<'a>,
219{
220 parser(selection_set)
221 .map(OperationDefinition::SelectionSet)
222 .or(parser(query).map(OperationDefinition::Query))
223 .or(parser(mutation).map(OperationDefinition::Mutation))
224 .or(parser(subscription).map(OperationDefinition::Subscription))
225 .parse_stream(input)
226}
227
228pub fn fragment_definition<'a, T: Text<'a>>(
229 input: &mut TokenStream<'a>,
230) -> ParseResult<FragmentDefinition<'a, T>, TokenStream<'a>>
231where
232 T: Text<'a>,
233{
234 (
235 position().skip(ident("fragment")),
236 name::<'a, T>(),
237 ident("on").with(name::<'a, T>()).map(TypeCondition::On),
238 parser(directives),
239 parser(selection_set),
240 )
241 .map(
242 |(position, name, type_condition, directives, selection_set)| {
243 FragmentDefinition {
244 position,
245 name,
246 type_condition,
247 directives,
248 selection_set,
249 }
250 },
251 )
252 .parse_stream(input)
253}
254
255pub fn definition<'a, S>(
256 input: &mut TokenStream<'a>,
257) -> ParseResult<Definition<'a, S>, TokenStream<'a>>
258where
259 S: Text<'a>,
260{
261 parser(operation_definition)
262 .map(Definition::Operation)
263 .or(parser(fragment_definition).map(Definition::Fragment))
264 .parse_stream(input)
265}
266
267pub fn parse_query<'a, S>(s: &'a str) -> Result<Document<'a, S>, ParseError>
269where
270 S: Text<'a>,
271{
272 let mut tokens = TokenStream::new(s);
273 let (doc, _) = many1(parser(definition))
274 .map(|d| Document { definitions: d })
275 .skip(eof())
276 .parse_stream(&mut tokens)
277 .map_err(|e| e.into_inner().error)?;
278
279 Ok(doc)
280}
281
282pub fn consume_definition<'a, S>(
285 s: &'a str,
286) -> Result<(Definition<'a, S>, &'a str), ParseError>
287where
288 S: Text<'a>,
289{
290 let tokens = TokenStream::new(s);
291 let (doc, tokens) = parser(definition).parse(tokens)?;
292
293 Ok((doc, &s[tokens.offset()..]))
294}
295
296#[cfg(test)]
297mod test {
298 use super::{consume_definition, parse_query};
299 use crate::position::Pos;
300 use crate::query::grammar::*;
301
302 fn ast(s: &str) -> Document<String> {
303 parse_query::<String>(s).unwrap()
304 }
305
306 #[test]
307 fn one_field() {
308 assert_eq!(
309 ast("{ a }"),
310 Document {
311 definitions: vec![Definition::Operation(
312 OperationDefinition::SelectionSet(SelectionSet {
313 span: (Pos { line: 1, column: 1 }, Pos { line: 1, column: 5 }),
314 items: vec![Selection::Field(Field {
315 position: Pos { line: 1, column: 3 },
316 alias: None,
317 name: "a".into(),
318 arguments: Vec::new(),
319 directives: Vec::new(),
320 selection_set: SelectionSet {
321 span: (
322 Pos { line: 1, column: 3 },
323 Pos { line: 1, column: 3 }
324 ),
325 items: Vec::new()
326 },
327 }),],
328 })
329 )],
330 }
331 );
332 }
333
334 #[test]
335 fn builtin_values() {
336 assert_eq!(
337 ast("{ a(t: true, f: false, n: null) }"),
338 Document {
339 definitions: vec![Definition::Operation(
340 OperationDefinition::SelectionSet(SelectionSet {
341 span: (
342 Pos { line: 1, column: 1 },
343 Pos {
344 line: 1,
345 column: 33
346 }
347 ),
348 items: vec![Selection::Field(Field {
349 position: Pos { line: 1, column: 3 },
350 alias: None,
351 name: "a".into(),
352 arguments: vec![
353 ("t".into(), Value::Boolean(true)),
354 ("f".into(), Value::Boolean(false)),
355 ("n".into(), Value::Null),
356 ],
357 directives: Vec::new(),
358 selection_set: SelectionSet {
359 span: (
360 Pos { line: 1, column: 3 },
361 Pos { line: 1, column: 3 }
362 ),
363 items: Vec::new()
364 },
365 }),],
366 })
367 )],
368 }
369 );
370 }
371
372 #[test]
373 fn one_field_roundtrip() {
374 assert_eq!(ast("{ a }").to_string(), "{\n a\n}\n");
375 }
376
377 #[test]
378 #[should_panic(expected = "number too large")]
379 fn large_integer() {
380 ast("{ a(x: 340282366920938463463374607431768211456 }");
381 }
382
383 #[test]
384 fn consume_single_query() {
385 let (query, remainder) =
386 consume_definition::<String>("query { a } query { b }").unwrap();
387 assert!(matches!(query, Definition::Operation(_)));
388 assert_eq!(remainder, "query { b }");
389 }
390
391 #[test]
392 fn consume_full_text() {
393 let (query, remainder) = consume_definition::<String>("query { a }").unwrap();
394 assert!(matches!(query, Definition::Operation(_)));
395 assert_eq!(remainder, "");
396 }
397
398 #[test]
399 fn consume_single_query_preceding_non_graphql() {
400 let (query, remainder) =
401 consume_definition::<String>("query { a } where a > 1 => 10.0").unwrap();
402 assert!(matches!(query, Definition::Operation(_)));
403 assert_eq!(remainder, "where a > 1 => 10.0");
404 }
405
406 #[test]
407 fn consume_fails_without_operation() {
408 let err = consume_definition::<String>("where a > 1 => 10.0")
409 .expect_err("Expected parse to fail with an error");
410 let err = format!("{}", err);
411 assert_eq!(err, "query parse error: Parse error at 1:1\nUnexpected `where[Name]`\nExpected `{`, `query`, `mutation`, `subscription` or `fragment`\n");
412 }
413
414 #[test]
415 fn recursion_too_deep() {
416 let query = format!(
417 "{}(b: {}{}){}",
418 "{ a".repeat(30),
419 "[".repeat(25),
420 "]".repeat(25),
421 "}".repeat(30)
422 );
423 let result = parse_query::<&str>(&query);
424 let err = format!("{}", result.unwrap_err());
425 assert_eq!(
426 &err,
427 "query parse error: Parse error at 1:114\nExpected `]`\nRecursion limit exceeded\n"
428 )
429 }
430}