apollo_encoder/
union_def.rs

1use std::fmt;
2
3use crate::{Directive, StringValue};
4
5/// UnionDefinitions are an abstract type where no common fields are declared.
6///
7/// *UnionDefTypeDefinition*:
8///     Description? **union** Name Directives? UnionDefMemberTypes?
9///
10/// Detailed documentation can be found in [GraphQL spec](https://spec.graphql.org/October2021/#UnionTypeDefinition).
11///
12/// ### Example
13/// ```rust
14/// use apollo_encoder::UnionDefinition;
15///
16/// let mut union_ = UnionDefinition::new("Pet".to_string());
17/// union_.member("Cat".to_string());
18/// union_.member("Dog".to_string());
19///
20/// assert_eq!(
21///     union_.to_string(),
22/// r#"union Pet = Cat | Dog
23/// "#
24/// );
25/// ```
26#[derive(Debug, PartialEq, Clone)]
27pub struct UnionDefinition {
28    // Name must return a String.
29    name: String,
30    // Description may return a String.
31    description: Option<StringValue>,
32    // The vector of members that can be represented within this union.
33    members: Vec<String>,
34    /// Contains all directives.
35    directives: Vec<Directive>,
36    extend: bool,
37}
38
39impl UnionDefinition {
40    /// Create a new instance of a UnionDef.
41    pub fn new(name: String) -> Self {
42        Self {
43            name,
44            description: None,
45            members: Vec::new(),
46            extend: false,
47            directives: Vec::new(),
48        }
49    }
50
51    /// Set the union type as an extension
52    pub fn extend(&mut self) {
53        self.extend = true;
54    }
55
56    /// Set the UnionDefs description.
57    pub fn description(&mut self, description: String) {
58        self.description = Some(StringValue::Top {
59            source: description,
60        });
61    }
62
63    /// Add a directive
64    pub fn directive(&mut self, directive: Directive) {
65        self.directives.push(directive);
66    }
67
68    /// Set a UnionDef member.
69    pub fn member(&mut self, member: String) {
70        self.members.push(member);
71    }
72}
73
74impl fmt::Display for UnionDefinition {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        if self.extend {
77            write!(f, "extend ")?;
78        // No description when it's a extension
79        } else if let Some(description) = &self.description {
80            writeln!(f, "{description}")?;
81        }
82
83        write!(f, "union {}", self.name)?;
84
85        for directive in &self.directives {
86            write!(f, " {directive}")?;
87        }
88
89        write!(f, " =")?;
90
91        for (i, member) in self.members.iter().enumerate() {
92            match i {
93                0 => write!(f, " {member}")?,
94                _ => write!(f, " | {member}")?,
95            }
96        }
97
98        writeln!(f)
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105    use pretty_assertions::assert_eq;
106
107    #[test]
108    fn it_encodes_union_with_description() {
109        let mut union_ = UnionDefinition::new("Pet".to_string());
110        union_.description("A union of all animals in a household.".to_string());
111        union_.member("Cat".to_string());
112        union_.member("Dog".to_string());
113
114        assert_eq!(
115            union_.to_string(),
116            r#""A union of all animals in a household."
117union Pet = Cat | Dog
118"#
119        );
120    }
121
122    #[test]
123    fn it_encodes_union_extension() {
124        let mut union_ = UnionDefinition::new("Pet".to_string());
125        union_.description("A union of all animals in a household.".to_string());
126        union_.member("Cat".to_string());
127        union_.member("Dog".to_string());
128        union_.extend();
129
130        assert_eq!(
131            union_.to_string(),
132            r#"extend union Pet = Cat | Dog
133"#
134        );
135    }
136}