apollo_encoder/
argument.rs

1use std::fmt;
2
3use crate::{InputValueDefinition, Value};
4
5/// The `ArgumentsDefinition` type represents an arguments definition
6///
7/// *ArgumentsDefinition*:
8///     ( InputValueDefinition* )
9///
10/// Detailed documentation can be found in [GraphQL spec](https://spec.graphql.org/October2021/#ArgumentsDefinition).
11///
12/// ### Example
13/// ```rust
14/// use apollo_encoder::{ArgumentsDefinition, InputValueDefinition, Type_};
15/// use indoc::indoc;
16///
17/// let input_value_defs = vec![
18///     InputValueDefinition::new(
19///         String::from("first"),
20///         Type_::NamedType {
21///             name: String::from("Int"),
22///         },
23///     ),
24///     InputValueDefinition::new(
25///         String::from("second"),
26///         Type_::List {
27///             ty: Box::new(Type_::NamedType {
28///                 name: String::from("Int"),
29///             }),
30///         },
31///     ),
32/// ];
33/// let arguments_def = ArgumentsDefinition::with_values(input_value_defs);
34///
35/// assert_eq!(arguments_def.to_string(), r#"(first: Int, second: [Int])"#);
36/// ```
37#[derive(Debug, Default, PartialEq, Clone)]
38pub struct ArgumentsDefinition {
39    pub(crate) input_values: Vec<InputValueDefinition>,
40}
41
42impl ArgumentsDefinition {
43    /// Create a new instance of Argument definition.
44    pub fn new() -> Self {
45        Self {
46            input_values: Vec::new(),
47        }
48    }
49
50    /// Create a new instance of ArgumentsDefinition given Input Value Definitions.
51    pub fn with_values(input_values: Vec<InputValueDefinition>) -> Self {
52        Self { input_values }
53    }
54
55    /// Add an InputValueDefinition to Arguments Definition
56    pub fn input_value(&mut self, input_value: InputValueDefinition) {
57        self.input_values.push(input_value)
58    }
59}
60
61impl fmt::Display for ArgumentsDefinition {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        write!(f, "(")?;
64        for (i, input_val_def) in self.input_values.iter().enumerate() {
65            // this branch multilines input value definitions, like this:
66            //   two(
67            //     """This is a description of the \`argument\` argument."""
68            //     argument: InputType!
69            //   ): Type
70            if input_val_def.description.is_some() {
71                if i != self.input_values.len() - 1 {
72                    write!(f, "{input_val_def},")?;
73                } else {
74                    writeln!(f, "{input_val_def}")?;
75                }
76            // with no descriptions we single line input value definitions:
77            //   two(argument: InputType!): Type
78            } else if i != self.input_values.len() - 1 {
79                write!(f, "{input_val_def}, ")?;
80            } else {
81                write!(f, "{input_val_def}")?;
82            }
83        }
84
85        if self
86            .input_values
87            .iter()
88            .any(|input| input.description.is_some())
89        {
90            write!(f, "  )")
91        } else {
92            write!(f, ")")
93        }
94    }
95}
96
97/// The `Argument` type represents an argument
98///
99/// *Argument*:
100///     Name: Value
101///
102/// Detailed documentation can be found in [GraphQL spec](https://spec.graphql.org/October2021/#sec-Language.Arguments).
103///
104/// ### Example
105/// ```rust
106/// use apollo_encoder::{Argument, Value};
107///
108/// let argument = Argument::new(String::from("argName"), Value::String("value".to_string()));
109/// assert_eq!(argument.to_string(), r#"argName: "value""#);
110/// ```
111#[derive(Debug, PartialEq, Clone)]
112pub struct Argument {
113    name: String,
114    value: Value,
115}
116
117impl Argument {
118    /// Create a new instance of Argument.
119    pub fn new(name: String, value: Value) -> Self {
120        Self { name, value }
121    }
122}
123
124impl fmt::Display for Argument {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        write!(f, "{}: {}", self.name, self.value)
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use crate::Type_;
133
134    use super::*;
135
136    #[test]
137    fn it_encodes_argument() {
138        let argument = Argument::new(String::from("argName"), Value::String("value".to_string()));
139
140        assert_eq!(argument.to_string(), r#"argName: "value""#);
141    }
142
143    #[test]
144    fn it_encodes_arguments_definitions() {
145        let input_value_defs = vec![
146            InputValueDefinition::new(
147                String::from("first"),
148                Type_::NamedType {
149                    name: String::from("Int"),
150                },
151            ),
152            InputValueDefinition::new(
153                String::from("second"),
154                Type_::List {
155                    ty: Box::new(Type_::NamedType {
156                        name: String::from("Int"),
157                    }),
158                },
159            ),
160        ];
161        let arguments_def = ArgumentsDefinition::with_values(input_value_defs);
162
163        assert_eq!(arguments_def.to_string(), r#"(first: Int, second: [Int])"#);
164    }
165}