X-Git-Url: http://git.euphorik.ch/?a=blobdiff_plain;f=backend%2Fsrc%2Fdb.rs;h=6458c7eb7308d384a695f7af38893d0c0e2fb821;hb=HEAD;hp=2bf383b4e395c49550c58689a316a6cfe79adbbe;hpb=cdb883c3c4ccbb82774ecfbfad059f3392e75432;p=recipes.git diff --git a/backend/src/db.rs b/backend/src/db.rs deleted file mode 100644 index 2bf383b..0000000 --- a/backend/src/db.rs +++ /dev/null @@ -1,158 +0,0 @@ -use std::{fs::{self, File}, path::Path, io::Read}; - -use itertools::Itertools; -//use rusqlite::types::ToSql; -//use rusqlite::{Connection, Result, NO_PARAMS}; -use r2d2::Pool; -use r2d2_sqlite::SqliteConnectionManager; - -use crate::consts; -use crate::model; - -const CURRENT_DB_VERSION: u32 = 1; - -#[derive(Debug)] -pub enum DBError { - SqliteError(rusqlite::Error), - R2d2Error(r2d2::Error), - UnsupportedVersion(u32), - Other(String), -} - -impl From for DBError { - fn from(error: rusqlite::Error) -> Self { - DBError::SqliteError(error) - } -} - -impl From for DBError { - fn from(error: r2d2::Error) -> Self { - DBError::R2d2Error(error) - } -} - -type Result = std::result::Result; - -#[derive(Clone)] -pub struct Connection { - //con: rusqlite::Connection - pool: Pool -} - -impl Connection { - pub fn new() -> Result { - - let data_dir = Path::new(consts::DB_DIRECTORY); - - if !data_dir.exists() { - fs::DirBuilder::new().create(data_dir).unwrap(); - } - - let manager = SqliteConnectionManager::file(consts::DB_FILENAME); - let pool = r2d2::Pool::new(manager).unwrap(); - - let connection = Connection { pool }; - connection.create_or_update()?; - Ok(connection) - } - - /* - * Called after the connection has been established for creating or updating the database. - * The 'Version' table tracks the current state of the database. - */ - fn create_or_update(&self) -> Result<()> { - // Check the Database version. - let mut con = self.pool.get()?; - let tx = con.transaction()?; - - // Version 0 corresponds to an empty database. - let mut version = { - match tx.query_row( - "SELECT [name] FROM [sqlite_master] WHERE [type] = 'table' AND [name] = 'Version'", - [], - |row| row.get::(0) - ) { - Ok(_) => tx.query_row("SELECT [version] FROM [Version] ORDER BY [id] DESC", [], |row| row.get(0)).unwrap_or_default(), - Err(_) => 0 - } - }; - - while Connection::update_to_next_version(version, &tx)? { - version += 1; - } - - tx.commit()?; - - Ok(()) - } - - fn update_to_next_version(current_version: u32, tx: &rusqlite::Transaction) -> Result { - let next_version = current_version + 1; - - if next_version <= CURRENT_DB_VERSION { - println!("Update to version {}...", next_version); - } - - fn update_version(to_version: u32, tx: &rusqlite::Transaction) -> Result<()> { - tx.execute("INSERT INTO [Version] ([version], [datetime]) VALUES (?1, datetime('now'))", [to_version]).map(|_| ()).map_err(DBError::from) - } - - fn ok(updated: bool) -> Result { - if updated { - println!("Version updated"); - } - Ok(updated) - } - - match next_version { - 1 => { - tx.execute_batch(&load_sql_file(next_version)?)?; - update_version(next_version, tx)?; - - ok(true) - } - - // Version 1 doesn't exist yet. - 2 => - ok(false), - - v => - Err(DBError::UnsupportedVersion(v)), - } - } - - pub fn get_all_recipe_titles(&self) -> Result> { - let con = self.pool.get()?; - let mut stmt = con.prepare("SELECT [id], [title] FROM [Recipe] ORDER BY [title]")?; - let titles = - stmt.query_map([], |row| { - Ok((row.get(0)?, row.get(1)?)) - })?.map(|r| r.unwrap()).collect_vec(); // TODO: remove unwrap. - Ok(titles) - } - - pub fn get_all_recipes(&self) -> Result> { - let con = self.pool.get()?; - let mut stmt = con.prepare("SELECT [id], [title] FROM [Recipe] ORDER BY [title]")?; - let recipes = - stmt.query_map([], |row| { - Ok(model::Recipe::new(row.get(0)?, row.get(1)?)) - })?.map(|r| r.unwrap()).collect_vec(); // TODO: remove unwrap. - Ok(recipes) - } - - pub fn get_recipe(&self, id: i32) -> Result { - let con = self.pool.get()?; - con.query_row("SELECT [id], [title] FROM [Recipe] WHERE [id] = ?1", [id], |row| { - Ok(model::Recipe::new(row.get(0)?, row.get(1)?)) - }).map_err(DBError::from) - } -} - -fn load_sql_file(version: u32) -> Result { - let sql_file = consts::SQL_FILENAME.replace("{VERSION}", &version.to_string()); - let mut file = File::open(&sql_file).map_err(|err| DBError::Other(format!("Cannot open SQL file ({}): {}", &sql_file, err.to_string())))?; - let mut sql = String::new(); - file.read_to_string(&mut sql).map_err(|err| DBError::Other(format!("Cannot read SQL file ({}) : {}", &sql_file, err.to_string())))?; - Ok(sql) -} \ No newline at end of file