Skip to main content

apollo_parser/parser/grammar/
argument.rs

1use crate::parser::grammar::input;
2use crate::parser::grammar::name;
3use crate::parser::grammar::value;
4use crate::parser::grammar::value::Constness;
5use crate::Parser;
6use crate::SyntaxKind;
7use crate::TokenKind;
8use crate::S;
9use crate::T;
10use std::ops::ControlFlow;
11
12/// See: https://spec.graphql.org/October2021/#Argument
13///
14/// *Argument[Const]*:
15///    Name **:** Value[?Const]
16pub(crate) fn argument(p: &mut Parser, constness: Constness) {
17    let _guard = p.start_node(SyntaxKind::ARGUMENT);
18    name::name(p);
19    if let Some(T![:]) = p.peek() {
20        p.bump(S![:]);
21        value::value(p, constness, false);
22    }
23}
24
25/// See: https://spec.graphql.org/October2021/#Arguments
26///
27/// *Arguments[Const]*:
28///    **(** Argument[?Const]* **)**
29pub(crate) fn arguments(p: &mut Parser, constness: Constness) {
30    let _g = p.start_node(SyntaxKind::ARGUMENTS);
31    p.bump(S!['(']);
32    if let Some(TokenKind::Name) = p.peek() {
33        argument(p, constness);
34    } else {
35        p.err("expected an Argument");
36    }
37    p.peek_while_kind(TokenKind::Name, |p| {
38        argument(p, constness);
39    });
40    p.expect(T![')'], S![')']);
41}
42
43/// See: https://spec.graphql.org/October2021/#ArgumentsDefinition
44///
45/// *ArgumentsDefinition*:
46///     **(** InputValueDefinition* **)**
47pub(crate) fn arguments_definition(p: &mut Parser) {
48    let _g = p.start_node(SyntaxKind::ARGUMENTS_DEFINITION);
49    p.bump(S!['(']);
50    if let Some(TokenKind::Name | TokenKind::StringValue) = p.peek() {
51        input::input_value_definition(p);
52    } else {
53        p.err("expected an Argument Definition");
54    }
55    p.peek_while(|p, kind| match kind {
56        TokenKind::Name | TokenKind::StringValue => {
57            input::input_value_definition(p);
58            ControlFlow::Continue(())
59        }
60        _ => ControlFlow::Break(()),
61    });
62    p.expect(T![')'], S![')']);
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use crate::cst;
69    use crate::cst::CstNode;
70
71    #[test]
72    fn it_can_access_arguments_in_fields() {
73        let schema = r#"
74type Query {
75  bestSellers(category: ProductCategory = ALL): [Product] @join__field(graph: PRODUCTS)
76  categories: [Department] @join__field(graph: PRODUCTS)
77  product(id: ID!): Product @join__field(graph: PRODUCTS)
78}
79        "#;
80        let parser = Parser::new(schema);
81        let cst = parser.parse();
82
83        assert!(cst.errors.is_empty());
84
85        let document = cst.document();
86        for definition in document.definitions() {
87            if let cst::Definition::ObjectTypeDefinition(obj_def) = definition {
88                for field in obj_def.fields_definition().unwrap().field_definitions() {
89                    if field.name().unwrap().text() == "bestSellers" {
90                        let argument = field
91                            .arguments_definition()
92                            .unwrap()
93                            .input_value_definitions()
94                            .next()
95                            .unwrap();
96                        assert_eq!(argument.name().unwrap().text(), "category");
97                        assert_eq!(argument.ty().unwrap().source_string(), "ProductCategory");
98                        assert_eq!(
99                            argument
100                                .default_value()
101                                .unwrap()
102                                .value()
103                                .unwrap()
104                                .source_string(),
105                            "ALL"
106                        );
107                    }
108                }
109            }
110        }
111    }
112}