1use combine::{eof, many1, optional, position, StdParseResult};
2use combine::{parser, Parser};
3
4use super::ast::*;
5use super::error::ParseError;
6use crate::parser::common::Directive;
7use crate::parser::common::{arguments, default_value, directives, parse_type, string};
8use crate::parser::helpers::{ident, name, punct};
9use crate::parser::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>> {
104 position()
105 .skip(ident("query"))
106 .and(parser(operation_common))
107 .map(
108 |(position, (name, variable_definitions, directives, selection_set))| Query {
109 position,
110 name,
111 selection_set,
112 variable_definitions,
113 directives,
114 },
115 )
116 .parse_stream(input)
117 .into_result()
118}
119
120#[allow(type_alias_bounds)]
122type OperationCommon<'a, T: Text<'a>> = (
123 Option<T::Value>,
124 Vec<VariableDefinition<'a, T>>,
125 Vec<Directive<'a, T>>,
126 SelectionSet<'a, T>,
127);
128
129pub fn operation_common<'a, T: Text<'a>>(
130 input: &mut TokenStream<'a>,
131) -> StdParseResult<OperationCommon<'a, T>, TokenStream<'a>> {
132 optional(name::<'a, T>())
133 .and(
134 optional(
135 punct("(")
136 .with(many1(
137 (
138 position(),
139 optional(parser(string))
141 .with(punct("$"))
142 .with(name::<'a, T>())
143 .skip(punct(":")),
144 parser(parse_type),
145 optional(punct("=").with(parser(default_value))),
146 )
147 .map(
148 |(position, name, var_type, default_value)| VariableDefinition {
149 position,
150 name,
151 var_type,
152 default_value,
153 },
154 ),
155 ))
156 .skip(punct(")")),
157 )
158 .map(|vars| vars.unwrap_or_default()),
159 )
160 .and(parser(directives))
161 .and(parser(selection_set))
162 .map(|(((a, b), c), d)| (a, b, c, d))
163 .parse_stream(input)
164 .into_result()
165}
166
167pub fn mutation<'a, T: Text<'a>>(
168 input: &mut TokenStream<'a>,
169) -> StdParseResult<Mutation<'a, T>, TokenStream<'a>> {
170 position()
171 .skip(ident("mutation"))
172 .and(parser(operation_common))
173 .map(
174 |(position, (name, variable_definitions, directives, selection_set))| Mutation {
175 position,
176 name,
177 selection_set,
178 variable_definitions,
179 directives,
180 },
181 )
182 .parse_stream(input)
183 .into_result()
184}
185
186pub fn subscription<'a, T: Text<'a>>(
187 input: &mut TokenStream<'a>,
188) -> StdParseResult<Subscription<'a, T>, TokenStream<'a>> {
189 position()
190 .skip(ident("subscription"))
191 .and(parser(operation_common))
192 .map(
193 |(position, (name, variable_definitions, directives, selection_set))| Subscription {
194 position,
195 name,
196 selection_set,
197 variable_definitions,
198 directives,
199 },
200 )
201 .parse_stream(input)
202 .into_result()
203}
204
205pub fn operation_definition<'a, S>(
206 input: &mut TokenStream<'a>,
207) -> StdParseResult<OperationDefinition<'a, S>, TokenStream<'a>>
208where
209 S: Text<'a>,
210{
211 parser(selection_set)
212 .map(OperationDefinition::SelectionSet)
213 .or(parser(query).map(OperationDefinition::Query))
214 .or(parser(mutation).map(OperationDefinition::Mutation))
215 .or(parser(subscription).map(OperationDefinition::Subscription))
216 .parse_stream(input)
217 .into_result()
218}
219
220pub fn fragment_definition<'a, T: Text<'a>>(
221 input: &mut TokenStream<'a>,
222) -> StdParseResult<FragmentDefinition<'a, T>, TokenStream<'a>> {
223 (
224 position().skip(ident("fragment")),
225 name::<'a, T>(),
226 ident("on").with(name::<'a, T>()).map(TypeCondition::On),
227 parser(directives),
228 parser(selection_set),
229 )
230 .map(
231 |(position, name, type_condition, directives, selection_set)| FragmentDefinition {
232 position,
233 name,
234 type_condition,
235 directives,
236 selection_set,
237 },
238 )
239 .parse_stream(input)
240 .into_result()
241}
242
243pub fn definition<'a, S>(
244 input: &mut TokenStream<'a>,
245) -> StdParseResult<Definition<'a, S>, TokenStream<'a>>
246where
247 S: Text<'a>,
248{
249 parser(operation_definition)
250 .map(Definition::Operation)
251 .or(parser(fragment_definition).map(Definition::Fragment))
252 .parse_stream(input)
253 .into_result()
254}
255
256pub fn parse_query<'a, S>(s: &'a str) -> Result<Document<'a, S>, ParseError>
258where
259 S: Text<'a>,
260{
261 let tokens = TokenStream::new(s);
262 handle_token_stream(tokens)
263}
264
265pub fn parse_query_with_token_limit<'a, S>(
266 s: &'a str,
267 token_limit: usize,
268) -> Result<Document<'a, S>, ParseError>
269where
270 S: Text<'a>,
271{
272 let tokens = TokenStream::new_with_token_limit(s, token_limit);
273 handle_token_stream(tokens)
274}
275
276fn handle_token_stream<'a, S>(mut tokens: TokenStream<'a>) -> Result<Document<'a, S>, ParseError>
277where
278 S: Text<'a>,
279{
280 let (doc, _) = many1(parser(definition))
281 .map(|d| Document { definitions: d })
282 .skip(eof())
283 .parse_stream(&mut tokens)
284 .into_result()
285 .map_err(|e| e.into_inner().error)?;
286
287 Ok(doc)
288}
289
290pub fn consume_definition<'a, S>(s: &'a str) -> Result<(Definition<'a, S>, &'a str), ParseError>
293where
294 S: Text<'a>,
295{
296 let tokens = TokenStream::new(s);
297 let (doc, tokens) = parser(definition).parse(tokens)?;
298
299 Ok((doc, &s[tokens.offset()..]))
300}
301
302#[cfg(test)]
303mod test {
304 use super::*;
305 use super::{consume_definition, parse_query};
306 use crate::parser::position::Pos;
307
308 fn ast<'a>(s: &'a str) -> Document<'a, String> {
309 parse_query::<String>(s).unwrap().to_owned()
310 }
311
312 #[test]
313 fn one_field() {
314 assert_eq!(
315 ast("{ a }"),
316 Document {
317 definitions: vec![Definition::Operation(OperationDefinition::SelectionSet(
318 SelectionSet {
319 span: (Pos { line: 1, column: 1 }, Pos { line: 1, column: 5 }),
320 items: vec![Selection::Field(Field {
321 position: Pos { line: 1, column: 3 },
322 alias: None,
323 name: "a".into(),
324 arguments: Vec::new(),
325 directives: Vec::new(),
326 selection_set: SelectionSet {
327 span: (Pos { line: 1, column: 3 }, Pos { line: 1, column: 3 }),
328 items: Vec::new()
329 },
330 }),],
331 }
332 ))],
333 }
334 );
335 }
336
337 #[test]
338 fn builtin_values() {
339 assert_eq!(
340 ast("{ a(t: true, f: false, n: null) }"),
341 Document {
342 definitions: vec![Definition::Operation(OperationDefinition::SelectionSet(
343 SelectionSet {
344 span: (
345 Pos { line: 1, column: 1 },
346 Pos {
347 line: 1,
348 column: 33
349 }
350 ),
351 items: vec![Selection::Field(Field {
352 position: Pos { line: 1, column: 3 },
353 alias: None,
354 name: "a".into(),
355 arguments: vec![
356 ("t".into(), Value::Boolean(true)),
357 ("f".into(), Value::Boolean(false)),
358 ("n".into(), Value::Null),
359 ],
360 directives: Vec::new(),
361 selection_set: SelectionSet {
362 span: (Pos { line: 1, column: 3 }, Pos { line: 1, column: 3 }),
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 = "PosOverflow")]
379 fn large_integer() {
380 ast("{ a(x: 10000000000000000000000000000 }");
381 }
382
383 #[test]
384 fn variable_definition_descriptions() {
385 assert_eq!(
386 ast(r#"query ("a" $a: Int, """b""" $b: String = "x") { f(a: $a, b: $b) }"#).to_string(),
387 ast(r#"query ($a: Int, $b: String = "x") { f(a: $a, b: $b) }"#).to_string(),
388 );
389 }
390
391 #[test]
392 fn consume_single_query() {
393 let (query, remainder) = consume_definition::<String>("query { a } query { b }").unwrap();
394 assert!(matches!(query, Definition::Operation(_)));
395 assert_eq!(remainder, "query { b }");
396 }
397
398 #[test]
399 fn consume_full_text() {
400 let (query, remainder) = consume_definition::<String>("query { a }").unwrap();
401 assert!(matches!(query, Definition::Operation(_)));
402 assert_eq!(remainder, "");
403 }
404
405 #[test]
406 fn consume_single_query_preceding_non_graphql() {
407 let (query, remainder) =
408 consume_definition::<String>("query { a } where a > 1 => 10.0").unwrap();
409 assert!(matches!(query, Definition::Operation(_)));
410 assert_eq!(remainder, "where a > 1 => 10.0");
411 }
412
413 #[test]
414 fn consume_fails_without_operation() {
415 let err = consume_definition::<String>("where a > 1 => 10.0")
416 .expect_err("Expected parse to fail with an error");
417 let err = format!("{}", err);
418 assert_eq!(err, "Parse error at 1:1\nUnexpected `where[Name]`\nExpected {, query, mutation, subscription or fragment\n");
419 }
420
421 #[test]
422 fn recursion_too_deep() {
423 let query = format!(
424 "{}(b: {}{}){}",
425 "{ a".repeat(30),
426 "[".repeat(25),
427 "]".repeat(25),
428 "}".repeat(30)
429 );
430 let result = parse_query::<&str>(&query);
431 let err = format!("{}", result.unwrap_err());
432 assert_eq!(
433 &err,
434 "Parse error at 1:114\nExpected ]\nRecursion limit exceeded\n"
435 )
436 }
437}