slack_messaging/blocks/data_visualization/charts/
data_point.rs1use crate::errors::ValidationErrors;
2use crate::validators::*;
3
4use serde::Serialize;
5use serde_json::Number;
6use slack_messaging_derive::Builder;
7
8#[derive(Debug, Clone, Serialize, PartialEq, Builder)]
48pub struct DataPoint {
49 #[builder(validate("required", "text::max_20"))]
50 pub(crate) label: Option<String>,
51
52 #[builder(validate("required"))]
53 pub(crate) value: Option<Number>,
54}
55
56impl<S, N> TryFrom<(S, N)> for DataPoint
57where
58 S: Into<String>,
59 N: Into<Number>,
60{
61 type Error = ValidationErrors;
62
63 fn try_from((label, value): (S, N)) -> Result<Self, Self::Error> {
64 DataPoint::builder()
65 .label(label)
66 .value(value)
67 .build()
68 }
69}
70
71pub fn data_points<Iter, S, N>(iter: Iter) -> Result<Vec<DataPoint>, ValidationErrors>
97where
98 Iter: IntoIterator<Item = (S, N)>,
99 S: Into<String>,
100 N: Into<Number>,
101{
102 iter.into_iter().map(DataPoint::try_from).collect()
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use crate::errors::*;
109
110 #[test]
111 fn it_implements_builder() {
112 let expected = DataPoint {
113 label: Some("Sales".into()),
114 value: Some(Number::from(150)),
115 };
116
117 let val = DataPoint::builder()
118 .set_label(Some("Sales"))
119 .set_value(Some(150))
120 .build()
121 .unwrap();
122
123 assert_eq!(val, expected);
124
125 let val = DataPoint::builder()
126 .label("Sales")
127 .value(150)
128 .build()
129 .unwrap();
130
131 assert_eq!(val, expected);
132 }
133
134 #[test]
135 fn it_implements_try_from() {
136 let expected = DataPoint {
137 label: Some("Revenue".into()),
138 value: Some(Number::from(200)),
139 };
140
141 let val = DataPoint::try_from(("Revenue", 200)).unwrap();
142
143 assert_eq!(val, expected);
144 }
145
146 #[test]
147 fn it_implements_data_points_function() {
148 let expected = vec![
149 DataPoint {
150 label: Some("Sales".into()),
151 value: Some(Number::from(150)),
152 },
153 DataPoint {
154 label: Some("Revenue".into()),
155 value: Some(Number::from(200)),
156 },
157 ];
158
159 let val = data_points(vec![("Sales", 150), ("Revenue", 200)]).unwrap();
160
161 assert_eq!(val, expected);
162 }
163
164 #[test]
165 fn it_requires_label_field() {
166 let err = DataPoint::builder().value(150).build().unwrap_err();
167 assert_eq!(err.object(), "DataPoint");
168
169 let errors = err.field("label");
170 assert!(errors.includes(ValidationErrorKind::Required));
171 }
172
173 #[test]
174 fn it_requires_label_field_less_than_20_characters_long() {
175 let err = DataPoint::builder()
176 .label("a".repeat(21))
177 .value(150)
178 .build()
179 .unwrap_err();
180 assert_eq!(err.object(), "DataPoint");
181
182 let errors = err.field("label");
183 assert!(errors.includes(ValidationErrorKind::MaxTextLength(20)));
184 }
185
186 #[test]
187 fn it_requires_value_field() {
188 let err = DataPoint::builder().label("Sales").build().unwrap_err();
189 assert_eq!(err.object(), "DataPoint");
190
191 let errors = err.field("value");
192 assert!(errors.includes(ValidationErrorKind::Required));
193 }
194}