apollo_encoder/
enum_def.rs

1use std::fmt;
2
3use crate::{Directive, EnumValue, StringValue};
4
5/// Enums are special scalars that can only have a defined set of values.
6///
7/// *EnumTypeDefinition*:
8///     Description? **enum** Name Directives? EnumValuesDefinition?
9///
10/// Detailed documentation can be found in [GraphQL spec](https://spec.graphql.org/October2021/#sec-Enums).
11///
12/// ### Example
13/// ```rust
14/// use apollo_encoder::{Argument, Directive, EnumValue, EnumDefinition, Value};
15///
16/// let mut enum_ty_1 = EnumValue::new("CAT_TREE".to_string());
17/// enum_ty_1.description("Top bunk of a cat tree.".to_string());
18/// let enum_ty_2 = EnumValue::new("BED".to_string());
19/// let mut deprecated_directive = Directive::new(String::from("deprecated"));
20/// deprecated_directive.arg(Argument::new(String::from("reason"), Value::String(String::from("Box was recycled."))));
21/// let mut enum_ty_3 = EnumValue::new("CARDBOARD_BOX".to_string());
22/// enum_ty_3.directive(deprecated_directive);
23///
24/// let mut enum_ = EnumDefinition::new("NapSpots".to_string());
25/// enum_.description("Favourite cat nap spots.".to_string());
26/// enum_.value(enum_ty_1);
27/// enum_.value(enum_ty_2);
28/// enum_.value(enum_ty_3);
29///
30/// assert_eq!(
31///     enum_.to_string(),
32///     r#""Favourite cat nap spots."
33/// enum NapSpots {
34///   "Top bunk of a cat tree."
35///   CAT_TREE
36///   BED
37///   CARDBOARD_BOX @deprecated(reason: "Box was recycled.")
38/// }
39/// "#
40/// );
41/// ```
42#[derive(Debug, PartialEq, Clone)]
43pub struct EnumDefinition {
44    // Name must return a String.
45    name: String,
46    // Description may return a String or null.
47    description: Option<StringValue>,
48    // A vector of EnumValue. There must be at least one and they must have
49    // unique names.
50    values: Vec<EnumValue>,
51    /// The vector of directives
52    directives: Vec<Directive>,
53    extend: bool,
54}
55
56impl EnumDefinition {
57    /// Create a new instance of Enum Definition.
58    pub fn new(name: String) -> Self {
59        Self {
60            name,
61            description: None,
62            values: Vec::new(),
63            directives: Vec::new(),
64            extend: false,
65        }
66    }
67
68    /// Set the enum type as an extension
69    pub fn extend(&mut self) {
70        self.extend = true;
71    }
72
73    /// Set the Enum Definition's description.
74    pub fn description(&mut self, description: String) {
75        self.description = Some(StringValue::Top {
76            source: description,
77        });
78    }
79
80    /// Set the Enum Definitions's values.
81    pub fn value(&mut self, value: EnumValue) {
82        self.values.push(value)
83    }
84
85    /// Add a directive.
86    pub fn directive(&mut self, directive: Directive) {
87        self.directives.push(directive)
88    }
89}
90
91impl fmt::Display for EnumDefinition {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        if self.extend {
94            write!(f, "extend ")?;
95        // No description when it's a extension
96        } else if let Some(description) = &self.description {
97            writeln!(f, "{description}")?;
98        }
99
100        write!(f, "enum {}", self.name)?;
101        for directive in &self.directives {
102            write!(f, " {directive}")?;
103        }
104
105        write!(f, " {{")?;
106        for value in &self.values {
107            write!(f, "\n{value}")?;
108        }
109        writeln!(f, "\n}}")
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use crate::{Argument, Value};
116
117    use super::*;
118    use pretty_assertions::assert_eq;
119
120    #[test]
121    fn it_encodes_a_simple_enum() {
122        let enum_ty_1 = EnumValue::new("CAT_TREE".to_string());
123        let enum_ty_2 = EnumValue::new("BED".to_string());
124        let enum_ty_3 = EnumValue::new("CARDBOARD_BOX".to_string());
125
126        let mut enum_ = EnumDefinition::new("NapSpots".to_string());
127        enum_.value(enum_ty_1);
128        enum_.value(enum_ty_2);
129        enum_.value(enum_ty_3);
130
131        assert_eq!(
132            enum_.to_string(),
133            r#"enum NapSpots {
134  CAT_TREE
135  BED
136  CARDBOARD_BOX
137}
138"#
139        );
140    }
141    #[test]
142    fn it_encodes_enum_with_descriptions() {
143        let mut enum_ty_1 = EnumValue::new("CAT_TREE".to_string());
144        enum_ty_1.description("Top bunk of a cat tree.".to_string());
145        let enum_ty_2 = EnumValue::new("BED".to_string());
146        let mut enum_ty_3 = EnumValue::new("CARDBOARD_BOX".to_string());
147        let mut deprecated_directive = Directive::new(String::from("deprecated"));
148        deprecated_directive.arg(Argument::new(
149            String::from("reason"),
150            Value::String(String::from("Box was recycled.")),
151        ));
152        enum_ty_3.directive(deprecated_directive);
153        let mut directive = Directive::new(String::from("testDirective"));
154        directive.arg(Argument::new(
155            String::from("first"),
156            Value::String("one".to_string()),
157        ));
158
159        let mut enum_ = EnumDefinition::new("NapSpots".to_string());
160        enum_.description("Favourite cat nap spots.".to_string());
161        enum_.value(enum_ty_1);
162        enum_.value(enum_ty_2);
163        enum_.value(enum_ty_3);
164        enum_.directive(directive);
165
166        assert_eq!(
167            enum_.to_string(),
168            r#""Favourite cat nap spots."
169enum NapSpots @testDirective(first: "one") {
170  "Top bunk of a cat tree."
171  CAT_TREE
172  BED
173  CARDBOARD_BOX @deprecated(reason: "Box was recycled.")
174}
175"#
176        );
177    }
178
179    #[test]
180    fn it_encodes_enum_extension() {
181        let mut enum_ty_1 = EnumValue::new("CAT_TREE".to_string());
182        enum_ty_1.description("Top bunk of a cat tree.".to_string());
183        let enum_ty_2 = EnumValue::new("BED".to_string());
184        let mut enum_ty_3 = EnumValue::new("CARDBOARD_BOX".to_string());
185        let mut deprecated_directive = Directive::new(String::from("deprecated"));
186        deprecated_directive.arg(Argument::new(
187            String::from("reason"),
188            Value::String(String::from("Box was recycled.")),
189        ));
190        enum_ty_3.directive(deprecated_directive);
191        let mut directive = Directive::new(String::from("testDirective"));
192        directive.arg(Argument::new(
193            String::from("first"),
194            Value::String("one".to_string()),
195        ));
196
197        let mut enum_ = EnumDefinition::new("NapSpots".to_string());
198        enum_.description("Favourite cat nap spots.".to_string());
199        enum_.value(enum_ty_1);
200        enum_.value(enum_ty_2);
201        enum_.value(enum_ty_3);
202        enum_.directive(directive);
203        enum_.extend();
204
205        assert_eq!(
206            enum_.to_string(),
207            r#"extend enum NapSpots @testDirective(first: "one") {
208  "Top bunk of a cat tree."
209  CAT_TREE
210  BED
211  CARDBOARD_BOX @deprecated(reason: "Box was recycled.")
212}
213"#
214        );
215    }
216}