singularity_cli/models/
tag.rs1use serde::{Deserialize, Serialize};
2use tabled::Tabled;
3
4fn display_opt(o: &Option<String>) -> String {
5 o.as_deref().unwrap_or("-").to_string()
6}
7
8#[derive(Debug, Deserialize)]
9pub struct TagListResponse {
10 pub tags: Vec<Tag>,
11}
12
13#[derive(Debug, Deserialize, Tabled)]
14#[tabled(rename_all = "UPPERCASE")]
15pub struct Tag {
16 pub id: String,
17 pub title: String,
18 #[tabled(display_with = "display_opt")]
19 pub parent: Option<String>,
20 #[tabled(skip)]
21 pub order: Option<f64>,
22 #[tabled(skip)]
23 #[serde(rename = "modificatedDate")]
24 #[allow(dead_code)]
25 pub modificated_date: Option<String>,
26}
27
28impl Tag {
29 pub fn display_detail(&self) {
30 println!("ID: {}", self.id);
31 println!("Title: {}", self.title);
32 if let Some(ref v) = self.parent {
33 println!("Parent: {}", v);
34 }
35 if let Some(v) = self.order {
36 println!("Order: {}", v);
37 }
38 }
39}
40
41#[derive(Debug, Serialize)]
42pub struct TagCreate {
43 pub title: String,
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub parent: Option<String>,
46 #[serde(skip_serializing_if = "Option::is_none")]
47 pub order: Option<f64>,
48}
49
50#[derive(Debug, Serialize, Default)]
51pub struct TagUpdate {
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub title: Option<String>,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub parent: Option<String>,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub order: Option<f64>,
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn deserialize_tag_list() {
66 let json = r#"{"tags": [{"id": "tag-1", "title": "urgent", "order": 1.0}]}"#;
67 let resp: TagListResponse = serde_json::from_str(json).unwrap();
68 assert_eq!(resp.tags.len(), 1);
69 assert_eq!(resp.tags[0].id, "tag-1");
70 assert_eq!(resp.tags[0].order, Some(1.0));
71 }
72
73 #[test]
74 fn deserialize_tag_minimal() {
75 let json = r#"{"id": "tag-2", "title": "low"}"#;
76 let t: Tag = serde_json::from_str(json).unwrap();
77 assert_eq!(t.id, "tag-2");
78 assert!(t.parent.is_none());
79 assert!(t.order.is_none());
80 }
81
82 #[test]
83 fn serialize_create_skips_none() {
84 let data = TagCreate {
85 title: "bug".to_string(),
86 parent: None,
87 order: None,
88 };
89 let json = serde_json::to_value(&data).unwrap();
90 assert_eq!(json, serde_json::json!({"title": "bug"}));
91 }
92
93 #[test]
94 fn serialize_update_partial() {
95 let data = TagUpdate {
96 title: Some("renamed".to_string()),
97 ..Default::default()
98 };
99 let json = serde_json::to_value(&data).unwrap();
100 assert_eq!(json, serde_json::json!({"title": "renamed"}));
101 }
102}