Skip to main content

finance_core/
db.rs

1// ═══════════════════════════════════════════════════════════════════════════
2// DB — shared SQLite connection + refinery migrations.
3//
4// One SQLite file (`Paths::db_file()`) is used by every finance-* CLI.
5// finance-core owns the schema and the migration runner so tables never
6// diverge across tools.
7// ═══════════════════════════════════════════════════════════════════════════
8
9use std::path::Path;
10
11use rusqlite::Connection;
12
13use crate::error::Result;
14use crate::paths::Paths;
15
16mod embedded {
17    use refinery::embed_migrations;
18    embed_migrations!("./migrations");
19}
20
21/// Open the shared accounting DB (creating dirs + file if missing) and run
22/// pending migrations. Use this in every CLI that wants to read/write the
23/// suite's data.
24pub fn open(paths: &Paths) -> Result<Connection> {
25    open_at(&paths.db_file())
26}
27
28pub fn open_at(path: &Path) -> Result<Connection> {
29    if let Some(parent) = path.parent() {
30        std::fs::create_dir_all(parent)?;
31    }
32    let mut conn = Connection::open(path)?;
33    conn.pragma_update(None, "journal_mode", "WAL")?;
34    conn.pragma_update(None, "foreign_keys", "ON")?;
35    embedded::migrations::runner().run(&mut conn)?;
36    Ok(conn)
37}
38
39/// Current applied migration version — useful for `doctor` / health checks.
40pub fn schema_version(conn: &Connection) -> Result<Option<u32>> {
41    let v: Option<u32> = conn
42        .query_row(
43            "SELECT MAX(version) FROM refinery_schema_history",
44            [],
45            |row| row.get(0),
46        )
47        .ok();
48    Ok(v)
49}