Skip to main content

apollo_parser/parser/grammar/
extensions.rs

1use crate::parser::grammar::enum_;
2use crate::parser::grammar::input;
3use crate::parser::grammar::interface;
4use crate::parser::grammar::object;
5use crate::parser::grammar::scalar;
6use crate::parser::grammar::schema;
7use crate::parser::grammar::union_;
8use crate::Parser;
9
10pub(crate) fn extensions(p: &mut Parser) {
11    // we already know the next node is 'extend', check for the node after that
12    // to figure out which type system extension to apply.
13    match p.peek_data_n(2) {
14        Some("schema") => schema::schema_extension(p),
15        Some("scalar") => scalar::scalar_type_extension(p),
16        Some("type") => object::object_type_extension(p),
17        Some("interface") => interface::interface_type_extension(p),
18        Some("union") => union_::union_type_extension(p),
19        Some("enum") => enum_::enum_type_extension(p),
20        Some("input") => input::input_object_type_extension(p),
21        _ => p.err_and_pop("Invalid Type System Extension. This extension cannot be applied."),
22    }
23}
24
25#[cfg(test)]
26mod test {
27    use crate::cst;
28    use crate::Parser;
29
30    #[test]
31    fn it_queries_graphql_extensions() {
32        let gql = r#"
33extend schema {
34    mutation: MyMutationType
35}
36extend scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
37extend type Business implements NamedEntity
38extend interface NamedEntity {
39    name: String
40}
41extend union SearchResult = Pet
42extend enum Pet {
43    GuineaPig
44    Cat
45}
46extend input First @include(if: "first")
47        "#;
48
49        let parser = Parser::new(gql);
50        let cst = parser.parse();
51
52        assert!(cst.errors().len() == 0);
53
54        let doc = cst.document();
55
56        for definition in doc.definitions() {
57            match definition {
58                cst::Definition::SchemaExtension(schema_ext) => {
59                    let root_operation_type: Vec<String> = schema_ext
60                        .root_operation_type_definitions()
61                        .filter_map(|def| Some(def.named_type()?.name()?.text().to_string()))
62                        .collect();
63                    assert_eq!(
64                        root_operation_type.as_slice(),
65                        ["MyMutationType".to_string()]
66                    )
67                }
68                cst::Definition::ScalarTypeExtension(scalar_ext) => {
69                    assert_eq!(
70                        scalar_ext
71                            .name()
72                            .expect("Cannot get scalar type extension name.")
73                            .text()
74                            .as_ref(),
75                        "UUID"
76                    );
77                }
78                cst::Definition::ObjectTypeExtension(obj_ext) => {
79                    assert_eq!(
80                        obj_ext
81                            .name()
82                            .expect("Cannot get object type extension name.")
83                            .text()
84                            .as_ref(),
85                        "Business"
86                    );
87                }
88                cst::Definition::InterfaceTypeExtension(interface_ext) => {
89                    assert_eq!(
90                        interface_ext
91                            .name()
92                            .expect("Cannot get interface type extension name.")
93                            .text()
94                            .as_ref(),
95                        "NamedEntity"
96                    );
97                }
98                cst::Definition::UnionTypeExtension(union_ext) => {
99                    assert_eq!(
100                        union_ext
101                            .name()
102                            .expect("Cannot get union type extension name.")
103                            .text()
104                            .as_ref(),
105                        "SearchResult"
106                    );
107                }
108                cst::Definition::EnumTypeExtension(enum_ext) => {
109                    assert_eq!(
110                        enum_ext
111                            .name()
112                            .expect("Cannot get enum type extension name.")
113                            .text()
114                            .as_ref(),
115                        "Pet"
116                    );
117                }
118                cst::Definition::InputObjectTypeExtension(input_object_ext) => {
119                    assert_eq!(
120                        input_object_ext
121                            .name()
122                            .expect("Cannot get input object type extension name.")
123                            .text()
124                            .as_ref(),
125                        "First"
126                    );
127                }
128                _ => unimplemented!(),
129            }
130        }
131    }
132
133    #[test]
134    fn it_reports_an_error_for_invalid_type_system_extension() {
135        let gql = r#"
136extend Cat
137        "#;
138
139        let parser = Parser::new(gql);
140        let cst = parser.parse();
141
142        assert!(cst.errors().len() == 2);
143        assert_eq!(cst.document().definitions().count(), 0);
144    }
145
146    #[test]
147    fn it_continuous_parsing_when_an_invalid_extension_is_given() {
148        let gql = r#"
149extend Cat
150
151extend interface NamedEntity {
152    name: String
153}
154        "#;
155
156        let parser = Parser::new(gql);
157        let cst = parser.parse();
158
159        assert!(cst.errors().len() == 2);
160        assert_eq!(cst.document().definitions().count(), 1);
161    }
162}