use anyhow::Result; use rusqlite::{Connection, Transaction, config::DbConfig}; const DB_NAME: &str = "database.sqlite"; const DB_VERSION: i64 = 0; struct Database { conn: Connection, } impl Database { fn new() -> Result { let mut init = false; if !std::fs::exists(DB_NAME)? { init = true; } let mut db = Database { conn: Connection::open(DB_NAME)?, }; 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, ())?; tx.commit()?; Ok(()) } fn execute(&mut self, q: Ex) -> Result> where Ex: DBExecutable { let tx = self.conn.transaction()?; let ris = q.execute(&tx)?; tx.commit()?; Ok(ris) } } pub trait DBExecutable { type T; fn execute(&self, tx: &Transaction) -> Result>; } pub enum QueryResult { Empty, Vec(Vec) }