use serde::{Deserialize, Serialize};
use crate::common::{FolderId, GrantId};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Folder {
pub id: FolderId,
pub grant_id: GrantId,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub child_count: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub unread_count: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_count: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system_folder: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_color: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CreateFolderRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_color: Option<String>,
}
impl CreateFolderRequest {
pub fn builder(name: impl Into<String>) -> CreateFolderRequestBuilder {
CreateFolderRequestBuilder::new(name)
}
}
#[derive(Debug, Clone)]
pub struct CreateFolderRequestBuilder {
name: String,
parent_id: Option<String>,
background_color: Option<String>,
text_color: Option<String>,
}
impl CreateFolderRequestBuilder {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
parent_id: None,
background_color: None,
text_color: None,
}
}
pub fn parent_id(mut self, parent_id: impl Into<String>) -> Self {
self.parent_id = Some(parent_id.into());
self
}
pub fn background_color(mut self, color: impl Into<String>) -> Self {
self.background_color = Some(color.into());
self
}
pub fn text_color(mut self, color: impl Into<String>) -> Self {
self.text_color = Some(color.into());
self
}
pub fn build(self) -> CreateFolderRequest {
CreateFolderRequest {
name: self.name,
parent_id: self.parent_id,
background_color: self.background_color,
text_color: self.text_color,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct UpdateFolderRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_color: Option<String>,
}
impl UpdateFolderRequest {
pub fn builder() -> UpdateFolderRequestBuilder {
UpdateFolderRequestBuilder::default()
}
}
#[derive(Debug, Clone, Default)]
pub struct UpdateFolderRequestBuilder {
name: Option<String>,
parent_id: Option<String>,
background_color: Option<String>,
text_color: Option<String>,
}
impl UpdateFolderRequestBuilder {
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn parent_id(mut self, parent_id: impl Into<String>) -> Self {
self.parent_id = Some(parent_id.into());
self
}
pub fn background_color(mut self, color: impl Into<String>) -> Self {
self.background_color = Some(color.into());
self
}
pub fn text_color(mut self, color: impl Into<String>) -> Self {
self.text_color = Some(color.into());
self
}
pub fn build(self) -> UpdateFolderRequest {
UpdateFolderRequest {
name: self.name,
parent_id: self.parent_id,
background_color: self.background_color,
text_color: self.text_color,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_folder_creation() {
let folder = Folder {
id: FolderId::new("folder_123"),
grant_id: GrantId::new("grant_456"),
name: "Important".to_string(),
parent_id: None,
child_count: Some(0),
unread_count: Some(5),
total_count: Some(42),
system_folder: Some(false),
background_color: None,
text_color: None,
};
assert_eq!(folder.id.as_str(), "folder_123");
assert_eq!(folder.name, "Important");
assert_eq!(folder.unread_count, Some(5));
}
#[test]
fn test_folder_serialization() {
let folder = Folder {
id: FolderId::new("folder_123"),
grant_id: GrantId::new("grant_456"),
name: "Work".to_string(),
parent_id: None,
child_count: None,
unread_count: Some(10),
total_count: Some(100),
system_folder: Some(false),
background_color: Some("#ff0000".to_string()),
text_color: Some("#ffffff".to_string()),
};
let json = serde_json::to_string(&folder).unwrap();
assert!(json.contains("folder_123"));
assert!(json.contains("Work"));
}
#[test]
fn test_folder_deserialization() {
let json = r#"{
"id": "folder_123",
"grant_id": "grant_456",
"name": "Archive",
"unread_count": 0,
"total_count": 500,
"system_folder": false
}"#;
let folder: Folder = serde_json::from_str(json).unwrap();
assert_eq!(folder.id.as_str(), "folder_123");
assert_eq!(folder.name, "Archive");
assert_eq!(folder.unread_count, Some(0));
}
#[test]
fn test_create_folder_request_builder() {
let request = CreateFolderRequest::builder("Projects")
.parent_id("folder_parent")
.background_color("#ff0000")
.text_color("#ffffff")
.build();
assert_eq!(request.name, "Projects");
assert_eq!(request.parent_id, Some("folder_parent".to_string()));
assert_eq!(request.background_color, Some("#ff0000".to_string()));
assert_eq!(request.text_color, Some("#ffffff".to_string()));
}
#[test]
fn test_create_folder_request_minimal() {
let request = CreateFolderRequest::builder("Simple Folder").build();
assert_eq!(request.name, "Simple Folder");
assert_eq!(request.parent_id, None);
assert_eq!(request.background_color, None);
}
#[test]
fn test_update_folder_request_builder() {
let update = UpdateFolderRequest::builder()
.name("Renamed Folder")
.background_color("#00ff00")
.build();
assert_eq!(update.name, Some("Renamed Folder".to_string()));
assert_eq!(update.background_color, Some("#00ff00".to_string()));
assert_eq!(update.parent_id, None);
}
#[test]
fn test_update_folder_request_partial() {
let update = UpdateFolderRequest::builder().name("New Name").build();
assert_eq!(update.name, Some("New Name".to_string()));
assert_eq!(update.parent_id, None);
assert_eq!(update.background_color, None);
}
}