singularity_cli/models/
task_group.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)]
9#[serde(rename_all = "camelCase")]
10pub struct TaskGroupListResponse {
11 pub task_groups: Vec<TaskGroup>,
12}
13
14#[derive(Debug, Deserialize, Tabled)]
15#[tabled(rename_all = "UPPERCASE")]
16pub struct TaskGroup {
17 pub id: String,
18 pub title: String,
19 #[tabled(display_with = "display_opt")]
20 pub parent: Option<String>,
21 #[tabled(skip)]
22 #[serde(rename = "parentOrder")]
23 pub parent_order: Option<f64>,
24 #[tabled(skip)]
25 pub fake: Option<bool>,
26 #[tabled(skip)]
27 #[serde(rename = "modificatedDate")]
28 #[allow(dead_code)]
29 pub modificated_date: Option<String>,
30}
31
32impl TaskGroup {
33 pub fn display_detail(&self) {
34 println!("ID: {}", self.id);
35 println!("Title: {}", self.title);
36 if let Some(ref v) = self.parent {
37 println!("Parent: {}", v);
38 }
39 if let Some(v) = self.parent_order {
40 println!("Order: {}", v);
41 }
42 if let Some(v) = self.fake {
43 println!("Fake: {}", v);
44 }
45 }
46}
47
48#[derive(Debug, Serialize)]
49pub struct TaskGroupCreate {
50 pub title: String,
51 pub parent: String,
52 #[serde(skip_serializing_if = "Option::is_none", rename = "parentOrder")]
53 pub parent_order: Option<f64>,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub fake: Option<bool>,
56}
57
58#[derive(Debug, Serialize, Default)]
59pub struct TaskGroupUpdate {
60 #[serde(skip_serializing_if = "Option::is_none")]
61 pub title: Option<String>,
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub parent: Option<String>,
64 #[serde(skip_serializing_if = "Option::is_none", rename = "parentOrder")]
65 pub parent_order: Option<f64>,
66 #[serde(skip_serializing_if = "Option::is_none")]
67 pub fake: Option<bool>,
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn deserialize_task_group_list() {
76 let json = r#"{"taskGroups": [{"id": "Q-1", "title": "Group 1", "parent": "P-1", "parentOrder": 2.0}]}"#;
77 let resp: TaskGroupListResponse = serde_json::from_str(json).unwrap();
78 assert_eq!(resp.task_groups.len(), 1);
79 assert_eq!(resp.task_groups[0].id, "Q-1");
80 assert_eq!(resp.task_groups[0].parent.as_deref(), Some("P-1"));
81 assert_eq!(resp.task_groups[0].parent_order, Some(2.0));
82 }
83
84 #[test]
85 fn deserialize_task_group_minimal() {
86 let json = r#"{"id": "Q-2", "title": "Bare"}"#;
87 let g: TaskGroup = serde_json::from_str(json).unwrap();
88 assert_eq!(g.id, "Q-2");
89 assert!(g.parent.is_none());
90 assert!(g.fake.is_none());
91 }
92
93 #[test]
94 fn serialize_create_camel_case() {
95 let data = TaskGroupCreate {
96 title: "G".to_string(),
97 parent: "P-1".to_string(),
98 parent_order: Some(3.0),
99 fake: None,
100 };
101 let json = serde_json::to_value(&data).unwrap();
102 assert_eq!(json["parentOrder"], 3.0);
103 assert!(json.get("parent_order").is_none());
104 assert!(json.get("fake").is_none());
105 }
106
107 #[test]
108 fn serialize_update_empty() {
109 let data = TaskGroupUpdate::default();
110 let json = serde_json::to_value(&data).unwrap();
111 assert_eq!(json, serde_json::json!({}));
112 }
113}