diff --git a/databases/mysql/src/models.rs b/databases/mysql/src/models.rs index 155b78c..1be719d 100644 --- a/databases/mysql/src/models.rs +++ b/databases/mysql/src/models.rs @@ -24,12 +24,6 @@ pub struct CustomerData { pub branch_name: String, } -#[derive(Debug, Serialize)] -pub struct ResponseStatus { - pub status_code: u8, - pub status_description: String, -} - #[derive(Debug, Serialize)] pub struct BankDetails { pub bank_name: String, @@ -38,8 +32,6 @@ pub struct BankDetails { #[derive(Debug, Serialize)] pub struct BankResponseData { - pub status_code: u8, - pub status_description: String, pub bank_data: Vec, } @@ -51,8 +43,6 @@ pub struct BranchDetails { #[derive(Debug, Serialize)] pub struct BranchResponseData { - pub status_code: u8, - pub status_description: String, pub branch_data: Vec, } @@ -64,8 +54,6 @@ pub struct TellerDetails { #[derive(Debug, Serialize)] pub struct TellerResponseData { - pub status_code: u8, - pub status_description: String, pub teller_data: Vec, } @@ -77,7 +65,5 @@ pub struct CustomerDetails { #[derive(Debug, Serialize)] pub struct CustomerResponseData { - pub status_code: u8, - pub status_description: String, pub customer_data: Vec, } diff --git a/databases/mysql/src/persistence.rs b/databases/mysql/src/persistence.rs index 6153e77..7c8e9f4 100644 --- a/databases/mysql/src/persistence.rs +++ b/databases/mysql/src/persistence.rs @@ -1,13 +1,12 @@ +use actix_web::http::StatusCode; use derive_more::{Display, Error, From}; use mysql::{params, prelude::*}; use crate::models::{ BankDetails, BankResponseData, BranchDetails, BranchResponseData, CustomerDetails, - CustomerResponseData, ResponseStatus, TellerDetails, TellerResponseData, + CustomerResponseData, TellerDetails, TellerResponseData, }; -const ERROR_MESSAGE: &str = "Error occurred during processing, please try again."; - #[derive(Debug, Display, Error, From)] pub enum PersistenceError { EmptyBankName, @@ -16,12 +15,28 @@ pub enum PersistenceError { EmptyLocation, EmptyTellerName, EmptyCustomerName, + MysqlError(mysql::Error), Unknown, } -impl actix_web::ResponseError for PersistenceError {} +impl actix_web::ResponseError for PersistenceError { + fn status_code(&self) -> StatusCode { + match self { + PersistenceError::EmptyBankName + | PersistenceError::EmptyCountry + | PersistenceError::EmptyBranch + | PersistenceError::EmptyLocation + | PersistenceError::EmptyTellerName + | PersistenceError::EmptyCustomerName => StatusCode::BAD_REQUEST, + + PersistenceError::MysqlError(_) | PersistenceError::Unknown => { + StatusCode::INTERNAL_SERVER_ERROR + } + } + } +} pub fn create_bank( pool: &mysql::Pool, @@ -38,246 +53,143 @@ pub fn create_bank( let mut conn = pool.get_conn()?; - let rows_inserted = + let last_insert_id = insert_bank_data(&mut conn, bank_name.to_lowercase(), country.to_lowercase())?; - if rows_inserted > 0 { - return Ok(()); + if last_insert_id > 0 { + Ok(()) } else { Err(PersistenceError::Unknown) } } -pub fn create_branch(pool: &mysql::Pool, branch_name: String, location: String) -> ResponseStatus { - let my_status_code: u8 = 1; - let my_status_description = ERROR_MESSAGE.to_owned(); - - let mut response_status = ResponseStatus { - status_code: my_status_code, - status_description: my_status_description, - }; - +pub fn create_branch( + pool: &mysql::Pool, + branch_name: String, + location: String, +) -> Result<(), PersistenceError> { if branch_name.replace(' ', "").trim().is_empty() { - response_status.status_description = String::from("Branch name is empty!"); - return response_status; + return Err(PersistenceError::EmptyBranch); } if location.replace(' ', "").trim().is_empty() { - response_status.status_description = String::from("Location is empty!"); - return response_status; + return Err(PersistenceError::EmptyLocation); } - match pool.get_conn().and_then(|mut conn| { - insert_branch_data( - &mut conn, - branch_name.to_lowercase(), - location.to_lowercase(), - ) - }) { - Ok(x) => { - if x > 0 { - response_status.status_code = 0; - response_status.status_description = "Successful".to_owned(); - } - } - Err(err) => println!("Failed to open DB connection. create_branch {err:?}"), - } + let mut conn = pool.get_conn()?; - response_status + let last_insert_id = insert_branch_data( + &mut conn, + branch_name.to_lowercase(), + location.to_lowercase(), + )?; + + if last_insert_id > 0 { + Ok(()) + } else { + Err(PersistenceError::Unknown) + } } pub fn create_teller( pool: &mysql::Pool, teller_name: String, branch_name: String, -) -> ResponseStatus { - let my_status_code: u8 = 1; - let my_status_description = ERROR_MESSAGE.to_owned(); - - let mut response_status = ResponseStatus { - status_code: my_status_code, - status_description: my_status_description, - }; - +) -> Result<(), PersistenceError> { if teller_name.replace(' ', "").trim().is_empty() { - response_status.status_description = String::from("Teller name is empty!"); - return response_status; + return Err(PersistenceError::EmptyTellerName); } if branch_name.replace(' ', "").trim().is_empty() { - response_status.status_description = String::from("Branch name is empty!"); - return response_status; + return Err(PersistenceError::EmptyBranch); } - match pool.get_conn().and_then(|mut conn| { - insert_teller_data( - &mut conn, - teller_name.to_lowercase(), - branch_name.to_lowercase(), - ) - }) { - Ok(x) => { - if x > 0 { - response_status.status_code = 0; - response_status.status_description = "Successful".to_owned(); - } - } - Err(err) => println!("Failed to open DB connection. create_teller {err:?}"), - } + let mut conn = pool.get_conn()?; - response_status + let last_insert_id = insert_teller_data( + &mut conn, + teller_name.to_lowercase(), + branch_name.to_lowercase(), + )?; + + if last_insert_id > 0 { + Ok(()) + } else { + Err(PersistenceError::Unknown) + } } pub fn create_customer( pool: &mysql::Pool, customer_name: String, branch_name: String, -) -> ResponseStatus { - let my_status_code: u8 = 1; - let my_status_description = ERROR_MESSAGE.to_owned(); - - let mut response_status = ResponseStatus { - status_code: my_status_code, - status_description: my_status_description, - }; - +) -> Result<(), PersistenceError> { if customer_name.replace(' ', "").trim().is_empty() { - response_status.status_description = String::from("Customer name is empty!"); - return response_status; + return Err(PersistenceError::EmptyCustomerName); } if branch_name.replace(' ', "").trim().is_empty() { - response_status.status_description = String::from("Branch name is empty!"); - return response_status; + return Err(PersistenceError::EmptyBranch); } - match pool.get_conn().and_then(|mut conn| { - insert_customer_data( - &mut conn, - customer_name.to_lowercase(), - branch_name.to_lowercase(), - ) - }) { - Ok(x) => { - if x > 0 { - response_status.status_code = 0; - response_status.status_description = "Successful".to_owned(); - } - } - Err(err) => println!("Failed to open DB connection. create_customer {err:?}"), - } + let mut conn = pool.get_conn()?; - response_status -} + let last_insert_id = insert_customer_data( + &mut conn, + customer_name.to_lowercase(), + branch_name.to_lowercase(), + )?; -pub fn get_bank_data(pool: &mysql::Pool) -> BankResponseData { - let mut vec_bank_data = Vec::new(); - let mut my_status_code = 1_u8; - let mut my_status_description: String = String::from("Record not found"); - - match pool - .get_conn() - .and_then(|mut conn| select_bank_details(&mut conn)) - { - Ok(data) => vec_bank_data = data, - Err(err) => println!("Failed to open DB connection. {err:?}"), - } - - if !vec_bank_data.is_empty() { - my_status_code = 0; - my_status_description = "Successful".to_owned(); - } - - BankResponseData { - status_code: my_status_code, - status_description: my_status_description, - bank_data: vec_bank_data, + if last_insert_id > 0 { + Ok(()) + } else { + Err(PersistenceError::Unknown) } } -pub fn get_branch_data(pool: &mysql::Pool) -> BranchResponseData { - let mut vec_branch_data = Vec::new(); - let mut my_status_code = 1_u8; - let mut my_status_description: String = String::from("Record not found"); +pub fn get_bank_data(pool: &mysql::Pool) -> Result { + let mut conn = pool.get_conn()?; - match pool - .get_conn() - .and_then(|mut conn| select_branch_details(&mut conn)) - { - Ok(data) => vec_branch_data = data, - Err(err) => println!("Failed to open DB connection. {err:?}"), - } - - if !vec_branch_data.is_empty() { - my_status_code = 0; - my_status_description = "Successful".to_owned(); - } - - BranchResponseData { - status_code: my_status_code, - status_description: my_status_description, - branch_data: vec_branch_data, - } + Ok(BankResponseData { + bank_data: select_bank_details(&mut conn)?, + }) } -pub fn get_teller_data(pool: &mysql::Pool) -> TellerResponseData { - let mut vec_teller_data = Vec::new(); - let mut my_status_code = 1_u8; - let mut my_status_description: String = String::from("Record not found"); +pub fn get_branch_data(pool: &mysql::Pool) -> Result { + let mut conn = pool.get_conn()?; - match pool - .get_conn() - .and_then(|mut conn| select_teller_details(&mut conn)) - { - Ok(data) => vec_teller_data = data, - Err(err) => println!("Failed to open DB connection. {err:?}"), - } - - if !vec_teller_data.is_empty() { - my_status_code = 0; - my_status_description = "Successful".to_owned(); - } - - TellerResponseData { - status_code: my_status_code, - status_description: my_status_description, - teller_data: vec_teller_data, - } + Ok(BranchResponseData { + branch_data: select_branch_details(&mut conn)?, + }) } -pub fn get_customer_data(pool: &mysql::Pool) -> CustomerResponseData { - let mut vec_customer_data = Vec::new(); - let mut my_status_code = 1_u8; - let mut my_status_description: String = String::from("Record not found"); +pub fn get_teller_data(pool: &mysql::Pool) -> Result { + let mut conn = pool.get_conn()?; - match pool - .get_conn() - .and_then(|mut conn| select_customer_details(&mut conn)) - { - Ok(data) => vec_customer_data = data, - Err(err) => println!("Failed to open DB connection. {err:?}"), - } - - if !vec_customer_data.is_empty() { - my_status_code = 0; - my_status_description = "Successful".to_owned(); - } - - CustomerResponseData { - status_code: my_status_code, - status_description: my_status_description, - customer_data: vec_customer_data, - } + Ok(TellerResponseData { + teller_data: select_teller_details(&mut conn)?, + }) } +pub fn get_customer_data(pool: &mysql::Pool) -> Result { + let mut conn = pool.get_conn()?; + + Ok(CustomerResponseData { + customer_data: select_customer_details(&mut conn)?, + }) +} + +/// Insert data into the database table `bank_details`. fn insert_bank_data( conn: &mut mysql::PooledConn, my_bank_name: String, my_country: String, -) -> std::result::Result { - // Insert data into the database table bank_details +) -> mysql::error::Result { conn.exec_drop( - "insert into bank_details (bank_name, country) values (:bank_name, :country);", + " + INSERT INTO bank_details (bank_name, country) + VALUES (:bank_name, :country) + ", params! { "bank_name" => my_bank_name, "country" => my_country, @@ -286,14 +198,17 @@ fn insert_bank_data( .map(|_| conn.last_insert_id()) } +/// Insert data into the database table `branch_details`. fn insert_branch_data( conn: &mut mysql::PooledConn, my_branch_name: String, my_location: String, -) -> std::result::Result { - // Insert data into the database table branch_details +) -> mysql::error::Result { conn.exec_drop( - "insert into branch_details (branch_name, location) values (:branch_name, :location);", + " + INSERT INTO branch_details (branch_name, location) + VALUES (:branch_name, :location) + ", params! { "branch_name" => my_branch_name, "location" => my_location, @@ -302,88 +217,106 @@ fn insert_branch_data( .map(|_| conn.last_insert_id()) } +/// Insert data into the database table `teller_details`. fn insert_teller_data( conn: &mut mysql::PooledConn, my_teller_name: String, my_branch_name: String, -) -> std::result::Result { - // Insert data into the database table teller_details +) -> mysql::error::Result { conn.exec_drop( - "insert into teller_details (teller_name, branch_name) values (:teller_name, :branch_name);", + " + INSERT INTO teller_details (teller_name, branch_name) + VALUES (:teller_name, :branch_name) + ", params! { "teller_name" => my_teller_name, "branch_name" => my_branch_name, }, - ).map(|_| conn.last_insert_id()) + ) + .map(|_| conn.last_insert_id()) } +/// Insert data into the database table `customer_details`. fn insert_customer_data( conn: &mut mysql::PooledConn, my_customer_name: String, my_branch_name: String, -) -> std::result::Result { - // Insert data into the database table customer_details +) -> mysql::error::Result { conn.exec_drop( - "insert into customer_details (customer_name, branch_name) values (:customer_name, :branch_name);", + r" + INSERT INTO customer_details (customer_name, branch_name) + VALUES (:customer_name, :branch_name) + ", params! { "customer_name" => my_customer_name, "branch_name" => my_branch_name, }, - ).map(|_| conn.last_insert_id()) + ) + .map(|_| conn.last_insert_id()) } -fn select_bank_details( - conn: &mut mysql::PooledConn, -) -> std::result::Result, mysql::error::Error> { - let mut bank_data = Vec::new(); - +/// Lists all banks' details. +fn select_bank_details(conn: &mut mysql::PooledConn) -> mysql::error::Result> { conn.query_map( - "select bank_name, country from bank_details where length(trim(coalesce(bank_name,''))) > 0 and length(trim(coalesce(country,''))) > 0 order by id asc;", - |(my_bank_name, my_country)| { - let bank_details = BankDetails { bank_name: my_bank_name, country: my_country, }; - bank_data.push(bank_details); - }, - ).map(|_| bank_data) + r" + SELECT bank_name, country FROM bank_details + WHERE LENGTH(TRIM(COALESCE(bank_name, ''))) > 0 + AND LENGTH(TRIM(COALESCE(country, ''))) > 0 + ORDER BY id ASC + ", + |(my_bank_name, my_country)| BankDetails { + bank_name: my_bank_name, + country: my_country, + }, + ) } -fn select_branch_details( - conn: &mut mysql::PooledConn, -) -> std::result::Result, mysql::error::Error> { - let mut branch_data = Vec::new(); - +/// Lists all branches' details. +fn select_branch_details(conn: &mut mysql::PooledConn) -> mysql::error::Result> { conn.query_map( - "select branch_name, location from branch_details where length(trim(coalesce(branch_name,''))) > 0 and length(trim(coalesce(location,''))) > 0 order by id asc;", - |(my_branch_name, my_location)| { - let branch_details = BranchDetails { branch_name: my_branch_name, location: my_location, }; - branch_data.push(branch_details); - }, - ).map(|_| branch_data) + r" + SELECT branch_name, location FROM branch_details + WHERE LENGTH(TRIM(COALESCE(branch_name, ''))) > 0 + AND LENGTH(TRIM(COALESCE(location, ''))) > 0 + ORDER BY id ASC + ", + |(my_branch_name, my_location)| BranchDetails { + branch_name: my_branch_name, + location: my_location, + }, + ) } -fn select_teller_details( - conn: &mut mysql::PooledConn, -) -> std::result::Result, mysql::error::Error> { - let mut teller_data = Vec::new(); - +/// Lists all tellers' details. +fn select_teller_details(conn: &mut mysql::PooledConn) -> mysql::error::Result> { conn.query_map( - "select teller_name, branch_name from teller_details where length(trim(coalesce(teller_name,''))) > 0 and length(trim(coalesce(branch_name,''))) > 0 order by id asc;", - |(my_teller_name, my_branch_name)| { - let teller_details = TellerDetails { teller_name: my_teller_name, branch_name: my_branch_name, }; - teller_data.push(teller_details); - }, - ).map(|_| teller_data) + r" + SELECT teller_name, branch_name FROM teller_details + WHERE LENGTH(TRIM(COALESCE(teller_name, ''))) > 0 + AND LENGTH(TRIM(COALESCE(branch_name, ''))) > 0 + ORDER BY id ASC + ", + |(my_teller_name, my_branch_name)| TellerDetails { + teller_name: my_teller_name, + branch_name: my_branch_name, + }, + ) } +/// Lists all customers' details. fn select_customer_details( conn: &mut mysql::PooledConn, -) -> std::result::Result, mysql::error::Error> { - let mut customer_data = Vec::new(); - +) -> mysql::error::Result> { conn.query_map( - "select customer_name, branch_name from customer_details where length(trim(coalesce(customer_name,''))) > 0 and length(trim(coalesce(branch_name,''))) > 0 order by id asc;", - |(my_customer_name, my_branch_name)| { - let teller_details = CustomerDetails { customer_name: my_customer_name, branch_name: my_branch_name, }; - customer_data.push(teller_details); - }, - ).map(|_| customer_data) + r" + SELECT customer_name, branch_name FROM customer_details + WHERE LENGTH(TRIM(COALESCE(customer_name, ''))) > 0 + AND LENGTH(TRIM(COALESCE(branch_name, ''))) > 0 + ORDER BY id ASC + ", + |(my_customer_name, my_branch_name)| CustomerDetails { + customer_name: my_customer_name, + branch_name: my_branch_name, + }, + ) } diff --git a/databases/mysql/src/routes.rs b/databases/mysql/src/routes.rs index c3429e7..ae0cc34 100644 --- a/databases/mysql/src/routes.rs +++ b/databases/mysql/src/routes.rs @@ -19,9 +19,9 @@ pub(crate) async fn add_bank( data: web::Data, ) -> actix_web::Result { let bank_name = bank_data.bank_name; - let _country = bank_data.country; + let country = bank_data.country; - create_bank(&data, bank_name, _country)?; + web::block(move || create_bank(&data, bank_name, country)).await??; Ok(HttpResponse::NoContent()) } @@ -32,11 +32,11 @@ pub(crate) async fn add_branch( data: web::Data, ) -> actix_web::Result { let branch_name = branch_data.branch_name; - let _location = branch_data.location; + let location = branch_data.location; - let response_data = create_branch(&data, branch_name, _location); + web::block(move || create_branch(&data, branch_name, location)).await??; - Ok(web::Json(response_data)) + Ok(HttpResponse::NoContent()) } #[post("/teller")] @@ -47,9 +47,9 @@ pub(crate) async fn add_teller( let teller_name = teller_data.teller_name; let branch_name = teller_data.branch_name; - let response_data = create_teller(&data, teller_name, branch_name); + web::block(move || create_teller(&data, teller_name, branch_name)).await??; - Ok(web::Json(response_data)) + Ok(HttpResponse::NoContent()) } #[post("/customer")] @@ -60,26 +60,26 @@ pub(crate) async fn add_customer( let customer_name = customer_data.customer_name; let branch_name = customer_data.branch_name; - let response_data = create_customer(&data, customer_name, branch_name); + web::block(move || create_customer(&data, customer_name, branch_name)).await??; - Ok(web::Json(response_data)) + Ok(HttpResponse::NoContent()) } #[get("/bank")] pub(crate) async fn get_bank(data: web::Data) -> actix_web::Result { - let bank_response_data = get_bank_data(&data); + let bank_response_data = web::block(move || get_bank_data(&data)).await??; Ok(web::Json(bank_response_data)) } #[get("/branch")] pub(crate) async fn get_branch(data: web::Data) -> actix_web::Result { - let branch_response_data = get_branch_data(&data); + let branch_response_data = web::block(move || get_branch_data(&data)).await??; Ok(web::Json(branch_response_data)) } #[get("/teller")] pub(crate) async fn get_teller(data: web::Data) -> actix_web::Result { - let teller_response_data = get_teller_data(&data); + let teller_response_data = web::block(move || get_teller_data(&data)).await??; Ok(web::Json(teller_response_data)) } @@ -87,6 +87,6 @@ pub(crate) async fn get_teller(data: web::Data) -> actix_web::Resul pub(crate) async fn get_customer( data: web::Data, ) -> actix_web::Result { - let customer_response_data = get_customer_data(&data); + let customer_response_data = web::block(move || get_customer_data(&data)).await??; Ok(web::Json(customer_response_data)) }