Skip to main content

do_memory_storage_turso/storage/
heuristics.rs

1//! Heuristic CRUD operations for Turso storage
2
3use crate::TursoStorage;
4use do_memory_core::{Error, Heuristic, Result};
5use libsql::Row;
6use tracing::{debug, info};
7use uuid::Uuid;
8
9impl TursoStorage {
10    /// Store a heuristic
11    pub async fn store_heuristic(&self, heuristic: &Heuristic) -> Result<()> {
12        debug!("Storing heuristic: {}", heuristic.heuristic_id);
13        let (conn, _conn_id) = self.get_connection_with_id().await?;
14
15        const SQL: &str = r#"
16            INSERT OR REPLACE INTO heuristics (
17                heuristic_id, condition_text, action_text, confidence, evidence, created_at, updated_at
18            ) VALUES (?, ?, ?, ?, ?, ?, ?)
19        "#;
20
21        let evidence_json =
22            serde_json::to_string(&heuristic.evidence).map_err(Error::Serialization)?;
23
24        // Use prepared statement cache
25        let stmt = self
26            .prepared_cache
27            .get_or_prepare(&conn, SQL)
28            .await
29            .map_err(|e| Error::Storage(format!("Failed to prepare statement: {}", e)))?;
30
31        stmt.execute(libsql::params![
32            heuristic.heuristic_id.to_string(),
33            heuristic.condition.clone(),
34            heuristic.action.clone(),
35            heuristic.confidence,
36            evidence_json,
37            heuristic.created_at.timestamp(),
38            heuristic.updated_at.timestamp(),
39        ])
40        .await
41        .map_err(|e| Error::Storage(format!("Failed to store heuristic: {}", e)))?;
42
43        info!("Successfully stored heuristic: {}", heuristic.heuristic_id);
44        Ok(())
45    }
46
47    /// Retrieve a heuristic by ID
48    pub async fn get_heuristic(&self, id: Uuid) -> Result<Option<Heuristic>> {
49        debug!("Retrieving heuristic: {}", id);
50        let (conn, _conn_id) = self.get_connection_with_id().await?;
51
52        const SQL: &str = r#"
53            SELECT heuristic_id, condition_text, action_text, confidence, evidence, created_at, updated_at
54            FROM heuristics WHERE heuristic_id = ?
55        "#;
56
57        // Use prepared statement cache
58        let stmt = self
59            .prepared_cache
60            .get_or_prepare(&conn, SQL)
61            .await
62            .map_err(|e| Error::Storage(format!("Failed to prepare statement: {}", e)))?;
63
64        let mut rows = stmt
65            .query(libsql::params![id.to_string()])
66            .await
67            .map_err(|e| Error::Storage(format!("Failed to query heuristic: {}", e)))?;
68
69        if let Some(row) = rows
70            .next()
71            .await
72            .map_err(|e| Error::Storage(format!("Failed to fetch heuristic row: {}", e)))?
73        {
74            let heuristic = row_to_heuristic(&row)?;
75            Ok(Some(heuristic))
76        } else {
77            Ok(None)
78        }
79    }
80
81    /// Get all heuristics
82    pub async fn get_heuristics(&self) -> Result<Vec<Heuristic>> {
83        debug!("Retrieving all heuristics");
84        let (conn, _conn_id) = self.get_connection_with_id().await?;
85
86        const SQL: &str = r#"
87            SELECT heuristic_id, condition_text, action_text, confidence, evidence, created_at, updated_at
88            FROM heuristics ORDER BY confidence DESC
89        "#;
90
91        // Use prepared statement cache
92        let stmt = self
93            .prepared_cache
94            .get_or_prepare(&conn, SQL)
95            .await
96            .map_err(|e| Error::Storage(format!("Failed to prepare statement: {}", e)))?;
97
98        let mut rows = stmt
99            .query(())
100            .await
101            .map_err(|e| Error::Storage(format!("Failed to query heuristics: {}", e)))?;
102
103        let mut heuristics = Vec::new();
104        while let Some(row) = rows
105            .next()
106            .await
107            .map_err(|e| Error::Storage(format!("Failed to fetch heuristic row: {}", e)))?
108        {
109            heuristics.push(row_to_heuristic(&row)?);
110        }
111
112        info!("Found {} heuristics", heuristics.len());
113        Ok(heuristics)
114    }
115
116    /// Delete a heuristic by ID
117    pub async fn delete_heuristic(&self, id: Uuid) -> Result<()> {
118        debug!("Deleting heuristic: {}", id);
119        let (conn, _conn_id) = self.get_connection_with_id().await?;
120
121        const SQL: &str = "DELETE FROM heuristics WHERE heuristic_id = ?";
122
123        // Use prepared statement cache
124        let stmt = self
125            .prepared_cache
126            .get_or_prepare(&conn, SQL)
127            .await
128            .map_err(|e| Error::Storage(format!("Failed to prepare statement: {}", e)))?;
129
130        stmt.execute(libsql::params![id.to_string()])
131            .await
132            .map_err(|e| Error::Storage(format!("Failed to delete heuristic: {}", e)))?;
133
134        info!("Successfully deleted heuristic: {}", id);
135        Ok(())
136    }
137}
138
139/// Convert a database row to a Heuristic
140pub fn row_to_heuristic(row: &Row) -> Result<Heuristic> {
141    let id: String = row.get(0).map_err(|e| Error::Storage(e.to_string()))?;
142    let heuristic_id = Uuid::parse_str(&id).map_err(|e| Error::Storage(e.to_string()))?;
143    let condition: String = row.get(1).map_err(|e| Error::Storage(e.to_string()))?;
144    let action: String = row.get(2).map_err(|e| Error::Storage(e.to_string()))?;
145    let confidence: f64 = row.get(3).map_err(|e| Error::Storage(e.to_string()))?;
146    let evidence_json: String = row.get(4).map_err(|e| Error::Storage(e.to_string()))?;
147    let created_at_timestamp: i64 = row.get(5).map_err(|e| Error::Storage(e.to_string()))?;
148    let updated_at_timestamp: i64 = row.get(6).map_err(|e| Error::Storage(e.to_string()))?;
149
150    let evidence: do_memory_core::types::Evidence = serde_json::from_str(&evidence_json)
151        .map_err(|e| Error::Storage(format!("Failed to parse evidence: {}", e)))?;
152
153    Ok(Heuristic {
154        heuristic_id,
155        condition,
156        action,
157        confidence: confidence as f32,
158        evidence,
159        created_at: chrono::DateTime::from_timestamp(created_at_timestamp, 0).unwrap_or_default(),
160        updated_at: chrono::DateTime::from_timestamp(updated_at_timestamp, 0).unwrap_or_default(),
161    })
162}