agentmux_srv/backend/storage/
agent_activity_summaries.rs1use rusqlite::params;
16
17use super::error::StoreError;
18use super::store::Store;
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct AgentActivitySummary {
22 pub definition_id: String,
23 pub summary: String,
24 pub updated_at: i64,
25}
26
27impl Store {
28 pub fn agent_activity_summary_get(
29 &self,
30 definition_id: &str,
31 ) -> Result<Option<AgentActivitySummary>, StoreError> {
32 let conn = self.conn.lock().unwrap();
33 let mut stmt = conn.prepare(
34 "SELECT definition_id, summary, updated_at FROM db_agent_activity_summaries WHERE definition_id = ?1",
35 )?;
36 let mut rows = stmt.query_map(params![definition_id], map_row)?;
37 match rows.next() {
38 Some(r) => Ok(Some(r?)),
39 None => Ok(None),
40 }
41 }
42
43 pub fn agent_activity_summary_set(
49 &self,
50 definition_id: &str,
51 summary: &str,
52 updated_at: i64,
53 ) -> Result<(), StoreError> {
54 let conn = self.conn.lock().unwrap();
55 conn.execute(
56 "INSERT INTO db_agent_activity_summaries (definition_id, summary, updated_at)
57 VALUES (?1, ?2, ?3)
58 ON CONFLICT(definition_id) DO UPDATE SET summary = ?2, updated_at = ?3",
59 params![definition_id, summary, updated_at],
60 )?;
61 Ok(())
62 }
63}
64
65fn map_row(row: &rusqlite::Row<'_>) -> rusqlite::Result<AgentActivitySummary> {
66 Ok(AgentActivitySummary {
67 definition_id: row.get(0)?,
68 summary: row.get(1)?,
69 updated_at: row.get(2)?,
70 })
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 fn object_store() -> Store {
78 Store::open(std::path::Path::new(":memory:")).unwrap()
79 }
80
81 #[test]
82 fn get_returns_none_when_never_generated() {
83 let store = object_store();
84 assert!(store.agent_activity_summary_get("def-1").unwrap().is_none());
85 }
86
87 #[test]
88 fn set_then_get_roundtrips() {
89 let store = object_store();
90 store.agent_activity_summary_set("def-1", "Debugging a flaky test", 1000).unwrap();
91 let got = store.agent_activity_summary_get("def-1").unwrap().unwrap();
92 assert_eq!(got.definition_id, "def-1");
93 assert_eq!(got.summary, "Debugging a flaky test");
94 assert_eq!(got.updated_at, 1000);
95 }
96
97 #[test]
98 fn set_twice_upserts_instead_of_erroring() {
99 let store = object_store();
100 store.agent_activity_summary_set("def-1", "first summary", 1000).unwrap();
101 store.agent_activity_summary_set("def-1", "second summary", 2000).unwrap();
102 let got = store.agent_activity_summary_get("def-1").unwrap().unwrap();
103 assert_eq!(got.summary, "second summary");
104 assert_eq!(got.updated_at, 2000);
105 }
106
107 #[test]
108 fn distinct_definitions_do_not_collide() {
109 let store = object_store();
110 store.agent_activity_summary_set("def-1", "summary one", 1000).unwrap();
111 store.agent_activity_summary_set("def-2", "summary two", 2000).unwrap();
112 assert_eq!(store.agent_activity_summary_get("def-1").unwrap().unwrap().summary, "summary one");
113 assert_eq!(store.agent_activity_summary_get("def-2").unwrap().unwrap().summary, "summary two");
114 }
115}