1use crate::core_loop::{ReviewStatus, review, time};
3use crate::shell::cli::workspace_path;
4use crate::store::Store;
5use anyhow::Result;
6use std::path::Path;
7
8pub fn cmd_review_list(workspace: Option<&Path>, status: Option<String>, json: bool) -> Result<()> {
9 output(
10 &review::list(&open(workspace)?, parse_status(status.as_deref()))?,
11 json,
12 )
13}
14
15pub fn cmd_review_show(workspace: Option<&Path>, id: &str, json: bool) -> Result<()> {
16 let row = review::get(&open(workspace)?, id)?;
17 if json {
18 println!("{}", json_one(&row)?);
19 return Ok(());
20 }
21 output(&[row], false)
22}
23
24pub fn cmd_review_resolve(workspace: Option<&Path>, id: &str) -> Result<()> {
25 set(workspace, id, ReviewStatus::Resolved, "resolved")
26}
27
28pub fn cmd_review_dismiss(workspace: Option<&Path>, id: &str) -> Result<()> {
29 set(workspace, id, ReviewStatus::Dismissed, "dismissed")
30}
31
32fn set(workspace: Option<&Path>, id: &str, status: ReviewStatus, label: &str) -> Result<()> {
33 review::set_status(&open(workspace)?, id, status, time::now_ms())?;
34 println!("{label} review {id}");
35 Ok(())
36}
37
38fn open(workspace: Option<&Path>) -> Result<Store> {
39 let ws = workspace_path(workspace)?;
40 Store::open(&crate::core::workspace::db_path(&ws)?)
41}
42
43fn output(rows: &[crate::core_loop::ReviewItem], json: bool) -> Result<()> {
44 if json {
45 println!("{}", serde_json::to_string_pretty(rows)?);
46 } else {
47 rows.iter().for_each(|r| {
48 println!(
49 "{} session={} status={} {}",
50 r.id,
51 r.session_id,
52 r.status.as_str(),
53 r.title
54 )
55 });
56 }
57 Ok(())
58}
59
60fn json_one(row: &crate::core_loop::ReviewItem) -> Result<String> {
61 Ok(serde_json::to_string_pretty(row)?)
62}
63
64fn parse_status(raw: Option<&str>) -> Option<ReviewStatus> {
65 raw.map(|s| match s {
66 "resolved" => ReviewStatus::Resolved,
67 "dismissed" => ReviewStatus::Dismissed,
68 _ => ReviewStatus::Open,
69 })
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use crate::core_loop::ReviewItem;
76
77 #[test]
78 fn review_show_json_renders_single_object() {
79 let text = json_one(&item()).unwrap();
80 assert!(
81 serde_json::from_str::<serde_json::Value>(&text)
82 .unwrap()
83 .is_object()
84 );
85 }
86
87 fn item() -> ReviewItem {
88 ReviewItem {
89 id: "r1".into(),
90 source_key: "k".into(),
91 session_id: "s1".into(),
92 title: "Review".into(),
93 status: ReviewStatus::Open,
94 created_at_ms: 1,
95 resolved_at_ms: None,
96 }
97 }
98}