slack_messaging/blocks/data_table/row.rs
1use super::DataTableCell;
2
3use crate::validators::*;
4
5use serde::Serialize;
6use slack_messaging_derive::Builder;
7
8/// Single table row representation being set to the rows field in [`DataTable`](crate::blocks::DataTable)
9/// object.
10///
11/// Table rows contain an array of table cells, each represented by
12/// [`DataTableCell`] enum.
13///
14/// # Fields and Validations
15///
16/// | Field | Type | Required | Validation |
17/// |-------|------|----------|------------|
18/// | cells | Vec<[DataTableCell]> | Yes | Maximum of 20 items. |
19///
20/// # Example
21///
22/// ```
23/// use slack_messaging::blocks::RichText;
24/// use slack_messaging::blocks::rich_text::RichTextSection;
25/// use slack_messaging::blocks::rich_text::types::{RichTextElementText, RichTextStyle};
26/// use slack_messaging::blocks::data_table::DataTableRow;
27/// # use std::error::Error;
28///
29/// # fn try_main() -> Result<(), Box<dyn Error>> {
30/// let row = DataTableRow::builder()
31/// .cell("Data Refinement Department")
32/// .cell("MDR")
33/// .cell(
34/// RichText::builder()
35/// .element(
36/// RichTextSection::builder()
37/// .element(
38/// RichTextElementText::builder()
39/// .text("Blue")
40/// .style(
41/// RichTextStyle::builder()
42/// .bold(true)
43/// .build()?
44/// )
45/// .build()?
46/// )
47/// .build()?
48/// )
49/// .build()?
50/// )
51/// .build()?;
52///
53/// let expected = serde_json::json!([
54/// {
55/// "type": "raw_text",
56/// "text": "Data Refinement Department"
57/// },
58/// {
59/// "type": "raw_text",
60/// "text": "MDR"
61/// },
62/// {
63/// "type": "rich_text",
64/// "elements": [
65/// {
66/// "type": "rich_text_section",
67/// "elements": [
68/// {
69/// "type": "text",
70/// "text": "Blue",
71/// "style": {
72/// "bold": true
73/// }
74/// }
75/// ]
76/// }
77/// ]
78/// }
79/// ]);
80///
81/// let json = serde_json::to_value(row).unwrap();
82///
83/// assert_eq!(json, expected);
84/// # Ok(())
85/// # }
86/// # fn main() {
87/// # try_main().unwrap()
88/// # }
89/// ```
90#[derive(Debug, Clone, Serialize, PartialEq, Builder)]
91#[serde(transparent)]
92pub struct DataTableRow {
93 #[builder(push_item = "cell", validate("required", "list::max_item_20"))]
94 pub(crate) cells: Option<Vec<DataTableCell>>,
95}
96
97impl<Cell: Into<DataTableCell>> FromIterator<Cell> for DataTableRow {
98 fn from_iter<T: IntoIterator<Item = Cell>>(iter: T) -> Self {
99 Self {
100 cells: Some(iter.into_iter().map(|c| c.into()).collect()),
101 }
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use crate::blocks::test_helpers::*;
109 use crate::blocks::data_table::RawNumber;
110 use crate::errors::*;
111
112 #[test]
113 fn it_implements_builder() {
114 let expected = DataTableRow {
115 cells: Some(vec![
116 DataTableCell::RawText("foo".into()),
117 DataTableCell::RawNumber((10, "foobar").into()),
118 DataTableCell::RichText(rich_text()),
119 ]),
120 };
121
122 let val = DataTableRow::builder()
123 .set_cells(Some(vec![
124 DataTableCell::RawText("foo".into()),
125 DataTableCell::RawNumber((10, "foobar").into()),
126 DataTableCell::RichText(rich_text()),
127 ]))
128 .build()
129 .unwrap();
130
131 assert_eq!(val, expected);
132
133 let val = DataTableRow::builder()
134 .cells(vec![
135 DataTableCell::RawText("foo".into()),
136 DataTableCell::RawNumber((10, "foobar").into()),
137 DataTableCell::RichText(rich_text()),
138 ])
139 .build()
140 .unwrap();
141
142 assert_eq!(val, expected);
143 }
144
145 #[test]
146 fn it_implements_push_item_method() {
147 let expected = DataTableRow {
148 cells: Some(vec![
149 DataTableCell::RawText("foo".into()),
150 DataTableCell::RawNumber((10, "foobar").into()),
151 DataTableCell::RichText(rich_text()),
152 ]),
153 };
154
155 let val = DataTableRow::builder()
156 .cell("foo")
157 .cell(RawNumber::new(10, "foobar"))
158 .cell(rich_text())
159 .build()
160 .unwrap();
161
162 assert_eq!(val, expected);
163 }
164
165 #[test]
166 fn it_requires_cells_field() {
167 let err = DataTableRow::builder().build().unwrap_err();
168 assert_eq!(err.object(), "DataTableRow");
169
170 let errors = err.field("cells");
171 assert!(errors.includes(ValidationErrorKind::Required));
172 }
173
174 #[test]
175 fn it_requires_cells_field_to_have_max_20_items() {
176 let cells: Vec<DataTableCell> = (0..21).map(|_| "foo".into()).collect();
177 let err = DataTableRow::builder().cells(cells).build().unwrap_err();
178 assert_eq!(err.object(), "DataTableRow");
179
180 let errors = err.field("cells");
181 assert!(errors.includes(ValidationErrorKind::MaxArraySize(20)));
182 }
183}