Skip to main content

innate_core/storage/
raw.rs

1use super::*;
2
3impl Storage {
4    pub fn attach_shared(&self, path: &str, alias: &str) -> Result<()> {
5        self.conn.execute_batch(&format!(
6            "ATTACH DATABASE '{}' AS '{alias}'",
7            path.replace('\'', "''")
8        ))?;
9        Ok(())
10    }
11
12    pub fn lib_id(&self) -> Result<String> {
13        Ok(self
14            .get_meta("lib_id")?
15            .unwrap_or_else(|| "unknown".to_string()))
16    }
17
18    // ------------------------------------------------------------------
19    // Generic helpers
20    // ------------------------------------------------------------------
21
22    pub(in crate::storage) fn query_json<P: rusqlite::Params>(
23        &self,
24        sql: &str,
25        p: P,
26    ) -> Result<Vec<Value>> {
27        let mut stmt = self.conn.prepare(sql)?;
28        let names: Vec<String> = stmt.column_names().iter().map(|s| s.to_string()).collect();
29        let rows = stmt.query_map(p, |r| row_to_json_with_names(r, &names))?;
30        Ok(rows.filter_map(|r| r.ok()).collect())
31    }
32
33    /// Execute a parameterised statement (not batch); returns rows-affected count.
34    pub(crate) fn conn_execute<P: rusqlite::Params>(&self, sql: &str, p: P) -> Result<()> {
35        self.conn.execute(sql, p)?;
36        Ok(())
37    }
38
39    pub(crate) fn conn_execute_count<P: rusqlite::Params>(&self, sql: &str, p: P) -> Result<usize> {
40        Ok(self.conn.execute(sql, p)?)
41    }
42
43    /// On-disk size of the main database file in bytes (`page_count * page_size`).
44    pub fn db_size_bytes(&self) -> Result<i64> {
45        let page_count: i64 = self.conn.query_row("PRAGMA page_count", [], |r| r.get(0))?;
46        let page_size: i64 = self.conn.query_row("PRAGMA page_size", [], |r| r.get(0))?;
47        Ok(page_count * page_size)
48    }
49
50    /// Reclaim space freed by curate's log compaction and trace purges: checkpoint
51    /// and truncate the WAL, then VACUUM to return free pages to the OS. Returns
52    /// `(before_bytes, after_bytes)`. Must run outside any transaction.
53    pub fn vacuum(&self) -> Result<(i64, i64)> {
54        let before = self.db_size_bytes()?;
55        self.conn.execute_batch("PRAGMA wal_checkpoint(TRUNCATE);")?;
56        self.conn.execute_batch("VACUUM;")?;
57        self.conn.execute_batch("PRAGMA wal_checkpoint(TRUNCATE);")?;
58        // VACUUM rebuilds the file but preserves all rows; in-memory vector caches
59        // stay valid (same data), so they are intentionally left untouched.
60        let after = self.db_size_bytes()?;
61        Ok((before, after))
62    }
63}