use crate::word::Word; use derive_more::From; use rusqlite::{params, Connection, Result}; use std::path::PathBuf; pub struct Database { conn: Connection, pub last_word_id: i64, } #[derive(From, Debug)] pub enum DatabaseCreationError { RusqliteError(rusqlite::Error), IoError(std::io::Error), } #[derive(Default)] pub enum DatabaseType { #[default] InMemory, OnDisk(String), } #[derive(Default)] pub struct DatabaseSettings { pub db_type: DatabaseType, } impl Database { pub fn new(settings: DatabaseSettings) -> Result { let conn = match settings.db_type { DatabaseType::InMemory => Connection::open_in_memory(), DatabaseType::OnDisk(path) => Connection::open(PathBuf::from(path)), }?; conn.execute( "CREATE TABLE IF NOT EXISTS word ( id INTEGER PRIMARY KEY, word TEXT, reading TEXT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP )", params![], )?; let last_word_id = match conn .prepare("SELECT id FROM word ORDER BY id DESC LIMIT 1")? .query_map(params![], |row| row.get(0))? .collect::>>()? .first() { Some(id) => *id, None => 0, // first database entry is id 1 }; Ok(Self { conn, last_word_id }) } pub fn load_words_before(&self, before_id: i64) -> Result> { self.conn .prepare("SELECT id, word, reading, timestamp FROM word WHERE id < ? ORDER BY id DESC LIMIT 10")? .query_map(params![before_id], |row| { Ok(Word { id: row.get(0)?, word: row.get(1)?, reading: row.get(2)?, timestamp: row.get(3)?, }) })? .collect::>>() } pub fn add_word(&mut self, word: &Word) -> Result<()> { self.conn.execute( "INSERT INTO word (word, reading) VALUES (?1, ?2)", params![word.word, word.reading,], )?; self.last_word_id += 1; Ok(()) } }