apollo_encoder/
fragment.rs1use std::fmt::{self, Write as _};
2
3use crate::{Directive, SelectionSet};
4
5#[derive(Debug, Clone)]
38pub struct FragmentDefinition {
39 name: String,
40 type_condition: TypeCondition,
41 directives: Vec<Directive>,
42 selection_set: SelectionSet,
43}
44
45impl FragmentDefinition {
46 pub fn new(name: String, type_condition: TypeCondition, selection_set: SelectionSet) -> Self {
48 Self {
49 name,
50 type_condition,
51 selection_set,
52 directives: Vec::new(),
53 }
54 }
55
56 pub fn directive(&mut self, directive: Directive) {
58 self.directives.push(directive)
59 }
60}
61
62impl fmt::Display for FragmentDefinition {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 let indent_level = 0;
65 write!(f, "fragment {} {}", self.name, self.type_condition)?;
66 for directive in &self.directives {
67 write!(f, " {directive}")?;
68 }
69 write!(
70 f,
71 " {}",
72 self.selection_set.format_with_indent(indent_level)
73 )?;
74
75 Ok(())
76 }
77}
78
79#[derive(Debug, Clone, PartialEq)]
94pub struct FragmentSpread {
95 name: String,
96 directives: Vec<Directive>,
97}
98
99impl FragmentSpread {
100 pub fn new(name: String) -> Self {
102 Self {
103 name,
104 directives: Vec::new(),
105 }
106 }
107
108 pub fn directive(&mut self, directive: Directive) {
110 self.directives.push(directive)
111 }
112}
113
114impl fmt::Display for FragmentSpread {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(f, "...{}", self.name)?;
117 for directive in &self.directives {
118 write!(f, " {directive}")?;
119 }
120
121 Ok(())
122 }
123}
124
125#[derive(Debug, Clone, PartialEq)]
156pub struct InlineFragment {
157 type_condition: Option<TypeCondition>,
158 directives: Vec<Directive>,
159 selection_set: SelectionSet,
160 pub(crate) indent_level: usize,
161}
162
163impl InlineFragment {
164 pub fn new(selection_set: SelectionSet) -> Self {
166 Self {
167 selection_set,
168 type_condition: Option::default(),
169 directives: Vec::new(),
170 indent_level: 0,
171 }
172 }
173
174 pub fn directive(&mut self, directive: Directive) {
176 self.directives.push(directive)
177 }
178
179 pub fn type_condition(&mut self, type_condition: Option<TypeCondition>) {
181 self.type_condition = type_condition;
182 }
183
184 pub(crate) fn format_with_indent(&self, indent_level: usize) -> String {
187 let mut text = String::from("...");
188
189 if let Some(type_condition) = &self.type_condition {
190 let _ = write!(text, " {type_condition}");
191 }
192 for directive in &self.directives {
193 let _ = write!(text, " {directive}");
194 }
195
196 let _ = write!(
197 text,
198 " {}",
199 self.selection_set.format_with_indent(indent_level),
200 );
201
202 text
203 }
204}
205
206impl fmt::Display for InlineFragment {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 let indent_level = 0;
211 write!(f, "{}", self.format_with_indent(indent_level))
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq)]
222pub struct TypeCondition {
223 name: String,
224}
225
226impl TypeCondition {
227 pub fn new(name: String) -> Self {
229 Self { name }
230 }
231}
232
233impl fmt::Display for TypeCondition {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 write!(f, "on {}", self.name)
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use indoc::indoc;
242
243 use crate::{field::Field, Argument, Selection, Value};
244
245 use super::*;
246
247 #[test]
248 fn it_encodes_simple_inline_fragment() {
249 let selections = vec![Selection::Field(Field::new(String::from("myField")))];
250 let mut selection_set = SelectionSet::new();
251 selections
252 .into_iter()
253 .for_each(|s| selection_set.selection(s));
254
255 let mut inline_fragment = InlineFragment::new(selection_set);
256 inline_fragment.type_condition(Some(TypeCondition::new(String::from("User"))));
257
258 assert_eq!(
259 inline_fragment.to_string(),
260 indoc! {r#"
261 ... on User {
262 myField
263 }
264 "#}
265 );
266 }
267
268 #[test]
269 fn it_encodes_simple_fragment_spread() {
270 let fragment = FragmentSpread::new(String::from("myFragment"));
271
272 assert_eq!(fragment.to_string(), indoc! {r#"...myFragment"#});
273 }
274
275 #[test]
276 fn it_encodes_deeper_inline_fragment() {
277 let another_nested_field_bis = Field::new(String::from("anotherNestedBisField"));
278
279 let mut another_nested_field = Field::new(String::from("anotherNestedField"));
280 let mut selection_set = SelectionSet::new();
281 selection_set.selection(Selection::Field(another_nested_field_bis));
282 another_nested_field.selection_set(selection_set.into());
283
284 let mut selection_set = SelectionSet::new();
285 selection_set.selection(Selection::Field(another_nested_field.clone()));
286 another_nested_field.selection_set(selection_set.into());
287
288 let nested_selections = vec![
289 Selection::Field(Field::new(String::from("nestedField"))),
290 Selection::Field(another_nested_field),
291 ];
292 let mut nested_selection_set = SelectionSet::new();
293 nested_selections
294 .into_iter()
295 .for_each(|s| nested_selection_set.selection(s));
296
297 let other_inline_fragment = InlineFragment::new(nested_selection_set);
298 let selections = vec![
299 Selection::Field(Field::new(String::from("myField"))),
300 Selection::FragmentSpread(FragmentSpread::new(String::from("myFragment"))),
301 Selection::InlineFragment(other_inline_fragment),
302 ];
303 let mut selection_set = SelectionSet::new();
304 selections
305 .into_iter()
306 .for_each(|s| selection_set.selection(s));
307
308 let mut inline_fragment = InlineFragment::new(selection_set);
309 inline_fragment.type_condition(Some(TypeCondition::new(String::from("User"))));
310
311 assert_eq!(
312 inline_fragment.to_string(),
313 indoc! {r#"
314 ... on User {
315 myField
316 ...myFragment
317 ... {
318 nestedField
319 anotherNestedField {
320 anotherNestedField {
321 anotherNestedBisField
322 }
323 }
324 }
325 }
326 "#}
327 );
328 }
329
330 #[test]
331 fn it_encodes_fragment_definition() {
332 let selections = vec![Selection::Field(Field::new(String::from("myField")))];
333 let mut selection_set = SelectionSet::new();
334 selections
335 .into_iter()
336 .for_each(|s| selection_set.selection(s));
337 let mut fragment_def = FragmentDefinition::new(
338 String::from("myFragment"),
339 TypeCondition::new(String::from("User")),
340 selection_set,
341 );
342 let mut directive = Directive::new(String::from("myDirective"));
343 directive.arg(Argument::new(String::from("first"), Value::Int(5)));
344 fragment_def.directive(directive);
345
346 assert_eq!(
347 fragment_def.to_string(),
348 indoc! {r#"
349 fragment myFragment on User @myDirective(first: 5) {
350 myField
351 }
352 "#}
353 );
354 }
355}