Skip to main content

zeph_memory/sqlite/
history.rs

1use super::SqliteStore;
2use crate::error::MemoryError;
3
4impl SqliteStore {
5    /// Load the most recent input history entries, ordered chronologically.
6    ///
7    /// # Errors
8    ///
9    /// Returns an error if the query fails.
10    pub async fn load_input_history(&self, limit: i64) -> Result<Vec<String>, MemoryError> {
11        let rows: Vec<(String,)> =
12            sqlx::query_as("SELECT input FROM input_history ORDER BY id ASC LIMIT ?")
13                .bind(limit)
14                .fetch_all(&self.pool)
15                .await?;
16        Ok(rows.into_iter().map(|(s,)| s).collect())
17    }
18
19    /// Persist a new input history entry.
20    ///
21    /// # Errors
22    ///
23    /// Returns an error if the insert fails.
24    pub async fn save_input_entry(&self, text: &str) -> Result<(), MemoryError> {
25        sqlx::query("INSERT INTO input_history (input) VALUES (?)")
26            .bind(text)
27            .execute(&self.pool)
28            .await?;
29        Ok(())
30    }
31
32    /// Delete all input history entries.
33    ///
34    /// # Errors
35    ///
36    /// Returns an error if the delete fails.
37    pub async fn clear_input_history(&self) -> Result<(), MemoryError> {
38        sqlx::query("DELETE FROM input_history")
39            .execute(&self.pool)
40            .await?;
41        Ok(())
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    async fn test_store() -> SqliteStore {
50        SqliteStore::new(":memory:").await.unwrap()
51    }
52
53    #[tokio::test]
54    async fn load_input_history_empty() {
55        let store = test_store().await;
56        let entries = store.load_input_history(100).await.unwrap();
57        assert!(entries.is_empty());
58    }
59
60    #[tokio::test]
61    async fn save_and_load_input_history() {
62        let store = test_store().await;
63        store.save_input_entry("hello").await.unwrap();
64        store.save_input_entry("world").await.unwrap();
65        let entries = store.load_input_history(100).await.unwrap();
66        assert_eq!(entries, vec!["hello", "world"]);
67    }
68
69    #[tokio::test]
70    async fn load_input_history_respects_limit() {
71        let store = test_store().await;
72        for i in 0..10 {
73            store.save_input_entry(&format!("entry {i}")).await.unwrap();
74        }
75        let entries = store.load_input_history(3).await.unwrap();
76        assert_eq!(entries.len(), 3);
77        assert_eq!(entries[0], "entry 0");
78    }
79
80    #[tokio::test]
81    async fn clear_input_history_removes_all() {
82        let store = test_store().await;
83        store.save_input_entry("a").await.unwrap();
84        store.save_input_entry("b").await.unwrap();
85        store.clear_input_history().await.unwrap();
86        let entries = store.load_input_history(100).await.unwrap();
87        assert!(entries.is_empty());
88    }
89}