1use anyhow::Result;
2use comfy_table::presets::NOTHING;
3use comfy_table::Table;
4use std::path::Path;
5
6use crate::db;
7
8pub fn run(
9 root: &Path,
10 status: Option<&str>,
11 priority: Option<i32>,
12 effort: Option<i32>,
13 label: Option<&str>,
14 json: bool,
15) -> Result<()> {
16 let conn = db::open(root)?;
17
18 let mut sql = String::from(
19 "SELECT id, title, description, type, priority, status, effort, parent, created, updated
20 FROM tasks WHERE 1=1",
21 );
22 let mut params: Vec<Box<dyn rusqlite::types::ToSql>> = Vec::new();
23 let mut idx = 1;
24
25 if let Some(s) = status {
26 sql.push_str(&format!(" AND status = ?{idx}"));
27 params.push(Box::new(s.to_string()));
28 idx += 1;
29 }
30 if let Some(p) = priority {
31 sql.push_str(&format!(" AND priority = ?{idx}"));
32 params.push(Box::new(p));
33 idx += 1;
34 }
35 if let Some(e) = effort {
36 sql.push_str(&format!(" AND effort = ?{idx}"));
37 params.push(Box::new(e));
38 idx += 1;
39 }
40 if let Some(l) = label {
41 sql.push_str(&format!(
42 " AND id IN (SELECT task_id FROM labels WHERE label = ?{idx})"
43 ));
44 params.push(Box::new(l.to_string()));
45 }
46
47 sql.push_str(" ORDER BY priority, created");
48
49 let param_refs: Vec<&dyn rusqlite::types::ToSql> = params.iter().map(|p| p.as_ref()).collect();
50 let mut stmt = conn.prepare(&sql)?;
51 let tasks: Vec<db::Task> = stmt
52 .query_map(param_refs.as_slice(), db::row_to_task)?
53 .collect::<rusqlite::Result<_>>()?;
54
55 if json {
56 let details: Vec<db::TaskDetail> = tasks
57 .into_iter()
58 .map(|t| {
59 let labels = db::load_labels(&conn, &t.id)?;
60 let blockers = db::load_blockers(&conn, &t.id)?;
61 Ok(db::TaskDetail {
62 task: t,
63 labels,
64 blockers,
65 })
66 })
67 .collect::<Result<_>>()?;
68 println!("{}", serde_json::to_string(&details)?);
69 } else {
70 let c = crate::color::stdout_theme();
71 let mut table = Table::new();
72 table.load_preset(NOTHING);
73 for t in &tasks {
74 table.add_row(vec![
75 format!("{}{}{}", c.bold, t.id, c.reset),
76 format!("{}[{}]{}", c.yellow, t.status, c.reset),
77 format!("{}{}{}", c.red, db::priority_label(t.priority), c.reset),
78 format!("{}{}{}", c.blue, db::effort_label(t.effort), c.reset),
79 t.title.clone(),
80 ]);
81 }
82 if !tasks.is_empty() {
83 println!("{table}");
84 }
85 }
86
87 Ok(())
88}