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}