apollo_encoder/
input_value.rs

1use std::fmt;
2
3use crate::{Directive, StringValue, Type_};
4
5/// The InputValueDefinition type represents field and directive arguments.
6///
7/// *InputValueDefinition*:
8///     Description? Name **:** Type DefaultValue? Directives?
9///
10/// Detailed documentation can be found in [GraphQL spec](https://spec.graphql.org/October2021/#sec-The-__InputValue-Type).
11///
12/// ### Example
13/// ```rust
14/// use apollo_encoder::{Type_, InputValueDefinition};
15///
16/// let ty_1 = Type_::NamedType {
17///     name: "SpaceProgram".to_string(),
18/// };
19///
20/// let ty_2 = Type_::List { ty: Box::new(ty_1) };
21/// let mut value = InputValueDefinition::new("cat".to_string(), ty_2);
22/// value.description("Very good cats".to_string());
23///
24/// assert_eq!(
25///     value.to_string(),
26///     r#"
27///     "Very good cats"
28///     cat: [SpaceProgram]"#
29/// );
30/// ```
31#[derive(Debug, PartialEq, Clone)]
32pub struct InputValueDefinition {
33    // Name must return a String.
34    name: String,
35    // Description may return a String.
36    pub(crate) description: Option<StringValue>,
37    // Type must return a __Type that represents the type this input value expects.
38    type_: Type_,
39    // Default may return a String encoding (using the GraphQL language) of
40    // the default value used by this input value in the condition a value is
41    // not provided at runtime. If this input value has no default value,
42    // returns null.
43    default_value: Option<String>,
44    /// Contains all directives for this input value definition
45    directives: Vec<Directive>,
46}
47
48impl InputValueDefinition {
49    /// Create a new instance of InputValueDefinition.
50    pub fn new(name: String, type_: Type_) -> Self {
51        Self {
52            description: None,
53            name,
54            type_,
55            default_value: None,
56            directives: Vec::new(),
57        }
58    }
59
60    /// Set the InputValueDefinition's description.
61    pub fn description(&mut self, description: String) {
62        self.description = Some(StringValue::Input {
63            source: description,
64        });
65    }
66
67    /// Set the InputValueDef's default value.
68    pub fn default_value(&mut self, default_value: String) {
69        self.default_value = Some(default_value);
70    }
71
72    /// Add a directive to InputValueDefinition.
73    pub fn directive(&mut self, directive: Directive) {
74        self.directives.push(directive)
75    }
76}
77
78impl fmt::Display for InputValueDefinition {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        match &self.description {
81            Some(description) => {
82                writeln!(f, "\n{description}")?;
83
84                write!(f, "    {}: {}", self.name, self.type_)?;
85            }
86            None => {
87                write!(f, "{}: {}", self.name, self.type_)?;
88            }
89        }
90
91        if let Some(default) = &self.default_value {
92            write!(f, " = {default}")?;
93        }
94
95        for directive in &self.directives {
96            write!(f, " {directive}")?;
97        }
98
99        Ok(())
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use crate::{Argument, Value};
106
107    use super::*;
108    use pretty_assertions::assert_eq;
109
110    #[test]
111    fn it_encodes_simple_values() {
112        let ty_1 = Type_::NamedType {
113            name: "SpaceProgram".to_string(),
114        };
115
116        let ty_2 = Type_::List { ty: Box::new(ty_1) };
117        let ty_3 = Type_::NonNull { ty: Box::new(ty_2) };
118        let value = InputValueDefinition::new("spaceCat".to_string(), ty_3);
119
120        assert_eq!(value.to_string(), r#"spaceCat: [SpaceProgram]!"#);
121    }
122
123    #[test]
124    fn it_encodes_input_values_with_default() {
125        let ty_1 = Type_::NamedType {
126            name: "Breed".to_string(),
127        };
128
129        let ty_2 = Type_::NonNull { ty: Box::new(ty_1) };
130        let mut value = InputValueDefinition::new("spaceCat".to_string(), ty_2);
131        value.default_value("\"Norwegian Forest\"".to_string());
132
133        assert_eq!(
134            value.to_string(),
135            r#"spaceCat: Breed! = "Norwegian Forest""#
136        );
137    }
138
139    #[test]
140    fn it_encodes_value_with_directive() {
141        let ty_1 = Type_::NamedType {
142            name: "SpaceProgram".to_string(),
143        };
144
145        let ty_2 = Type_::List { ty: Box::new(ty_1) };
146        let mut value = InputValueDefinition::new("cat".to_string(), ty_2);
147        let mut directive = Directive::new(String::from("testDirective"));
148        directive.arg(Argument::new(String::from("first"), Value::Int(1)));
149        value.description("Very good cats".to_string());
150        value.directive(directive);
151
152        assert_eq!(
153            value.to_string(),
154            r#"
155    "Very good cats"
156    cat: [SpaceProgram] @testDirective(first: 1)"#
157        );
158    }
159
160    #[test]
161    fn it_encodes_valueuments_with_description() {
162        let ty_1 = Type_::NamedType {
163            name: "SpaceProgram".to_string(),
164        };
165
166        let ty_2 = Type_::NonNull { ty: Box::new(ty_1) };
167        let ty_3 = Type_::List { ty: Box::new(ty_2) };
168        let ty_4 = Type_::NonNull { ty: Box::new(ty_3) };
169        let mut value = InputValueDefinition::new("spaceCat".to_string(), ty_4);
170        value.description("Very good space cats".to_string());
171
172        assert_eq!(
173            value.to_string(),
174            r#"
175    "Very good space cats"
176    spaceCat: [SpaceProgram!]!"#
177        );
178    }
179}