Skip to main content

sift_queue/cli/commands/
list.rs

1use crate::cli::formatters;
2use crate::queue::{Item, Queue};
3use crate::ListArgs;
4use anyhow::Result;
5use std::collections::HashSet;
6use std::io::Write;
7use std::path::PathBuf;
8use std::process::{Command, Stdio};
9
10/// Execute the `sq list` command.
11pub fn execute(args: &ListArgs, queue_path: PathBuf) -> Result<i32> {
12    let queue = Queue::new(queue_path);
13
14    let mut items: Vec<Item> = if args.ready {
15        queue.ready()
16    } else {
17        queue.filter(args.status.as_deref())
18    };
19
20    // Apply jq filter
21    if let Some(ref filter_expr) = args.filter {
22        let expr = format!("[.[] | {}]", filter_expr);
23        match jq_filter(&items, &expr) {
24            Some(filtered) => items = filtered,
25            None => return Ok(1),
26        }
27    }
28
29    // Apply jq sort
30    if let Some(ref sort_path) = args.sort {
31        let expr = format!("sort_by({} // infinite)", sort_path);
32        match jq_filter(&items, &expr) {
33            Some(sorted) => items = sorted,
34            None => return Ok(1),
35        }
36    }
37
38    // Apply reverse
39    if args.reverse {
40        items.reverse();
41    }
42
43    if args.json {
44        let values: Vec<serde_json::Value> = items.iter().map(|i: &Item| i.to_json_value()).collect();
45        let json = serde_json::to_string_pretty(&values)?;
46        println!("{}", json);
47    } else if items.is_empty() {
48        eprintln!("No items found");
49    } else {
50        let pending_ids: HashSet<String> = queue
51            .filter(Some("pending"))
52            .iter()
53            .map(|i| i.id.clone())
54            .collect();
55        for item in &items {
56            formatters::print_item_summary(item, Some(&pending_ids));
57        }
58        eprintln!("{} item(s)", items.len());
59    }
60
61    Ok(0)
62}
63
64/// Run a jq expression on items, returning parsed results or None on error.
65fn jq_filter(items: &[Item], expr: &str) -> Option<Vec<Item>> {
66    let json_values: Vec<serde_json::Value> = items.iter().map(|i: &Item| i.to_json_value()).collect();
67    let json = serde_json::to_string(&json_values).ok()?;
68
69    let mut child = Command::new("jq")
70        .arg("-e")
71        .arg(expr)
72        .stdin(Stdio::piped())
73        .stdout(Stdio::piped())
74        .stderr(Stdio::piped())
75        .spawn()
76        .map_err(|e| {
77            eprintln!("Error: Failed to run jq: {}", e);
78        })
79        .ok()?;
80
81    if let Some(ref mut stdin) = child.stdin {
82        stdin.write_all(json.as_bytes()).ok()?;
83    }
84    // Close stdin
85    drop(child.stdin.take());
86
87    let output = child.wait_with_output().ok()?;
88
89    if !output.status.success() {
90        let stderr = String::from_utf8_lossy(&output.stderr);
91        eprintln!("Error: Filter failed: {}", stderr.trim());
92        return None;
93    }
94
95    let parsed: Vec<serde_json::Value> = serde_json::from_slice(&output.stdout).ok()?;
96    Some(
97        parsed
98            .into_iter()
99            .filter_map(|v| serde_json::from_value::<Item>(v).ok())
100            .collect(),
101    )
102}