Skip to main content

kaizen/store/sqlite/
reports.rs

1use super::rows::*;
2use super::*;
3
4impl Store {
5    pub fn summary_stats(&self, workspace: &str) -> Result<SummaryStats> {
6        let session_count: i64 = self.conn.query_row(
7            "SELECT COUNT(*) FROM sessions WHERE workspace = ?1",
8            params![workspace],
9            |r| r.get(0),
10        )?;
11
12        let total_cost: i64 = self.conn.query_row(
13            "SELECT COALESCE(SUM(e.cost_usd_e6), 0) FROM events e
14             JOIN sessions s ON s.id = e.session_id WHERE s.workspace = ?1",
15            params![workspace],
16            |r| r.get(0),
17        )?;
18
19        let mut stmt = self.conn.prepare(
20            "SELECT agent, COUNT(*) FROM sessions WHERE workspace = ?1 GROUP BY agent ORDER BY COUNT(*) DESC",
21        )?;
22        let by_agent: Vec<(String, u64)> = stmt
23            .query_map(params![workspace], |r| {
24                Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)? as u64))
25            })?
26            .filter_map(|r| r.ok())
27            .collect();
28
29        let mut stmt = self.conn.prepare(
30            "SELECT COALESCE(model, 'unknown'), COUNT(*) FROM sessions WHERE workspace = ?1 GROUP BY model ORDER BY COUNT(*) DESC",
31        )?;
32        let by_model: Vec<(String, u64)> = stmt
33            .query_map(params![workspace], |r| {
34                Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)? as u64))
35            })?
36            .filter_map(|r| r.ok())
37            .collect();
38
39        let mut stmt = self.conn.prepare(
40            "SELECT tool, COUNT(*) FROM events e JOIN sessions s ON s.id = e.session_id
41             WHERE s.workspace = ?1 AND tool IS NOT NULL
42             GROUP BY tool ORDER BY COUNT(*) DESC LIMIT 10",
43        )?;
44        let top_tools: Vec<(String, u64)> = stmt
45            .query_map(params![workspace], |r| {
46                Ok((r.get::<_, String>(0)?, r.get::<_, i64>(1)? as u64))
47            })?
48            .filter_map(|r| r.ok())
49            .collect();
50
51        Ok(SummaryStats {
52            session_count: session_count as u64,
53            total_cost_usd_e6: total_cost,
54            by_agent,
55            by_model,
56            top_tools,
57        })
58    }
59
60    /// Workspace activity dashboard — feeds `cmd_insights`.
61    pub fn insights(&self, workspace: &str) -> Result<InsightsStats> {
62        let (total_cost_usd_e6, sessions_with_cost) = cost_stats(&self.conn, workspace)?;
63        Ok(InsightsStats {
64            total_sessions: count_q(
65                &self.conn,
66                "SELECT COUNT(*) FROM sessions WHERE workspace=?1",
67                workspace,
68            )?,
69            running_sessions: count_q(
70                &self.conn,
71                "SELECT COUNT(*) FROM sessions WHERE workspace=?1 AND status='Running'",
72                workspace,
73            )?,
74            total_events: count_q(
75                &self.conn,
76                "SELECT COUNT(*) FROM events e JOIN sessions s ON s.id=e.session_id WHERE s.workspace=?1",
77                workspace,
78            )?,
79            sessions_by_day: sessions_by_day_7(&self.conn, workspace, now_ms())?,
80            recent: recent_sessions_3(&self.conn, workspace)?,
81            top_tools: top_tools_5(&self.conn, workspace)?,
82            total_cost_usd_e6,
83            sessions_with_cost,
84        })
85    }
86}