apollo_encoder/
selection_set.rs1use std::fmt::{self, Write as _};
2
3use crate::{Field, FragmentSpread, InlineFragment};
4
5#[derive(Debug, PartialEq, Clone, Default)]
38pub struct SelectionSet {
39 selections: Vec<Selection>,
40}
41
42impl SelectionSet {
43 pub fn new() -> Self {
45 Self::default()
46 }
47
48 pub fn with_selections(selections: Vec<Selection>) -> Self {
50 Self { selections }
51 }
52
53 pub fn selection(&mut self, selection: Selection) {
55 self.selections.push(selection);
56 }
57
58 pub(crate) fn format_with_indent(&self, mut indent_level: usize) -> String {
61 let mut text = String::from("{\n");
62 indent_level += 1;
63 let indent = " ".repeat(indent_level);
64 for sel in &self.selections {
65 let _ = writeln!(text, "{}{}", indent, sel.format_with_indent(indent_level));
66 }
67 if indent_level <= 1 {
68 text.push_str("}\n");
69 } else {
70 let _ = write!(text, "{}}}", " ".repeat(indent_level - 1));
71 }
72
73 text
74 }
75}
76
77impl fmt::Display for SelectionSet {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 let indent_level = 1;
82 writeln!(f, "{{")?;
83 let indent = " ".repeat(indent_level);
84 for sel in &self.selections {
85 writeln!(f, "{}{}", indent, sel.format_with_indent(indent_level))?;
86 }
87 writeln!(f, "}}")?;
88
89 Ok(())
90 }
91}
92
93#[derive(Debug, Clone, PartialEq)]
99pub enum Selection {
100 Field(Field),
102 FragmentSpread(FragmentSpread),
104 InlineFragment(InlineFragment),
106}
107
108impl Selection {
109 pub(crate) fn format_with_indent(&self, indent_level: usize) -> String {
110 match self {
111 Selection::Field(field) => field.format_with_indent(indent_level),
112 Selection::FragmentSpread(frag_spread) => frag_spread.to_string(),
113 Selection::InlineFragment(inline_frag) => inline_frag.format_with_indent(indent_level),
114 }
115 }
116}
117
118impl fmt::Display for Selection {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 let indent_level = 0;
121 match self {
122 Selection::Field(field) => write!(f, "{}", field.format_with_indent(indent_level)),
123 Selection::FragmentSpread(fragment_spread) => write!(f, "{fragment_spread}"),
124 Selection::InlineFragment(inline_fragment) => {
125 write!(f, "{}", inline_fragment.format_with_indent(indent_level))
126 }
127 }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use indoc::indoc;
134
135 use super::*;
136
137 #[test]
138 fn it_encodes_selection_set() {
139 let mut aliased_field = Field::new(String::from("myField"));
140 aliased_field.alias(Some(String::from("myAlias")));
141 let selections = vec![
142 Selection::Field(aliased_field),
143 Selection::FragmentSpread(FragmentSpread::new(String::from("myFragment"))),
144 ];
145 let mut selection_set = SelectionSet::new();
146 selections
147 .into_iter()
148 .for_each(|s| selection_set.selection(s));
149
150 assert_eq!(
151 selection_set.to_string(),
152 indoc! {r#"
153 {
154 myAlias: myField
155 ...myFragment
156 }
157 "#}
158 )
159 }
160
161 #[test]
162 fn it_encodes_deeper_selection_set() {
163 let fourth_field = Field::new("fourth".to_string());
164 let mut third_field = Field::new("third".to_string());
165 third_field.selection_set(Some(SelectionSet::with_selections(vec![Selection::Field(
166 fourth_field,
167 )])));
168 let mut second_field = Field::new("second".to_string());
169 second_field.selection_set(Some(SelectionSet::with_selections(vec![Selection::Field(
170 third_field,
171 )])));
172
173 let mut first_field = Field::new("first".to_string());
174 first_field.selection_set(Some(SelectionSet::with_selections(vec![Selection::Field(
175 second_field,
176 )])));
177
178 let selections = vec![
179 Selection::Field(first_field),
180 Selection::FragmentSpread(FragmentSpread::new(String::from("myFragment"))),
181 ];
182 let mut selection_set = SelectionSet::new();
183
184 selections
185 .into_iter()
186 .for_each(|s| selection_set.selection(s));
187
188 assert_eq!(
189 selection_set.to_string(),
190 indoc! {r#"
191 {
192 first {
193 second {
194 third {
195 fourth
196 }
197 }
198 }
199 ...myFragment
200 }
201 "#}
202 )
203 }
204}