X-Git-Url: http://git.euphorik.ch/?p=recipes.git;a=blobdiff_plain;f=backend%2Fsrc%2Fdb.rs;fp=backend%2Fsrc%2Fdb.rs;h=2bf383b4e395c49550c58689a316a6cfe79adbbe;hp=1d38a454f03091e1d1020f1a19001919494aef8b;hb=cdb883c3c4ccbb82774ecfbfad059f3392e75432;hpb=4fbc599d074180920b20ee46e80cc0d3669a4129 diff --git a/backend/src/db.rs b/backend/src/db.rs index 1d38a45..2bf383b 100644 --- a/backend/src/db.rs +++ b/backend/src/db.rs @@ -1,14 +1,14 @@ -use crate::consts::SQL_FILENAME; - -use super::consts; - 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)] @@ -19,30 +19,28 @@ pub enum DBError { Other(String), } -pub struct Connection { - //con: rusqlite::Connection - pool: Pool -} - -pub struct Recipe { - pub title: String, - pub id: i32, -} - -impl std::convert::From for DBError { +impl From for DBError { fn from(error: rusqlite::Error) -> Self { DBError::SqliteError(error) } } -impl std::convert::From for DBError { +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 { + pub fn new() -> Result { let data_dir = Path::new(consts::DB_DIRECTORY); @@ -62,11 +60,7 @@ impl 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: &Self) -> Result<(), DBError> { - // let connection = Connection::new(); - // let mut stmt = connection.sqlite_con.prepare("SELECT * FROM versions ORDER BY date").unwrap(); - // let mut stmt = connection.sqlite_con.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='versions'").unwrap(); - + fn create_or_update(&self) -> Result<()> { // Check the Database version. let mut con = self.pool.get()?; let tx = con.transaction()?; @@ -78,7 +72,7 @@ impl Connection { [], |row| row.get::(0) ) { - Ok(_) => tx.query_row("SELECT [version] FROM [Version]", [], |row| row.get(0)).unwrap_or_default(), + Ok(_) => tx.query_row("SELECT [version] FROM [Version] ORDER BY [id] DESC", [], |row| row.get(0)).unwrap_or_default(), Err(_) => 0 } }; @@ -92,14 +86,18 @@ impl Connection { Ok(()) } - fn update_to_next_version(current_version: u32, tx: &rusqlite::Transaction) -> Result { + 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 ok(updated: bool) -> Result { + 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"); } @@ -109,6 +107,7 @@ impl Connection { match next_version { 1 => { tx.execute_batch(&load_sql_file(next_version)?)?; + update_version(next_version, tx)?; ok(true) } @@ -122,13 +121,36 @@ impl Connection { } } - pub fn get_all_recipes() { + 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 = SQL_FILENAME.replace("{VERSION}", &version.to_string()); +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())))?;