freeroast 0.1.9

A simple coffee roasting app
Documentation
//!
//! Implements database functionality for roast objects
//!
use crate::{Bean, Roast};
use chrono::NaiveDateTime;
use rusqlite::{params, Connection, Result};
use uuid::Uuid;

///
/// Database methods for roast struct
///
impl Roast {
    pub fn new(bean: Bean) -> Self {
        let now = chrono::Utc::now().naive_utc();

        assert!(bean.amount_in_stock > 0.0);

        Roast {
            id: Uuid::new_v4().to_string(),
            bean,
            starting_weight: 0.000,
            beans_in: now,
            first_crack_start: now,
            first_crack_finish: now,
            second_crack_start: None,
            second_crack_finish: None,
            beans_out: now,
        }
    }

    ///
    /// Insert new roast into database
    ///
    pub fn insert(&mut self, conn: &mut Connection) -> Result<()> {
        // Begin database transaction
        let tx = conn.transaction()?;

        // Prepare query
        let mut qry = tx.prepare(
            r#"
                INSERT INTO roasts (
                    id, 
                    bean_name, 
                    starting_weight,
                    beans_in, 
                    first_crack_start, 
                    first_crack_finish, 
                    second_crack_start, 
                    second_crack_finish, 
                    beans_out)
                VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9);

            "#,
        )?;

        // Execute query with variables
        qry.execute(params![
            self.id,
            self.bean.bean_nickname,
            self.starting_weight,
            self.beans_in.timestamp_millis(),
            self.first_crack_start.timestamp_millis(),
            self.first_crack_finish.timestamp_millis(),
            match self.second_crack_start {
                Some(scs) => {
                    Some(scs.timestamp_millis())
                }
                None => None,
            },
            match self.second_crack_finish {
                Some(scf) => {
                    Some(scf.timestamp_millis())
                }
                None => None,
            },
            self.beans_out.timestamp_millis(),
        ])?;

        qry.finalize()?;

        // Update stock in database
        tx.execute(
            r#"
                UPDATE beans 
                SET amount_in_stock = ?1 - ?2
                WHERE bean_nickname = ?3;
            "#,
            params![
                self.bean.amount_in_stock,
                self.starting_weight,
                self.bean.bean_nickname,
            ],
        )?;

        // Commit to database
        tx.commit()?;

        self.bean.amount_in_stock -= self.starting_weight;

        Ok(())
    }

    ///
    /// Delete roast from database
    ///
    pub fn delete(&self, conn: &mut Connection) -> Result<()> {
        conn.execute(
            r#"DELETE FROM roasts WHERE ?1 like "id";"#,
            params![self.id],
        )
        .expect("Problem deleting roast");
        Ok(())
    }
}

///
/// Returns vector containing all roasts in database
///
pub fn get_all_roasts(conn: &mut Connection) -> Result<Vec<Roast>> {
    let mut roasts: Vec<Roast> = Vec::new();
    let mut qry = conn.prepare("SELECT * FROM roasts;")?;
    let rows = qry.query_map([], |row| {
        let mut bean = Bean::default();
        bean.bean_nickname = row.get(1)?;

        let roast = Roast {
            id: row.get(0)?,
            bean,
            starting_weight: row.get(2)?,
            beans_in: NaiveDateTime::from_timestamp_millis(row.get(3)?).unwrap(),
            first_crack_start: NaiveDateTime::from_timestamp_millis(row.get(4)?).unwrap(),
            first_crack_finish: NaiveDateTime::from_timestamp_millis(row.get(5)?).unwrap(),
            second_crack_start: match row.get(6) {
                Err(_) => None,
                Ok(ts) => Some(NaiveDateTime::from_timestamp_millis(ts).unwrap()),
            },
            second_crack_finish: match row.get(7) {
                Err(_) => None,
                Ok(ts) => Some(NaiveDateTime::from_timestamp_millis(ts).unwrap()),
            },
            beans_out: NaiveDateTime::from_timestamp_millis(row.get(8)?).unwrap(),
        };
        roasts.append(&mut vec![roast]);
        Ok(())
    })?;

    for i in rows {
        i.unwrap();
    }

    drop(qry);

    // Get the roasts bean data
    roasts.iter_mut().for_each(|i| {
        i.bean.get(conn).unwrap();
    });

    return Ok(roasts);
}