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};
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 punct("$").with(name::<'a, T>()).skip(punct(":")),
140 parser(parse_type),
141 optional(punct("=").with(parser(default_value))),
142 )
143 .map(
144 |(position, name, var_type, default_value)| VariableDefinition {
145 position,
146 name,
147 var_type,
148 default_value,
149 },
150 ),
151 ))
152 .skip(punct(")")),
153 )
154 .map(|vars| vars.unwrap_or_default()),
155 )
156 .and(parser(directives))
157 .and(parser(selection_set))
158 .map(|(((a, b), c), d)| (a, b, c, d))
159 .parse_stream(input)
160 .into_result()
161}
162
163pub fn mutation<'a, T: Text<'a>>(
164 input: &mut TokenStream<'a>,
165) -> StdParseResult<Mutation<'a, T>, TokenStream<'a>> {
166 position()
167 .skip(ident("mutation"))
168 .and(parser(operation_common))
169 .map(
170 |(position, (name, variable_definitions, directives, selection_set))| Mutation {
171 position,
172 name,
173 selection_set,
174 variable_definitions,
175 directives,
176 },
177 )
178 .parse_stream(input)
179 .into_result()
180}
181
182pub fn subscription<'a, T: Text<'a>>(
183 input: &mut TokenStream<'a>,
184) -> StdParseResult<Subscription<'a, T>, TokenStream<'a>> {
185 position()
186 .skip(ident("subscription"))
187 .and(parser(operation_common))
188 .map(
189 |(position, (name, variable_definitions, directives, selection_set))| Subscription {
190 position,
191 name,
192 selection_set,
193 variable_definitions,
194 directives,
195 },
196 )
197 .parse_stream(input)
198 .into_result()
199}
200
201pub fn operation_definition<'a, S>(
202 input: &mut TokenStream<'a>,
203) -> StdParseResult<OperationDefinition<'a, S>, TokenStream<'a>>
204where
205 S: Text<'a>,
206{
207 parser(selection_set)
208 .map(OperationDefinition::SelectionSet)
209 .or(parser(query).map(OperationDefinition::Query))
210 .or(parser(mutation).map(OperationDefinition::Mutation))
211 .or(parser(subscription).map(OperationDefinition::Subscription))
212 .parse_stream(input)
213 .into_result()
214}
215
216pub fn fragment_definition<'a, T: Text<'a>>(
217 input: &mut TokenStream<'a>,
218) -> StdParseResult<FragmentDefinition<'a, T>, TokenStream<'a>> {
219 (
220 position().skip(ident("fragment")),
221 name::<'a, T>(),
222 ident("on").with(name::<'a, T>()).map(TypeCondition::On),
223 parser(directives),
224 parser(selection_set),
225 )
226 .map(
227 |(position, name, type_condition, directives, selection_set)| FragmentDefinition {
228 position,
229 name,
230 type_condition,
231 directives,
232 selection_set,
233 },
234 )
235 .parse_stream(input)
236 .into_result()
237}
238
239pub fn definition<'a, S>(
240 input: &mut TokenStream<'a>,
241) -> StdParseResult<Definition<'a, S>, TokenStream<'a>>
242where
243 S: Text<'a>,
244{
245 parser(operation_definition)
246 .map(Definition::Operation)
247 .or(parser(fragment_definition).map(Definition::Fragment))
248 .parse_stream(input)
249 .into_result()
250}
251
252pub fn parse_query<'a, S>(s: &'a str) -> Result<Document<'a, S>, ParseError>
254where
255 S: Text<'a>,
256{
257 let mut tokens = TokenStream::new(s);
258 let (doc, _) = many1(parser(definition))
259 .map(|d| Document { definitions: d })
260 .skip(eof())
261 .parse_stream(&mut tokens)
262 .into_result()
263 .map_err(|e| e.into_inner().error)?;
264
265 Ok(doc)
266}
267
268pub fn consume_definition<'a, S>(s: &'a str) -> Result<(Definition<'a, S>, &'a str), ParseError>
271where
272 S: Text<'a>,
273{
274 let tokens = TokenStream::new(s);
275 let (doc, tokens) = parser(definition).parse(tokens)?;
276
277 Ok((doc, &s[tokens.offset()..]))
278}
279
280#[cfg(test)]
281mod test {
282 use super::*;
283 use super::{consume_definition, parse_query};
284 use crate::parser::position::Pos;
285
286 fn ast<'a>(s: &'a str) -> Document<'a, String> {
287 parse_query::<String>(s).unwrap().to_owned()
288 }
289
290 #[test]
291 fn one_field() {
292 assert_eq!(
293 ast("{ a }"),
294 Document {
295 definitions: vec![Definition::Operation(OperationDefinition::SelectionSet(
296 SelectionSet {
297 span: (Pos { line: 1, column: 1 }, Pos { line: 1, column: 5 }),
298 items: vec![Selection::Field(Field {
299 position: Pos { line: 1, column: 3 },
300 alias: None,
301 name: "a".into(),
302 arguments: Vec::new(),
303 directives: Vec::new(),
304 selection_set: SelectionSet {
305 span: (Pos { line: 1, column: 3 }, Pos { line: 1, column: 3 }),
306 items: Vec::new()
307 },
308 }),],
309 }
310 ))],
311 }
312 );
313 }
314
315 #[test]
316 fn builtin_values() {
317 assert_eq!(
318 ast("{ a(t: true, f: false, n: null) }"),
319 Document {
320 definitions: vec![Definition::Operation(OperationDefinition::SelectionSet(
321 SelectionSet {
322 span: (
323 Pos { line: 1, column: 1 },
324 Pos {
325 line: 1,
326 column: 33
327 }
328 ),
329 items: vec![Selection::Field(Field {
330 position: Pos { line: 1, column: 3 },
331 alias: None,
332 name: "a".into(),
333 arguments: vec![
334 ("t".into(), Value::Boolean(true)),
335 ("f".into(), Value::Boolean(false)),
336 ("n".into(), Value::Null),
337 ],
338 directives: Vec::new(),
339 selection_set: SelectionSet {
340 span: (Pos { line: 1, column: 3 }, Pos { line: 1, column: 3 }),
341 items: Vec::new()
342 },
343 }),],
344 }
345 ))],
346 }
347 );
348 }
349
350 #[test]
351 fn one_field_roundtrip() {
352 assert_eq!(ast("{ a }").to_string(), "{\n a\n}\n");
353 }
354
355 #[test]
356 #[should_panic(expected = "number too large")]
357 fn large_integer() {
358 ast("{ a(x: 10000000000000000000000000000 }");
359 }
360
361 #[test]
362 fn consume_single_query() {
363 let (query, remainder) = consume_definition::<String>("query { a } query { b }").unwrap();
364 assert!(matches!(query, Definition::Operation(_)));
365 assert_eq!(remainder, "query { b }");
366 }
367
368 #[test]
369 fn consume_full_text() {
370 let (query, remainder) = consume_definition::<String>("query { a }").unwrap();
371 assert!(matches!(query, Definition::Operation(_)));
372 assert_eq!(remainder, "");
373 }
374
375 #[test]
376 fn consume_single_query_preceding_non_graphql() {
377 let (query, remainder) =
378 consume_definition::<String>("query { a } where a > 1 => 10.0").unwrap();
379 assert!(matches!(query, Definition::Operation(_)));
380 assert_eq!(remainder, "where a > 1 => 10.0");
381 }
382
383 #[test]
384 fn consume_fails_without_operation() {
385 let err = consume_definition::<String>("where a > 1 => 10.0")
386 .expect_err("Expected parse to fail with an error");
387 let err = format!("{}", err);
388 assert_eq!(err, "query parse error: Parse error at 1:1\nUnexpected `where[Name]`\nExpected {, query, mutation, subscription or fragment\n");
389 }
390
391 #[test]
392 fn recursion_too_deep() {
393 let query = format!(
394 "{}(b: {}{}){}",
395 "{ a".repeat(30),
396 "[".repeat(25),
397 "]".repeat(25),
398 "}".repeat(30)
399 );
400 let result = parse_query::<&str>(&query);
401 let err = format!("{}", result.unwrap_err());
402 assert_eq!(
403 &err,
404 "query parse error: Parse error at 1:114\nExpected ]\nRecursion limit exceeded\n"
405 )
406 }
407}