Skip to main content

verso/store/
db.rs

1use rusqlite::{Connection, OpenFlags};
2use std::path::{Path, PathBuf};
3
4/// Owns the SQLite path and produces fresh connections.
5/// A "connection" here is a short-lived handle; the store-writer thread owns a long-lived one.
6pub struct Db {
7    path: PathBuf,
8}
9
10impl Db {
11    pub fn open(path: &Path) -> anyhow::Result<Self> {
12        if let Some(parent) = path.parent() {
13            std::fs::create_dir_all(parent)?;
14        }
15        // Validate we can open.
16        let _ = Self::new_conn(path)?;
17        Ok(Self {
18            path: path.to_path_buf(),
19        })
20    }
21
22    pub fn conn(&self) -> anyhow::Result<Connection> {
23        Self::new_conn(&self.path)
24    }
25
26    fn new_conn(path: &Path) -> anyhow::Result<Connection> {
27        let c = Connection::open_with_flags(
28            path,
29            OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE,
30        )?;
31        c.pragma_update(None, "journal_mode", "WAL")?;
32        c.pragma_update(None, "synchronous", "NORMAL")?;
33        c.pragma_update(None, "busy_timeout", 5000i64)?;
34        c.pragma_update(None, "foreign_keys", "ON")?;
35        Ok(c)
36    }
37
38    pub fn migrate(&self) -> anyhow::Result<()> {
39        super::migrate::run(&mut self.conn()?)
40    }
41
42    pub fn location(&self) -> &std::path::Path {
43        &self.path
44    }
45}