Skip to main content

kernex_memory/store/
sessions.rs

1//! Project-scoped CLI session persistence.
2//!
3//! SQLite-backed sessions scoped per (channel, sender_id, project).
4
5use super::Store;
6use kernex_core::error::KernexError;
7use uuid::Uuid;
8
9impl Store {
10    /// Upsert a CLI session for a (channel, sender_id, project) tuple.
11    pub async fn store_session(
12        &self,
13        channel: &str,
14        sender_id: &str,
15        project: &str,
16        session_id: &str,
17    ) -> Result<(), KernexError> {
18        let id = Uuid::new_v4().to_string();
19        sqlx::query(
20            "INSERT INTO project_sessions (id, channel, sender_id, project, session_id) \
21             VALUES (?, ?, ?, ?, ?) \
22             ON CONFLICT(channel, sender_id, project) \
23             DO UPDATE SET session_id = excluded.session_id, updated_at = datetime('now')",
24        )
25        .bind(&id)
26        .bind(channel)
27        .bind(sender_id)
28        .bind(project)
29        .bind(session_id)
30        .execute(&self.pool)
31        .await
32        .map_err(|e| KernexError::Store(format!("store_session failed: {e}")))?;
33
34        Ok(())
35    }
36
37    /// Look up the CLI session_id for a (channel, sender_id, project) tuple.
38    pub async fn get_session(
39        &self,
40        channel: &str,
41        sender_id: &str,
42        project: &str,
43    ) -> Result<Option<String>, KernexError> {
44        let row: Option<(String,)> = sqlx::query_as(
45            "SELECT session_id FROM project_sessions \
46             WHERE channel = ? AND sender_id = ? AND project = ?",
47        )
48        .bind(channel)
49        .bind(sender_id)
50        .bind(project)
51        .fetch_optional(&self.pool)
52        .await
53        .map_err(|e| KernexError::Store(format!("get_session failed: {e}")))?;
54
55        Ok(row.map(|(sid,)| sid))
56    }
57
58    /// Delete the CLI session for a specific (channel, sender_id, project).
59    pub async fn clear_session(
60        &self,
61        channel: &str,
62        sender_id: &str,
63        project: &str,
64    ) -> Result<(), KernexError> {
65        sqlx::query(
66            "DELETE FROM project_sessions \
67             WHERE channel = ? AND sender_id = ? AND project = ?",
68        )
69        .bind(channel)
70        .bind(sender_id)
71        .bind(project)
72        .execute(&self.pool)
73        .await
74        .map_err(|e| KernexError::Store(format!("clear_session failed: {e}")))?;
75
76        Ok(())
77    }
78
79    /// Delete all CLI sessions for a sender.
80    pub async fn clear_all_sessions_for_sender(&self, sender_id: &str) -> Result<(), KernexError> {
81        sqlx::query("DELETE FROM project_sessions WHERE sender_id = ?")
82            .bind(sender_id)
83            .execute(&self.pool)
84            .await
85            .map_err(|e| KernexError::Store(format!("clear_all_sessions failed: {e}")))?;
86
87        Ok(())
88    }
89}