Add some data access methods to Connection
This commit is contained in:
parent
4fbc599d07
commit
cdb883c3c4
6 changed files with 180 additions and 114 deletions
|
|
@ -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<SqliteConnectionManager>
|
||||
}
|
||||
|
||||
pub struct Recipe {
|
||||
pub title: String,
|
||||
pub id: i32,
|
||||
}
|
||||
|
||||
impl std::convert::From<rusqlite::Error> for DBError {
|
||||
impl From<rusqlite::Error> for DBError {
|
||||
fn from(error: rusqlite::Error) -> Self {
|
||||
DBError::SqliteError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<r2d2::Error> for DBError {
|
||||
impl From<r2d2::Error> for DBError {
|
||||
fn from(error: r2d2::Error) -> Self {
|
||||
DBError::R2d2Error(error)
|
||||
}
|
||||
}
|
||||
|
||||
type Result<T> = std::result::Result<T, DBError>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Connection {
|
||||
//con: rusqlite::Connection
|
||||
pool: Pool<SqliteConnectionManager>
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
pub fn new() -> Result<Connection, DBError> {
|
||||
pub fn new() -> Result<Connection> {
|
||||
|
||||
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::<usize, String>(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<bool, DBError> {
|
||||
fn update_to_next_version(current_version: u32, tx: &rusqlite::Transaction) -> Result<bool> {
|
||||
let next_version = current_version + 1;
|
||||
|
||||
if next_version <= CURRENT_DB_VERSION {
|
||||
println!("Update to version {}...", next_version);
|
||||
}
|
||||
|
||||
fn ok(updated: bool) -> Result<bool, DBError> {
|
||||
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<bool> {
|
||||
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<Vec<(i32, String)>> {
|
||||
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<Vec<model::Recipe>> {
|
||||
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<model::Recipe> {
|
||||
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<String, DBError> {
|
||||
let sql_file = SQL_FILENAME.replace("{VERSION}", &version.to_string());
|
||||
fn load_sql_file(version: u32) -> Result<String> {
|
||||
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())))?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue