diff --git a/src/data_layer.rs b/src/data_layer.rs index 4c89efe..52b5d6e 100644 --- a/src/data_layer.rs +++ b/src/data_layer.rs @@ -1,4 +1,5 @@ use crate::entities::*; +use chrono::DateTime; use sqlite::{Connection, State}; pub fn setup(con: &Connection) { @@ -20,7 +21,7 @@ pub fn setup(con: &Connection) { account_id INTEGER NOT NULL, type_id INTEGER NOT NULL, amount FLOAT NOT NULL, - date DATE NOT NULL, + date INTEGER NOT NULL, description TEXT, FOREIGN KEY(account_id) REFERENCES Accounts(id), FOREIGN KEY(type_id) REFERENCES TransactionTypes(id) @@ -150,3 +151,106 @@ pub fn get_transaction_types(con: &Connection) -> Vec { return vec; } + +pub fn upsert_transaction(con: &Connection, tr: Transaction) -> Transaction { + let query; + if tr.get_id() == 0 { + query = "INSERT INTO Transactions + (account_id, type_id, amount, date, description) + VALUES (?, ?, ?, ?, ?) + RETURNING id;"; + } else { + query = "UPDATE Transactions + SET account_id = ?, type_id = ?, amount = ?, date = ?, description = ? + WHERE id = ? RETURNING id;"; + } + + let mut statement = con.prepare(query).unwrap(); + statement.bind((1, tr.get_account().get_id())).unwrap(); + statement.bind((2, tr.get_type().get_id())).unwrap(); + statement.bind((3, tr.get_amount())).unwrap(); + statement.bind((4, tr.get_date().timestamp())).unwrap(); + statement.bind((5, &tr.get_desc() as &str)).unwrap(); + + if tr.get_id() != 0 { + statement.bind((6, tr.get_id())).unwrap(); + } + + let id; + if let Ok(State::Row) = statement.next() { + id = statement.read::("id").unwrap(); + } else { + id = 0; + } + + return Transaction::new( + id, + tr.get_account().get_id(), + tr.get_amount(), + tr.get_date(), + tr.get_desc(), + tr.get_type().get_id(), + con, + ); +} + +pub fn get_transaction(con: &Connection, id: i64) -> Transaction { + let query = "SELECT * FROM Transactions WHERE id = ?"; + let mut statement = con.prepare(query).unwrap(); + statement.bind((1, id)).unwrap(); + + if let Ok(State::Row) = statement.next() { + return Transaction::new( + statement.read::("id").unwrap(), + statement.read::("account_id").unwrap(), + statement.read::("amount").unwrap(), + DateTime::from_timestamp(statement.read::("date").unwrap(), 0).unwrap(), + statement.read::("description").unwrap(), + statement.read::("type_id").unwrap(), + con, + ); + } else { + return Transaction::new_empty(); + } +} + +pub fn get_account_transactions(con: &Connection, ac_id: i64) -> Vec { + let query = "SELECT * FROM Transactions WHERE account_id = ?"; + let mut statement = con.prepare(query).unwrap(); + statement.bind((1, ac_id)).unwrap(); + let mut vec = Vec::::new(); + + while let Ok(State::Row) = statement.next() { + vec.push(Transaction::new( + statement.read::("id").unwrap(), + statement.read::("account_id").unwrap(), + statement.read::("amount").unwrap(), + DateTime::from_timestamp(statement.read::("date").unwrap(), 0).unwrap(), + statement.read::("description").unwrap(), + statement.read::("type_id").unwrap(), + con, + )); + } + + return vec; +} + +pub fn get_transactions(con: &Connection) -> Vec { + let query = "SELECT * FROM TransactionTypes"; + let mut statement = con.prepare(query).unwrap(); + let mut vec = Vec::::new(); + + while let Ok(State::Row) = statement.next() { + vec.push(Transaction::new( + statement.read::("id").unwrap(), + statement.read::("account_id").unwrap(), + statement.read::("amount").unwrap(), + DateTime::from_timestamp(statement.read::("date").unwrap(), 0).unwrap(), + statement.read::("description").unwrap(), + statement.read::("type_id").unwrap(), + con, + )); + } + + return vec; +} diff --git a/src/entities/transaction.rs b/src/entities/transaction.rs index 4c54b6f..f8c6f06 100644 --- a/src/entities/transaction.rs +++ b/src/entities/transaction.rs @@ -36,6 +36,19 @@ impl Transaction { } } + pub fn new_empty() -> Self { + Transaction { + id: 0, + account_id: 0, + amount: 0.0, + date: DateTime::from_timestamp(0, 0).unwrap(), + description: "".to_string(), + type_id: 0, + account: Account::new(0, "".to_string(), super::AccountType::Cash), + tr_type: TransactionType::new(0, "".to_string()), + } + } + pub fn get_id(&self) -> i64 { return self.id; } diff --git a/src/main.rs b/src/main.rs index 521a045..5955fd4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,10 @@ mod data_layer; mod entities; +use chrono::DateTime; use sqlite::Connection; use std::io; -use crate::entities::{Account, TransactionType}; +use crate::entities::{Account, Transaction, TransactionType}; fn main() { let connection = match Connection::open("ft_rs.db") { @@ -22,6 +23,8 @@ fn main() { println!("2. Add an account"); println!("3. List transaction types"); println!("4. Add a transaction type"); + println!("5. List transactions"); + println!("6. Add a transaction"); println!("0. Exit"); let mut choice = String::new(); @@ -64,12 +67,74 @@ fn main() { let tr_type = TransactionType::new(0, desc.to_string()); data_layer::upsert_transaction_type(&connection, tr_type); } + "5" => { + println!("Please enter the account id:"); + let mut ac_id_str = String::new(); + io::stdin() + .read_line(&mut ac_id_str) + .expect("Failed to read line"); + ac_id_str = ac_id_str.trim().to_string(); + let ac_id = ac_id_str.parse::().unwrap(); + let trx: Vec = + data_layer::get_account_transactions(&connection, ac_id); + // .sort_by(|a, b| b.get_date().cmp(&a.get_date())) + // .try_into() + // .unwrap(); + for t in trx.iter() { + println!( + "Date: {}, Type: {}, Description: {}, Amount: {}$", + t.get_date(), + t.get_type().get_description(), + t.get_desc(), + t.get_amount() + ); + } + } + "6" => { + println!("Please enter the account id:"); + let mut ac_id_str = String::new(); + io::stdin() + .read_line(&mut ac_id_str) + .expect("Failed to read line"); + ac_id_str = ac_id_str.trim().to_string(); + let ac_id = ac_id_str.parse::().unwrap(); + println!("Please enter the transaction type id:"); + let mut tr_type_id_str = String::new(); + io::stdin() + .read_line(&mut tr_type_id_str) + .expect("Failed to read line"); + tr_type_id_str = tr_type_id_str.trim().to_string(); + let type_id = tr_type_id_str.parse::().unwrap(); + println!("Please enter the amount:"); + let mut amnt_str = String::new(); + io::stdin() + .read_line(&mut amnt_str) + .expect("Failed to read line"); + amnt_str = amnt_str.trim().to_string(); + let amount = amnt_str.parse::().unwrap(); + println!("Please enter the description:"); + let mut desc = String::new(); + io::stdin() + .read_line(&mut desc) + .expect("Failed to read line"); + desc = desc.trim().to_string(); + let tr = Transaction::new( + 0, + ac_id, + amount, + chrono::offset::Utc::now(), + desc, + type_id, + &connection, + ); + data_layer::upsert_transaction(&connection, tr); + } "0" => { println!("Exiting..."); break; // Exit the loop } _ => { - println!("Invalid choice. Please enter 1, 2, or 3."); + println!("Invalid choice."); } } }