create.rs

 1use anyhow::Result;
 2use std::path::Path;
 3
 4use crate::db;
 5
 6pub struct Opts<'a> {
 7    pub title: Option<&'a str>,
 8    pub priority: i32,
 9    pub task_type: &'a str,
10    pub desc: Option<&'a str>,
11    pub parent: Option<&'a str>,
12    pub labels: Option<&'a str>,
13    pub json: bool,
14}
15
16pub fn run(root: &Path, opts: Opts) -> Result<()> {
17    let title = opts
18        .title
19        .ok_or_else(|| anyhow::anyhow!("title required"))?;
20    let desc = opts.desc.unwrap_or("");
21    let ts = db::now_utc();
22
23    let conn = db::open(root)?;
24
25    let id = match opts.parent {
26        Some(pid) => {
27            let count: i64 =
28                conn.query_row("SELECT COUNT(*) FROM tasks WHERE parent = ?1", [pid], |r| {
29                    r.get(0)
30                })?;
31            format!("{pid}.{}", count + 1)
32        }
33        None => db::gen_id(),
34    };
35
36    conn.execute(
37        "INSERT INTO tasks (id, title, description, type, priority, status, parent, created, updated)
38         VALUES (?1, ?2, ?3, ?4, ?5, 'open', ?6, ?7, ?8)",
39        rusqlite::params![
40            id,
41            title,
42            desc,
43            opts.task_type,
44            opts.priority,
45            opts.parent.unwrap_or(""),
46            ts,
47            ts
48        ],
49    )?;
50
51    if let Some(label_str) = opts.labels {
52        for lbl in label_str.split(',') {
53            let lbl = lbl.trim();
54            if !lbl.is_empty() {
55                conn.execute(
56                    "INSERT OR IGNORE INTO labels (task_id, label) VALUES (?1, ?2)",
57                    [&id, lbl],
58                )?;
59            }
60        }
61    }
62
63    if opts.json {
64        let task = db::Task {
65            id: id.clone(),
66            title: title.to_string(),
67            description: desc.to_string(),
68            task_type: opts.task_type.to_string(),
69            priority: opts.priority,
70            status: "open".to_string(),
71            parent: opts.parent.unwrap_or("").to_string(),
72            created: ts.clone(),
73            updated: ts,
74        };
75        println!("{}", serde_json::to_string(&task)?);
76    } else {
77        let c = crate::color::stdout_theme();
78        println!("{}created{} {id}: {title}", c.green, c.reset);
79    }
80
81    Ok(())
82}