Skip to main content

kaizen/store/sqlite/
prompts.rs

1use super::*;
2
3impl Store {
4    pub fn upsert_prompt_snapshot(&self, snap: &crate::prompt::PromptSnapshot) -> Result<()> {
5        self.conn.execute(
6            "INSERT OR IGNORE INTO prompt_snapshots
7             (fingerprint, captured_at_ms, files_json, total_bytes)
8             VALUES (?1, ?2, ?3, ?4)",
9            params![
10                snap.fingerprint,
11                snap.captured_at_ms as i64,
12                snap.files_json,
13                snap.total_bytes as i64
14            ],
15        )?;
16        Ok(())
17    }
18
19    pub fn get_prompt_snapshot(
20        &self,
21        fingerprint: &str,
22    ) -> Result<Option<crate::prompt::PromptSnapshot>> {
23        self.conn
24            .query_row(
25                "SELECT fingerprint, captured_at_ms, files_json, total_bytes
26                 FROM prompt_snapshots WHERE fingerprint = ?1",
27                params![fingerprint],
28                |r| {
29                    Ok(crate::prompt::PromptSnapshot {
30                        fingerprint: r.get(0)?,
31                        captured_at_ms: r.get::<_, i64>(1)? as u64,
32                        files_json: r.get(2)?,
33                        total_bytes: r.get::<_, i64>(3)? as u64,
34                    })
35                },
36            )
37            .optional()
38            .map_err(Into::into)
39    }
40
41    pub fn list_prompt_snapshots(&self) -> Result<Vec<crate::prompt::PromptSnapshot>> {
42        let mut stmt = self.conn.prepare(
43            "SELECT fingerprint, captured_at_ms, files_json, total_bytes
44             FROM prompt_snapshots ORDER BY captured_at_ms DESC",
45        )?;
46        let rows = stmt.query_map([], |r| {
47            Ok(crate::prompt::PromptSnapshot {
48                fingerprint: r.get(0)?,
49                captured_at_ms: r.get::<_, i64>(1)? as u64,
50                files_json: r.get(2)?,
51                total_bytes: r.get::<_, i64>(3)? as u64,
52            })
53        })?;
54        Ok(rows.filter_map(|r| r.ok()).collect())
55    }
56
57    /// Sessions with a non-null prompt_fingerprint in the given window.
58    pub fn sessions_with_prompt_fingerprint(
59        &self,
60        workspace: &str,
61        start_ms: u64,
62        end_ms: u64,
63    ) -> Result<Vec<(String, String)>> {
64        let mut stmt = self.conn.prepare(
65            "SELECT id, prompt_fingerprint FROM sessions
66             WHERE workspace = ?1
67               AND started_at_ms >= ?2 AND started_at_ms < ?3
68               AND prompt_fingerprint IS NOT NULL",
69        )?;
70        let rows = stmt.query_map(params![workspace, start_ms as i64, end_ms as i64], |r| {
71            Ok((r.get::<_, String>(0)?, r.get::<_, String>(1)?))
72        })?;
73        Ok(rows.filter_map(|r| r.ok()).collect())
74    }
75}