koan_core/db/
connection.rs1use std::path::Path;
2
3use rusqlite::Connection;
4use thiserror::Error;
5
6use super::schema;
7use crate::config;
8
9#[derive(Debug, Error)]
10pub enum DbError {
11 #[error("sqlite error: {0}")]
12 Sqlite(#[from] rusqlite::Error),
13 #[error("io error: {0}")]
14 Io(#[from] std::io::Error),
15}
16
17pub struct Database {
19 pub conn: Connection,
20}
21
22impl Database {
23 pub fn open(path: &Path) -> Result<Self, DbError> {
25 if let Some(parent) = path.parent() {
26 std::fs::create_dir_all(parent)?;
27 }
28
29 let conn = Connection::open(path)?;
30
31 #[cfg(unix)]
32 {
33 use std::os::unix::fs::PermissionsExt;
34 let _ = std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o600));
35 }
36
37 conn.pragma_update(None, "journal_mode", "wal")?;
39 conn.pragma_update(None, "foreign_keys", "on")?;
40 conn.pragma_update(None, "busy_timeout", 5000)?;
41 conn.pragma_update(None, "synchronous", "normal")?;
43
44 let _ = conn.execute_batch("PRAGMA wal_checkpoint(PASSIVE)");
48
49 schema::create_tables(&conn)?;
50
51 Ok(Self { conn })
52 }
53
54 pub fn open_default() -> Result<Self, DbError> {
56 Self::open(&config::db_path())
57 }
58}