apollo_encoder/
operation.rs1use std::fmt;
2
3use crate::{Directive, SelectionSet, VariableDefinition};
4
5#[derive(Debug, Clone)]
55pub struct OperationDefinition {
56 operation_type: OperationType,
57 name: Option<String>,
58 variable_definitions: Vec<VariableDefinition>,
59 directives: Vec<Directive>,
60 selection_set: SelectionSet,
61 shorthand: bool,
64}
65
66impl OperationDefinition {
67 pub fn new(operation_type: OperationType, selection_set: SelectionSet) -> Self {
69 Self {
70 operation_type,
71 selection_set,
72 name: None,
73 variable_definitions: Vec::new(),
74 directives: Vec::new(),
75 shorthand: false,
76 }
77 }
78
79 pub fn name(&mut self, name: Option<String>) {
81 self.name = name;
82 }
83
84 pub fn variable_definition(&mut self, variable_definition: VariableDefinition) {
86 self.variable_definitions.push(variable_definition);
87 }
88
89 pub fn directive(&mut self, directive: Directive) {
91 self.directives.push(directive);
92 }
93
94 pub fn shorthand(&mut self) {
99 self.shorthand = true;
100 }
101}
102
103impl fmt::Display for OperationDefinition {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 let indent_level = 0;
106
107 if !self.shorthand {
108 write!(f, "{}", self.operation_type)?;
109 if let Some(name) = &self.name {
110 write!(f, " {name}")?;
111 }
112
113 if !self.variable_definitions.is_empty() {
114 write!(f, "(")?;
115 for (i, var_def) in self.variable_definitions.iter().enumerate() {
116 if i == self.variable_definitions.len() - 1 {
117 write!(f, "{var_def}")?;
118 } else {
119 write!(f, "{var_def}, ")?;
120 }
121 }
122 write!(f, ")")?;
123 }
124 for directive in &self.directives {
125 write!(f, " {directive}")?;
126 }
127 write!(f, " ")?;
128 }
129
130 write!(f, "{}", self.selection_set.format_with_indent(indent_level))?;
131
132 Ok(())
133 }
134}
135
136#[derive(Debug, Clone)]
143pub enum OperationType {
144 Query,
146 Mutation,
148 Subscription,
150}
151
152impl fmt::Display for OperationType {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 match self {
155 OperationType::Query => write!(f, "query"),
156 OperationType::Mutation => write!(f, "mutation"),
157 OperationType::Subscription => write!(f, "subscription"),
158 }
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 use crate::{field::Field, Argument, FragmentSpread, Selection, Type_, Value};
166 use indoc::indoc;
167
168 #[test]
169 fn it_encodes_a_query_operation() {
170 let selection_set = {
171 let sels = vec![
172 Selection::Field(Field::new(String::from("first"))),
173 Selection::Field(Field::new(String::from("second"))),
174 ];
175 let mut sel_set = SelectionSet::new();
176 sels.into_iter().for_each(|sel| sel_set.selection(sel));
177
178 sel_set
179 };
180 let var_def = VariableDefinition::new(
181 String::from("variable_def"),
182 Type_::List {
183 ty: Box::new(Type_::NamedType {
184 name: String::from("Int"),
185 }),
186 },
187 );
188 let mut new_op = OperationDefinition::new(OperationType::Query, selection_set);
189 let mut directive = Directive::new(String::from("testDirective"));
190 directive.arg(Argument::new(
191 String::from("first"),
192 Value::String("one".to_string()),
193 ));
194 new_op.variable_definition(var_def);
195 new_op.directive(directive);
196
197 assert_eq!(
198 new_op.to_string(),
199 indoc! { r#"
200 query($variable_def: [Int]) @testDirective(first: "one") {
201 first
202 second
203 }
204 "#}
205 );
206 }
207
208 #[test]
209 fn it_encodes_a_shorthand_query_operation() {
210 let selection_set = {
211 let sels = vec![
212 Selection::Field(Field::new(String::from("first"))),
213 Selection::Field(Field::new(String::from("second"))),
214 ];
215 let mut sel_set = SelectionSet::new();
216 sels.into_iter().for_each(|sel| sel_set.selection(sel));
217
218 sel_set
219 };
220 let mut new_op = OperationDefinition::new(OperationType::Query, selection_set);
221 new_op.shorthand();
222
223 assert_eq!(
224 new_op.to_string(),
225 indoc! { r#"
226 {
227 first
228 second
229 }
230 "#}
231 );
232 }
233
234 #[test]
235 fn it_encodes_a_deeper_query_operation() {
236 let fourth_field = Field::new("fourth".to_string());
238 let mut third_field = Field::new("third".to_string());
239 third_field.selection_set(Some(SelectionSet::with_selections(vec![Selection::Field(
240 fourth_field,
241 )])));
242 let mut second_field = Field::new("second".to_string());
243 second_field.selection_set(Some(SelectionSet::with_selections(vec![Selection::Field(
244 third_field,
245 )])));
246
247 let mut first_field = Field::new("first".to_string());
248 first_field.selection_set(Some(SelectionSet::with_selections(vec![Selection::Field(
249 second_field,
250 )])));
251
252 let selections = vec![
253 Selection::Field(first_field),
254 Selection::FragmentSpread(FragmentSpread::new(String::from("myFragment"))),
255 ];
256 let mut selection_set = SelectionSet::new();
257 selections
258 .into_iter()
259 .for_each(|s| selection_set.selection(s));
260 let var_def = VariableDefinition::new(
263 String::from("variable_def"),
264 Type_::List {
265 ty: Box::new(Type_::NamedType {
266 name: String::from("Int"),
267 }),
268 },
269 );
270 let mut new_op = OperationDefinition::new(OperationType::Query, selection_set);
271 let mut directive = Directive::new(String::from("testDirective"));
272 directive.arg(Argument::new(
273 String::from("first"),
274 Value::String("one".to_string()),
275 ));
276 new_op.variable_definition(var_def);
277 new_op.directive(directive);
278
279 assert_eq!(
280 new_op.to_string(),
281 indoc! { r#"
282 query($variable_def: [Int]) @testDirective(first: "one") {
283 first {
284 second {
285 third {
286 fourth
287 }
288 }
289 }
290 ...myFragment
291 }
292 "#}
293 );
294 }
295}