use anyhow::Result; use rusqlite::{Connection, Transaction, config::DbConfig}; pub const DB_NAME: &str = "database.sqlite"; const DB_VERSION: i64 = 0; pub struct Database { conn: Connection, } impl Database { pub fn new(db_file: &str) -> Result { let mut init = false; if !std::fs::exists(db_file)? { init = true; } let mut db = Database { conn: Connection::open(db_file)?, }; if init { db.initialize()?; } db.conn.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_FKEY)?; Ok(db) } fn initialize(&mut self) -> Result<()> { let tx = self.conn.transaction()?; let mut q = "CREATE TABLE version ( version INTEGER NOT NULL, UNIQUE (version))"; tx.execute(q, ())?; q = "INSERT INTO version VALUES (?)"; tx.execute(q, [&DB_VERSION])?; q = "CREATE TABLE user ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, email TEXT NOT NULL, UNIQUE (email))"; tx.execute(q, ())?; q = "CREATE TABLE list ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, description TEXT, UNIQUE (name))"; tx.execute(q, ())?; q = "CREATE TABLE subscription ( user_id INTEGER REFERENCES user (id), list_id INTEGER REFERENCES list (id), UNIQUE (user_id, list_id))"; tx.execute(q, ())?; q = "CREATE TABLE queue ( id INTEGER PRIMARY KEY AUTOINCREMENT, from_ TEXT NOT NULL, recipient TEXT NOT NULL, data BLOB NOT NULL)"; tx.execute(q, ())?; tx.commit()?; Ok(()) } pub fn execute(&mut self, q: Ex) -> Result> where Ex: Query, { let tx = self.conn.transaction()?; let ris = q.callback(&tx)?; tx.commit()?; Ok(ris) } } pub trait Query { type T; fn callback(&self, tx: &Transaction) -> Result>; } #[derive(Debug)] pub enum QueryResult { Empty, Single(T), Vec(Vec), }