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