1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5#[serde(rename_all = "snake_case")]
6pub enum TaskStatus {
7 Pending,
8 InProgress,
9 Completed,
10 Blocked,
11 Cancelled,
12}
13
14impl fmt::Display for TaskStatus {
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 match self {
17 TaskStatus::Pending => write!(f, "pending"),
18 TaskStatus::InProgress => write!(f, "in_progress"),
19 TaskStatus::Completed => write!(f, "completed"),
20 TaskStatus::Blocked => write!(f, "blocked"),
21 TaskStatus::Cancelled => write!(f, "cancelled"),
22 }
23 }
24}
25
26impl TaskStatus {
27 pub fn from_str(s: &str) -> Option<Self> {
28 match s {
29 "pending" => Some(TaskStatus::Pending),
30 "in_progress" => Some(TaskStatus::InProgress),
31 "completed" => Some(TaskStatus::Completed),
32 "blocked" => Some(TaskStatus::Blocked),
33 "cancelled" => Some(TaskStatus::Cancelled),
34 _ => None,
35 }
36 }
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct Task {
41 pub id: i64,
42 pub description: String,
43 pub status: TaskStatus,
44 pub priority: i32,
45 pub blocked_by: Option<String>,
46 pub spec_section_id: Option<i64>,
47 pub created_at: String,
48 pub started_at: Option<String>,
49 pub completed_at: Option<String>,
50}
51
52impl Task {
53 pub fn from_row(row: &rusqlite::Row) -> rusqlite::Result<Self> {
54 let status_str: String = row.get("status")?;
55 Ok(Task {
56 id: row.get("id")?,
57 description: row.get("description")?,
58 status: TaskStatus::from_str(&status_str).unwrap_or(TaskStatus::Pending),
59 priority: row.get("priority")?,
60 blocked_by: row.get("blocked_by")?,
61 spec_section_id: row.get("spec_section_id")?,
62 created_at: row.get("created_at")?,
63 started_at: row.get("started_at")?,
64 completed_at: row.get("completed_at")?,
65 })
66 }
67}