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