1use serde::{Deserialize, Serialize};
6
7use crate::common::{EmailAddress, GrantId, ThreadId};
8
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33pub struct Thread {
34 pub id: ThreadId,
36
37 pub grant_id: GrantId,
39
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub subject: Option<String>,
43
44 #[serde(default)]
46 pub participants: Vec<EmailAddress>,
47
48 #[serde(default)]
50 pub message_ids: Vec<String>,
51
52 #[serde(default)]
54 pub draft_ids: Vec<String>,
55
56 #[serde(default)]
58 pub folders: Vec<String>,
59
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub snippet: Option<String>,
63
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub starred: Option<bool>,
67
68 #[serde(skip_serializing_if = "Option::is_none")]
70 pub unread: Option<bool>,
71
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub latest_draft_or_message: Option<i64>,
75
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub has_attachments: Option<bool>,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
85pub struct UpdateThreadRequest {
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub starred: Option<bool>,
89
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub unread: Option<bool>,
93
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub folders: Option<Vec<String>>,
97}
98
99impl UpdateThreadRequest {
100 pub fn builder() -> UpdateThreadRequestBuilder {
102 UpdateThreadRequestBuilder::default()
103 }
104}
105
106#[derive(Debug, Clone, Default)]
108pub struct UpdateThreadRequestBuilder {
109 starred: Option<bool>,
110 unread: Option<bool>,
111 folders: Option<Vec<String>>,
112}
113
114impl UpdateThreadRequestBuilder {
115 pub fn starred(mut self, starred: bool) -> Self {
117 self.starred = Some(starred);
118 self
119 }
120
121 pub fn unread(mut self, unread: bool) -> Self {
123 self.unread = Some(unread);
124 self
125 }
126
127 pub fn folders(mut self, folders: Vec<String>) -> Self {
129 self.folders = Some(folders);
130 self
131 }
132
133 pub fn build(self) -> UpdateThreadRequest {
135 UpdateThreadRequest {
136 starred: self.starred,
137 unread: self.unread,
138 folders: self.folders,
139 }
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn test_thread_creation() {
149 let thread = Thread {
150 id: ThreadId::new("thread_123"),
151 grant_id: GrantId::new("grant_456"),
152 subject: Some("Test Subject".to_string()),
153 participants: vec![],
154 message_ids: vec!["msg_1".to_string(), "msg_2".to_string()],
155 draft_ids: vec![],
156 folders: vec!["folder_1".to_string()],
157 snippet: Some("Test snippet".to_string()),
158 starred: Some(false),
159 unread: Some(true),
160 latest_draft_or_message: Some(1234567890),
161 has_attachments: Some(false),
162 };
163
164 assert_eq!(thread.id.as_str(), "thread_123");
165 assert_eq!(thread.subject, Some("Test Subject".to_string()));
166 assert_eq!(thread.message_ids.len(), 2);
167 assert_eq!(thread.unread, Some(true));
168 }
169
170 #[test]
171 fn test_thread_serialization() {
172 let thread = Thread {
173 id: ThreadId::new("thread_123"),
174 grant_id: GrantId::new("grant_456"),
175 subject: Some("Test".to_string()),
176 participants: vec![],
177 message_ids: vec!["msg_1".to_string()],
178 draft_ids: vec![],
179 folders: vec![],
180 snippet: None,
181 starred: Some(true),
182 unread: Some(false),
183 latest_draft_or_message: None,
184 has_attachments: Some(false),
185 };
186
187 let json = serde_json::to_string(&thread).unwrap();
188 assert!(json.contains("thread_123"));
189 assert!(json.contains("Test"));
190 }
191
192 #[test]
193 fn test_thread_deserialization() {
194 let json = r#"{
195 "id": "thread_123",
196 "grant_id": "grant_456",
197 "subject": "Test Subject",
198 "participants": [],
199 "message_ids": ["msg_1", "msg_2"],
200 "draft_ids": [],
201 "folders": ["folder_1"],
202 "starred": false,
203 "unread": true,
204 "latest_draft_or_message": 1234567890
205 }"#;
206
207 let thread: Thread = serde_json::from_str(json).unwrap();
208 assert_eq!(thread.id.as_str(), "thread_123");
209 assert_eq!(thread.subject, Some("Test Subject".to_string()));
210 assert_eq!(thread.message_ids.len(), 2);
211 assert_eq!(thread.unread, Some(true));
212 }
213
214 #[test]
215 fn test_update_thread_request_builder() {
216 let update = UpdateThreadRequest::builder()
217 .starred(true)
218 .unread(false)
219 .folders(vec!["folder_1".to_string()])
220 .build();
221
222 assert_eq!(update.starred, Some(true));
223 assert_eq!(update.unread, Some(false));
224 assert_eq!(update.folders, Some(vec!["folder_1".to_string()]));
225 }
226
227 #[test]
228 fn test_update_thread_request_partial() {
229 let update = UpdateThreadRequest::builder().starred(true).build();
230
231 assert_eq!(update.starred, Some(true));
232 assert_eq!(update.unread, None);
233 assert_eq!(update.folders, None);
234 }
235
236 #[test]
237 fn test_update_thread_request_serialization() {
238 let update = UpdateThreadRequest::builder()
239 .starred(true)
240 .unread(false)
241 .build();
242
243 let json = serde_json::to_string(&update).unwrap();
244 assert!(json.contains("starred"));
245 assert!(json.contains("unread"));
246
247 let deserialized: UpdateThreadRequest = serde_json::from_str(&json).unwrap();
248 assert_eq!(deserialized, update);
249 }
250}