sqlite_graphrag/storage/
backend.rs1use rusqlite::Connection;
10
11pub trait StorageBackend {
16 fn execute_sql(
18 &self,
19 sql: &str,
20 params: &[&dyn rusqlite::types::ToSql],
21 ) -> Result<usize, crate::errors::AppError>;
22
23 fn query_one<T, F>(
25 &self,
26 sql: &str,
27 params: &[&dyn rusqlite::types::ToSql],
28 f: F,
29 ) -> Result<Option<T>, crate::errors::AppError>
30 where
31 F: FnOnce(&rusqlite::Row<'_>) -> Result<T, rusqlite::Error>;
32
33 fn as_connection(&self) -> &Connection;
36}
37
38pub struct SqliteBackend {
40 conn: Connection,
41}
42
43impl SqliteBackend {
44 pub fn new(conn: Connection) -> Self {
45 Self { conn }
46 }
47
48 pub fn into_inner(self) -> Connection {
49 self.conn
50 }
51}
52
53impl StorageBackend for SqliteBackend {
54 fn execute_sql(
55 &self,
56 sql: &str,
57 params: &[&dyn rusqlite::types::ToSql],
58 ) -> Result<usize, crate::errors::AppError> {
59 self.conn
60 .execute(sql, params)
61 .map_err(crate::errors::AppError::Database)
62 }
63
64 fn query_one<T, F>(
65 &self,
66 sql: &str,
67 params: &[&dyn rusqlite::types::ToSql],
68 f: F,
69 ) -> Result<Option<T>, crate::errors::AppError>
70 where
71 F: FnOnce(&rusqlite::Row<'_>) -> Result<T, rusqlite::Error>,
72 {
73 match self.conn.query_row(sql, params, f) {
74 Ok(val) => Ok(Some(val)),
75 Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
76 Err(e) => Err(crate::errors::AppError::Database(e)),
77 }
78 }
79
80 fn as_connection(&self) -> &Connection {
81 &self.conn
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn sqlite_backend_wraps_connection() {
91 let conn = Connection::open_in_memory().unwrap();
92 conn.execute_batch("CREATE TABLE test (id INTEGER PRIMARY KEY, val TEXT)")
93 .unwrap();
94 let backend = SqliteBackend::new(conn);
95 let affected = backend
96 .execute_sql(
97 "INSERT INTO test (val) VALUES (?1)",
98 &[&"hello" as &dyn rusqlite::types::ToSql],
99 )
100 .unwrap();
101 assert_eq!(affected, 1);
102
103 let result: Option<String> = backend
104 .query_one("SELECT val FROM test WHERE id = 1", &[], |r| r.get(0))
105 .unwrap();
106 assert_eq!(result, Some("hello".to_string()));
107 }
108}