From 8dab4b9a50ba4b8a65a91d46bcbd6cb88a622621 Mon Sep 17 00:00:00 2001 From: Tobias Reisinger Date: Mon, 27 Nov 2023 13:33:04 +0100 Subject: [PATCH] Improve database errors (NotFound -> Option) --- emgauwa-controller/src/main.rs | 11 ++------ emgauwa-lib/src/db/controllers.rs | 22 +++++++++------ emgauwa-lib/src/db/errors.rs | 22 +++++++++------ emgauwa-lib/src/db/mod.rs | 35 +++++++++++------------- emgauwa-lib/src/db/relays.rs | 29 ++++++++++++-------- emgauwa-lib/src/db/schedules.rs | 22 +++++++++------ emgauwa-lib/src/db/tag.rs | 18 ++++++------ emgauwa-lib/src/handlers/v1/schedules.rs | 12 ++++++-- emgauwa-lib/src/models/mod.rs | 3 +- 9 files changed, 96 insertions(+), 78 deletions(-) diff --git a/emgauwa-controller/src/main.rs b/emgauwa-controller/src/main.rs index 7a6e468..20bd992 100644 --- a/emgauwa-controller/src/main.rs +++ b/emgauwa-controller/src/main.rs @@ -2,7 +2,6 @@ use std::str; use crate::relay_loop::run_relay_loop; use crate::settings::Settings; -use emgauwa_lib::db::errors::DatabaseError; use emgauwa_lib::db::{DbController, DbRelay}; use emgauwa_lib::types::ControllerUid; use emgauwa_lib::{db, models}; @@ -75,14 +74,10 @@ async fn main() { relay.number.unwrap(), ) .await + .expect("Failed to get relay from database") { - Ok(relay) => relay, - Err(err) => match err { - DatabaseError::NotFound => { - create_this_relay(&mut conn, &db_controller, relay).await - } - _ => panic!("Failed to get relay from database"), - }, + None => create_this_relay(&mut conn, &db_controller, relay).await, + Some(relay) => relay, } }) }) diff --git a/emgauwa-lib/src/db/controllers.rs b/emgauwa-lib/src/db/controllers.rs index b930517..20a4364 100644 --- a/emgauwa-lib/src/db/controllers.rs +++ b/emgauwa-lib/src/db/controllers.rs @@ -21,25 +21,26 @@ impl DbController { pub async fn get_all( conn: &mut PoolConnection, ) -> Result, DatabaseError> { - Ok(sqlx::query_as!(DbController, "SELECT * FROM controllers") + sqlx::query_as!(DbController, "SELECT * FROM controllers") .fetch_all(conn.deref_mut()) - .await?) + .await + .map_err(DatabaseError::from) } pub async fn get( conn: &mut PoolConnection, id: i64, - ) -> Result { + ) -> Result, DatabaseError> { sqlx::query_as!(DbController, "SELECT * FROM controllers WHERE id = ?", id) .fetch_optional(conn.deref_mut()) .await - .map(|s| s.ok_or(DatabaseError::NotFound))? + .map_err(DatabaseError::from) } pub async fn get_by_uid( conn: &mut PoolConnection, filter_uid: &ControllerUid, - ) -> Result { + ) -> Result, DatabaseError> { sqlx::query_as!( DbController, "SELECT * FROM controllers WHERE uid = ?", @@ -47,16 +48,17 @@ impl DbController { ) .fetch_optional(conn.deref_mut()) .await - .map(|s| s.ok_or(DatabaseError::NotFound))? + .map_err(DatabaseError::from) } pub async fn get_by_tag( conn: &mut PoolConnection, tag: &DbTag, ) -> Result, DatabaseError> { - Ok(sqlx::query_as!(DbController, "SELECT schedule.* FROM controllers AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id) + sqlx::query_as!(DbController, "SELECT schedule.* FROM controllers AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id) .fetch_all(conn.deref_mut()) - .await?) + .await + .map_err(DatabaseError::from) } pub async fn delete_by_uid( @@ -109,6 +111,8 @@ impl DbController { .execute(conn.deref_mut()) .await?; - Self::get(conn, self.id).await + Self::get(conn, self.id) + .await? + .ok_or(DatabaseError::UpdateGetError) } } diff --git a/emgauwa-lib/src/db/errors.rs b/emgauwa-lib/src/db/errors.rs index f71d109..d486c36 100644 --- a/emgauwa-lib/src/db/errors.rs +++ b/emgauwa-lib/src/db/errors.rs @@ -12,6 +12,7 @@ pub enum DatabaseError { NotFound, Protected, UpdateError, + UpdateGetError, Unknown, } @@ -40,17 +41,20 @@ impl Serialize for DatabaseError { impl From<&DatabaseError> for String { fn from(err: &DatabaseError) -> Self { - match err { - DatabaseError::InsertError => String::from("error on inserting into database"), + String::from(match err { + DatabaseError::InsertError => "error on inserting into database", DatabaseError::InsertGetError => { - String::from("error on retrieving new entry from database (your entry was saved)") + "error on retrieving new entry from database (your entry was saved)" } - DatabaseError::NotFound => String::from("model was not found in database"), - DatabaseError::DeleteError => String::from("error on deleting from database"), - DatabaseError::Protected => String::from("model is protected"), - DatabaseError::UpdateError => String::from("error on updating the model"), - DatabaseError::Unknown => String::from("unknown error"), - } + DatabaseError::NotFound => "model was not found in database", + DatabaseError::DeleteError => "error on deleting from database", + DatabaseError::Protected => "model is protected", + DatabaseError::UpdateError => "error on updating the model", + DatabaseError::UpdateGetError => { + "error on retrieving updated model from database (your entry was saved)" + } + DatabaseError::Unknown => "unknown error", + }) } } diff --git a/emgauwa-lib/src/db/mod.rs b/emgauwa-lib/src/db/mod.rs index 7e7df11..031449b 100644 --- a/emgauwa-lib/src/db/mod.rs +++ b/emgauwa-lib/src/db/mod.rs @@ -34,25 +34,22 @@ async fn init_schedule( periods: DbPeriods, ) -> Result<(), DatabaseError> { trace!("Initializing schedule {:?}", name); - match DbSchedule::get_by_uid(&mut pool.acquire().await.unwrap(), uid).await { - Ok(_) => Ok(()), - Err(err) => match err { - DatabaseError::NotFound => { - trace!("Schedule {:?} not found, inserting", name); - sqlx::query_as!( - DbSchedule, - "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", - uid, - name, - periods, - ) - .fetch_optional(pool) - .await? - .ok_or(DatabaseError::InsertGetError) - .map(|_| ()) - } - _ => Err(err), - }, + match DbSchedule::get_by_uid(&mut pool.acquire().await.unwrap(), uid).await? { + Some(_) => Ok(()), + None => { + trace!("Schedule {:?} not found, inserting", name); + sqlx::query_as!( + DbSchedule, + "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", + uid, + name, + periods, + ) + .fetch_optional(pool) + .await? + .ok_or(DatabaseError::InsertGetError) + .map(|_| ()) + } } } diff --git a/emgauwa-lib/src/db/relays.rs b/emgauwa-lib/src/db/relays.rs index 70dcb1f..80f9b2b 100644 --- a/emgauwa-lib/src/db/relays.rs +++ b/emgauwa-lib/src/db/relays.rs @@ -25,27 +25,30 @@ impl DbRelay { .await?) } - pub async fn get(conn: &mut PoolConnection, id: i64) -> Result { - sqlx::query_as!(DbRelay, "SELECT * FROM relays WHERE id = ?", id) - .fetch_optional(conn.deref_mut()) - .await - .map(|s| s.ok_or(DatabaseError::NotFound))? + pub async fn get( + conn: &mut PoolConnection, + id: i64, + ) -> Result, DatabaseError> { + Ok( + sqlx::query_as!(DbRelay, "SELECT * FROM relays WHERE id = ?", id) + .fetch_optional(conn.deref_mut()) + .await?, + ) } pub async fn get_by_controller_and_num( conn: &mut PoolConnection, controller: &DbController, number: i64, - ) -> Result { - sqlx::query_as!( + ) -> Result, DatabaseError> { + Ok(sqlx::query_as!( DbRelay, "SELECT * FROM relays WHERE controller_id = ? AND number = ?", controller.id, number ) .fetch_optional(conn.deref_mut()) - .await - .map(|s| s.ok_or(DatabaseError::NotFound))? + .await?) } pub async fn get_by_tag( @@ -102,14 +105,18 @@ impl DbRelay { .execute(conn.deref_mut()) .await?; - DbRelay::get(conn, self.id).await + DbRelay::get(conn, self.id) + .await? + .ok_or(DatabaseError::UpdateGetError) } pub async fn get_controller( &self, conn: &mut PoolConnection, ) -> Result { - DbController::get(conn, self.controller_id).await + DbController::get(conn, self.controller_id) + .await? + .ok_or(DatabaseError::NotFound) } pub async fn get_tags( diff --git a/emgauwa-lib/src/db/schedules.rs b/emgauwa-lib/src/db/schedules.rs index bf5232f..bfe1f27 100644 --- a/emgauwa-lib/src/db/schedules.rs +++ b/emgauwa-lib/src/db/schedules.rs @@ -27,25 +27,26 @@ impl DbSchedule { pub async fn get_all( conn: &mut PoolConnection, ) -> Result, DatabaseError> { - Ok(sqlx::query_as!(DbSchedule, "SELECT * FROM schedules") + sqlx::query_as!(DbSchedule, "SELECT * FROM schedules") .fetch_all(conn.deref_mut()) - .await?) + .await + .map_err(DatabaseError::from) } pub async fn get( conn: &mut PoolConnection, id: i64, - ) -> Result { + ) -> Result, DatabaseError> { sqlx::query_as!(DbSchedule, "SELECT * FROM schedules WHERE id = ?", id) .fetch_optional(conn.deref_mut()) .await - .map(|s| s.ok_or(DatabaseError::NotFound))? + .map_err(DatabaseError::from) } pub async fn get_by_uid( conn: &mut PoolConnection, filter_uid: &ScheduleUid, - ) -> Result { + ) -> Result, DatabaseError> { sqlx::query_as!( DbSchedule, "SELECT * FROM schedules WHERE uid = ?", @@ -53,16 +54,17 @@ impl DbSchedule { ) .fetch_optional(conn.deref_mut()) .await - .map(|s| s.ok_or(DatabaseError::NotFound))? + .map_err(DatabaseError::from) } pub async fn get_by_tag( conn: &mut PoolConnection, tag: &DbTag, ) -> Result, DatabaseError> { - Ok(sqlx::query_as!(DbSchedule, "SELECT schedule.* FROM schedules AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id) + sqlx::query_as!(DbSchedule, "SELECT schedule.* FROM schedules AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id) .fetch_all(conn.deref_mut()) - .await?) + .await + .map_err(DatabaseError::from) } pub async fn delete_by_uid( @@ -123,7 +125,9 @@ impl DbSchedule { .execute(conn.deref_mut()) .await?; - DbSchedule::get(conn, self.id).await + DbSchedule::get(conn, self.id) + .await? + .ok_or(DatabaseError::UpdateGetError) } pub async fn get_tags( diff --git a/emgauwa-lib/src/db/tag.rs b/emgauwa-lib/src/db/tag.rs index f788f5b..4f89432 100644 --- a/emgauwa-lib/src/db/tag.rs +++ b/emgauwa-lib/src/db/tag.rs @@ -35,32 +35,34 @@ impl DbTag { .ok_or(DatabaseError::InsertGetError) } - pub async fn get(conn: &mut PoolConnection, id: i64) -> Result { + pub async fn get( + conn: &mut PoolConnection, + id: i64, + ) -> Result, DatabaseError> { sqlx::query_as!(DbTag, "SELECT * FROM tags WHERE id = ?", id) .fetch_optional(conn.deref_mut()) .await - .map(|t| t.ok_or(DatabaseError::NotFound))? + .map_err(DatabaseError::from) } pub async fn get_by_tag_or_create( conn: &mut PoolConnection, target_tag: &str, ) -> Result { - match DbTag::get_by_tag(conn, target_tag).await { - Ok(tag) => Ok(tag), - Err(DatabaseError::NotFound) => DbTag::create(conn, target_tag).await, - Err(e) => Err(e), + match DbTag::get_by_tag(conn, target_tag).await? { + Some(tag) => Ok(tag), + None => DbTag::create(conn, target_tag).await, } } pub async fn get_by_tag( conn: &mut PoolConnection, target_tag: &str, - ) -> Result { + ) -> Result, DatabaseError> { sqlx::query_as!(DbTag, "SELECT * FROM tags WHERE tag = ?", target_tag) .fetch_optional(conn.deref_mut()) .await - .map(|t| t.ok_or(DatabaseError::NotFound))? + .map_err(DatabaseError::from) } pub async fn link_relay( diff --git a/emgauwa-lib/src/handlers/v1/schedules.rs b/emgauwa-lib/src/handlers/v1/schedules.rs index 489bac6..14d4949 100644 --- a/emgauwa-lib/src/handlers/v1/schedules.rs +++ b/emgauwa-lib/src/handlers/v1/schedules.rs @@ -39,7 +39,9 @@ pub async fn tagged( let mut pool_conn = pool.acquire().await?; let (tag,) = path.into_inner(); - let tag_db = DbTag::get_by_tag(&mut pool_conn, &tag).await?; + let tag_db = DbTag::get_by_tag(&mut pool_conn, &tag) + .await? + .ok_or(DatabaseError::NotFound)?; let schedules = DbSchedule::get_by_tag(&mut pool_conn, &tag_db).await?; @@ -61,7 +63,9 @@ pub async fn show( let (schedule_uid,) = path.into_inner(); let uid = ScheduleUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?; - let schedule = DbSchedule::get_by_uid(&mut pool_conn, &uid).await?; + let schedule = DbSchedule::get_by_uid(&mut pool_conn, &uid) + .await? + .ok_or(DatabaseError::NotFound)?; let return_schedule = Schedule::from_schedule(schedule, &mut pool_conn); Ok(HttpResponse::Ok().json(return_schedule)) @@ -136,7 +140,9 @@ pub async fn update( let (schedule_uid,) = path.into_inner(); let uid = ScheduleUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?; - let schedule = DbSchedule::get_by_uid(&mut pool_conn, &uid).await?; + let schedule = DbSchedule::get_by_uid(&mut pool_conn, &uid) + .await? + .ok_or(DatabaseError::NotFound)?; let schedule = schedule .update(&mut pool_conn, data.name.as_str(), &data.periods) diff --git a/emgauwa-lib/src/models/mod.rs b/emgauwa-lib/src/models/mod.rs index bfd7a70..fd23583 100644 --- a/emgauwa-lib/src/models/mod.rs +++ b/emgauwa-lib/src/models/mod.rs @@ -38,8 +38,7 @@ impl Schedule { impl Relay { pub fn from_db_relay(relay: db::DbRelay, conn: &mut PoolConnection) -> Self { let relay = relay.clone(); - let controller = - executor::block_on(db::DbController::get(conn, relay.controller_id)).unwrap(); + let controller = executor::block_on(relay.get_controller(conn)).unwrap(); let tags = executor::block_on(relay.get_tags(conn)).unwrap(); Relay {