use rusqlite::{Connection, params, Result, Row, Transaction}; use crate::securities::Security; use crate::users::User; pub struct Account { id: i64, amount: i64, timestamp: i64, } fn _account_from_row(row: &Row) -> Result { return Ok(Account{ id: row.get(0)?, amount: row.get(1)?, timestamp: row.get(2)?, }); } pub fn list_accounts<'a>(conn: &Connection) -> Result> { let q = "SELECT id, amount, UNIXEPOCH(timestamp) FROM accounts ORDER BY id ASC"; let mut stmt = conn.prepare(q)?; let ret: Vec = stmt .query_map([], &_account_from_row)? .filter(Result::is_ok) .map(Result::unwrap) .collect(); return Ok(ret); } pub fn get_account_by_id(tx: &Transaction, id: u32) -> Result{ let q = "SELECT id, amount, UNIXEPOCH(timestamp) FROM accounts WHERE id = ?1"; return tx.query_row(q, params![id], _account_from_row); } pub fn create_account(tx: &Transaction, sec: &Security, user: &User) -> Result{ let q = "INSERT INTO accounts(security, owner, amount, timestamp) VALUES (?1, ?2, 0, CURRENT_TIMESTAMP)"; tx.execute(q, (sec.id, user.id))?; return get_account_by_id(tx, tx.last_insert_rowid() as u32); } #[cfg(test)] mod test { use rusqlite::{Connection}; use crate::users; use crate::securities; use crate::migration; use super::*; fn setup_users(tx: &Transaction) -> Result> { let user_1 = users::create_user(tx, &"bernard".to_string(), &"123".to_string())?; let user_2 = users::create_user(tx, &"sam".to_string(), &"abc".to_string())?; return Ok(vec![user_1, user_2]); } fn setup_securities(tx: &Transaction) -> Result> { let sec_1 = securities::create_security(tx, &securities::test_util::mock_currency_1())?; let sec_2 = securities::create_security(tx, &securities::test_util::mock_currency_2())?; return Ok(vec![sec_1, sec_2]); } fn setup() -> (Connection, Vec, Vec) { let mut conn = Connection::open_in_memory().unwrap(); migration::apply_migrations(&mut conn).unwrap(); let tx = conn.transaction().unwrap(); let users = setup_users(&tx).unwrap(); let securities = setup_securities(&tx).unwrap(); tx.commit().unwrap(); return (conn, users, securities); } fn create_all_accounts(tx: & Transaction, users: & Vec, secs: & Vec) -> Result<()>{ for sec in secs.iter() { for user in users.iter() { create_account(&tx, sec, user)?; } } return Ok(()); } #[test] fn test_happy_path() -> Result<()>{ let (mut conn, users, secs) = setup(); let tx = conn.transaction()?; create_all_accounts(& tx, &users, &secs)?; tx.commit()?; let accs = list_accounts(& conn)?; assert_eq!(4, accs.len()); assert_eq!(1, accs.get(0).unwrap().id); assert_eq!(4, accs.get(3).unwrap().id); return Ok(()); } #[test] fn test_happy_path_no_commit() -> Result<()>{ let (mut conn, users, secs) = setup(); create_all_accounts(& conn.transaction()?, &users, &secs)?; let accs = list_accounts(& conn)?; assert_eq!(0, accs.len()); return Ok(()); } }