1use serde::{Deserialize, Serialize};
7
8use crate::common::{FolderId, GrantId};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33pub struct Folder {
34 pub id: FolderId,
36
37 pub grant_id: GrantId,
39
40 pub name: String,
42
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub parent_id: Option<String>,
46
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub child_count: Option<i32>,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub unread_count: Option<i32>,
54
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub total_count: Option<i32>,
58
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub system_folder: Option<bool>,
62
63 #[serde(skip_serializing_if = "Option::is_none")]
65 pub background_color: Option<String>,
66
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub text_color: Option<String>,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74pub struct CreateFolderRequest {
75 pub name: String,
77
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub parent_id: Option<String>,
81
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub background_color: Option<String>,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub text_color: Option<String>,
89}
90
91impl CreateFolderRequest {
92 pub fn builder(name: impl Into<String>) -> CreateFolderRequestBuilder {
94 CreateFolderRequestBuilder::new(name)
95 }
96}
97
98#[derive(Debug, Clone)]
100pub struct CreateFolderRequestBuilder {
101 name: String,
102 parent_id: Option<String>,
103 background_color: Option<String>,
104 text_color: Option<String>,
105}
106
107impl CreateFolderRequestBuilder {
108 pub fn new(name: impl Into<String>) -> Self {
110 Self {
111 name: name.into(),
112 parent_id: None,
113 background_color: None,
114 text_color: None,
115 }
116 }
117
118 pub fn parent_id(mut self, parent_id: impl Into<String>) -> Self {
120 self.parent_id = Some(parent_id.into());
121 self
122 }
123
124 pub fn background_color(mut self, color: impl Into<String>) -> Self {
126 self.background_color = Some(color.into());
127 self
128 }
129
130 pub fn text_color(mut self, color: impl Into<String>) -> Self {
132 self.text_color = Some(color.into());
133 self
134 }
135
136 pub fn build(self) -> CreateFolderRequest {
138 CreateFolderRequest {
139 name: self.name,
140 parent_id: self.parent_id,
141 background_color: self.background_color,
142 text_color: self.text_color,
143 }
144 }
145}
146
147#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
149pub struct UpdateFolderRequest {
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub name: Option<String>,
153
154 #[serde(skip_serializing_if = "Option::is_none")]
156 pub parent_id: Option<String>,
157
158 #[serde(skip_serializing_if = "Option::is_none")]
160 pub background_color: Option<String>,
161
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub text_color: Option<String>,
165}
166
167impl UpdateFolderRequest {
168 pub fn builder() -> UpdateFolderRequestBuilder {
170 UpdateFolderRequestBuilder::default()
171 }
172}
173
174#[derive(Debug, Clone, Default)]
176pub struct UpdateFolderRequestBuilder {
177 name: Option<String>,
178 parent_id: Option<String>,
179 background_color: Option<String>,
180 text_color: Option<String>,
181}
182
183impl UpdateFolderRequestBuilder {
184 pub fn name(mut self, name: impl Into<String>) -> Self {
186 self.name = Some(name.into());
187 self
188 }
189
190 pub fn parent_id(mut self, parent_id: impl Into<String>) -> Self {
192 self.parent_id = Some(parent_id.into());
193 self
194 }
195
196 pub fn background_color(mut self, color: impl Into<String>) -> Self {
198 self.background_color = Some(color.into());
199 self
200 }
201
202 pub fn text_color(mut self, color: impl Into<String>) -> Self {
204 self.text_color = Some(color.into());
205 self
206 }
207
208 pub fn build(self) -> UpdateFolderRequest {
210 UpdateFolderRequest {
211 name: self.name,
212 parent_id: self.parent_id,
213 background_color: self.background_color,
214 text_color: self.text_color,
215 }
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 #[test]
224 fn test_folder_creation() {
225 let folder = Folder {
226 id: FolderId::new("folder_123"),
227 grant_id: GrantId::new("grant_456"),
228 name: "Important".to_string(),
229 parent_id: None,
230 child_count: Some(0),
231 unread_count: Some(5),
232 total_count: Some(42),
233 system_folder: Some(false),
234 background_color: None,
235 text_color: None,
236 };
237
238 assert_eq!(folder.id.as_str(), "folder_123");
239 assert_eq!(folder.name, "Important");
240 assert_eq!(folder.unread_count, Some(5));
241 }
242
243 #[test]
244 fn test_folder_serialization() {
245 let folder = Folder {
246 id: FolderId::new("folder_123"),
247 grant_id: GrantId::new("grant_456"),
248 name: "Work".to_string(),
249 parent_id: None,
250 child_count: None,
251 unread_count: Some(10),
252 total_count: Some(100),
253 system_folder: Some(false),
254 background_color: Some("#ff0000".to_string()),
255 text_color: Some("#ffffff".to_string()),
256 };
257
258 let json = serde_json::to_string(&folder).unwrap();
259 assert!(json.contains("folder_123"));
260 assert!(json.contains("Work"));
261 }
262
263 #[test]
264 fn test_folder_deserialization() {
265 let json = r#"{
266 "id": "folder_123",
267 "grant_id": "grant_456",
268 "name": "Archive",
269 "unread_count": 0,
270 "total_count": 500,
271 "system_folder": false
272 }"#;
273
274 let folder: Folder = serde_json::from_str(json).unwrap();
275 assert_eq!(folder.id.as_str(), "folder_123");
276 assert_eq!(folder.name, "Archive");
277 assert_eq!(folder.unread_count, Some(0));
278 }
279
280 #[test]
281 fn test_create_folder_request_builder() {
282 let request = CreateFolderRequest::builder("Projects")
283 .parent_id("folder_parent")
284 .background_color("#ff0000")
285 .text_color("#ffffff")
286 .build();
287
288 assert_eq!(request.name, "Projects");
289 assert_eq!(request.parent_id, Some("folder_parent".to_string()));
290 assert_eq!(request.background_color, Some("#ff0000".to_string()));
291 assert_eq!(request.text_color, Some("#ffffff".to_string()));
292 }
293
294 #[test]
295 fn test_create_folder_request_minimal() {
296 let request = CreateFolderRequest::builder("Simple Folder").build();
297
298 assert_eq!(request.name, "Simple Folder");
299 assert_eq!(request.parent_id, None);
300 assert_eq!(request.background_color, None);
301 }
302
303 #[test]
304 fn test_update_folder_request_builder() {
305 let update = UpdateFolderRequest::builder()
306 .name("Renamed Folder")
307 .background_color("#00ff00")
308 .build();
309
310 assert_eq!(update.name, Some("Renamed Folder".to_string()));
311 assert_eq!(update.background_color, Some("#00ff00".to_string()));
312 assert_eq!(update.parent_id, None);
313 }
314
315 #[test]
316 fn test_update_folder_request_partial() {
317 let update = UpdateFolderRequest::builder().name("New Name").build();
318
319 assert_eq!(update.name, Some("New Name".to_string()));
320 assert_eq!(update.parent_id, None);
321 assert_eq!(update.background_color, None);
322 }
323}