create.rs

 1use anyhow::{anyhow, Result};
 2use loro::LoroMap;
 3use std::path::Path;
 4
 5use crate::db;
 6
 7pub struct Opts<'a> {
 8    pub title: Option<&'a str>,
 9    pub priority: db::Priority,
10    pub effort: db::Effort,
11    pub task_type: &'a str,
12    pub desc: Option<&'a str>,
13    pub parent: Option<&'a str>,
14    pub labels: Option<&'a str>,
15    pub json: bool,
16}
17
18pub fn run(root: &Path, opts: Opts) -> Result<()> {
19    let title = opts.title.ok_or_else(|| anyhow!("title required"))?;
20    let desc = opts.desc.unwrap_or("");
21    let ts = db::now_utc();
22
23    let store = db::open(root)?;
24    let id = db::gen_id();
25
26    let parent = if let Some(raw) = opts.parent {
27        Some(db::resolve_task_id(&store, raw, false)?)
28    } else {
29        None
30    };
31
32    store.apply_and_persist(|doc| {
33        let tasks = doc.get_map("tasks");
34        let task = db::insert_task_map(&tasks, &id)?;
35
36        task.insert("title", title)?;
37        task.insert("description", desc)?;
38        task.insert("type", opts.task_type)?;
39        task.insert("priority", db::priority_label(opts.priority))?;
40        task.insert("status", db::status_label(db::Status::Open))?;
41        task.insert("effort", db::effort_label(opts.effort))?;
42        task.insert("parent", parent.as_ref().map(|p| p.as_str()).unwrap_or(""))?;
43        task.insert("created_at", ts.clone())?;
44        task.insert("updated_at", ts.clone())?;
45        task.insert("deleted_at", "")?;
46        task.insert_container("labels", LoroMap::new())?;
47        task.insert_container("blockers", LoroMap::new())?;
48        task.insert_container("logs", LoroMap::new())?;
49
50        if let Some(label_str) = opts.labels {
51            let labels = db::get_or_create_child_map(&task, "labels")?;
52            for lbl in label_str
53                .split(',')
54                .map(str::trim)
55                .filter(|l| !l.is_empty())
56            {
57                labels.insert(lbl, true)?;
58            }
59        }
60
61        Ok(())
62    })?;
63
64    let task = store
65        .get_task(&id, false)?
66        .ok_or_else(|| anyhow!("failed to reload created task"))?;
67
68    if opts.json {
69        println!("{}", serde_json::to_string(&task)?);
70    } else {
71        let c = crate::color::stdout_theme();
72        println!("{}created{} {}: {}", c.green, c.reset, task.id, task.title);
73    }
74
75    Ok(())
76}