apollo_parser/parser/grammar/
extensions.rs1use 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 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}