Improve database errors (NotFound -> Option)

This commit is contained in:
Tobias Reisinger 2023-11-27 13:33:04 +01:00
parent be7f31906c
commit 8dab4b9a50
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
9 changed files with 96 additions and 78 deletions

View file

@ -2,7 +2,6 @@ use std::str;
use crate::relay_loop::run_relay_loop; use crate::relay_loop::run_relay_loop;
use crate::settings::Settings; use crate::settings::Settings;
use emgauwa_lib::db::errors::DatabaseError;
use emgauwa_lib::db::{DbController, DbRelay}; use emgauwa_lib::db::{DbController, DbRelay};
use emgauwa_lib::types::ControllerUid; use emgauwa_lib::types::ControllerUid;
use emgauwa_lib::{db, models}; use emgauwa_lib::{db, models};
@ -75,14 +74,10 @@ async fn main() {
relay.number.unwrap(), relay.number.unwrap(),
) )
.await .await
.expect("Failed to get relay from database")
{ {
Ok(relay) => relay, None => create_this_relay(&mut conn, &db_controller, relay).await,
Err(err) => match err { Some(relay) => relay,
DatabaseError::NotFound => {
create_this_relay(&mut conn, &db_controller, relay).await
}
_ => panic!("Failed to get relay from database"),
},
} }
}) })
}) })

View file

@ -21,25 +21,26 @@ impl DbController {
pub async fn get_all( pub async fn get_all(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
) -> Result<Vec<DbController>, DatabaseError> { ) -> Result<Vec<DbController>, DatabaseError> {
Ok(sqlx::query_as!(DbController, "SELECT * FROM controllers") sqlx::query_as!(DbController, "SELECT * FROM controllers")
.fetch_all(conn.deref_mut()) .fetch_all(conn.deref_mut())
.await?) .await
.map_err(DatabaseError::from)
} }
pub async fn get( pub async fn get(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
id: i64, id: i64,
) -> Result<DbController, DatabaseError> { ) -> Result<Option<DbController>, DatabaseError> {
sqlx::query_as!(DbController, "SELECT * FROM controllers WHERE id = ?", id) sqlx::query_as!(DbController, "SELECT * FROM controllers WHERE id = ?", id)
.fetch_optional(conn.deref_mut()) .fetch_optional(conn.deref_mut())
.await .await
.map(|s| s.ok_or(DatabaseError::NotFound))? .map_err(DatabaseError::from)
} }
pub async fn get_by_uid( pub async fn get_by_uid(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
filter_uid: &ControllerUid, filter_uid: &ControllerUid,
) -> Result<DbController, DatabaseError> { ) -> Result<Option<DbController>, DatabaseError> {
sqlx::query_as!( sqlx::query_as!(
DbController, DbController,
"SELECT * FROM controllers WHERE uid = ?", "SELECT * FROM controllers WHERE uid = ?",
@ -47,16 +48,17 @@ impl DbController {
) )
.fetch_optional(conn.deref_mut()) .fetch_optional(conn.deref_mut())
.await .await
.map(|s| s.ok_or(DatabaseError::NotFound))? .map_err(DatabaseError::from)
} }
pub async fn get_by_tag( pub async fn get_by_tag(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
tag: &DbTag, tag: &DbTag,
) -> Result<Vec<DbController>, DatabaseError> { ) -> Result<Vec<DbController>, 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()) .fetch_all(conn.deref_mut())
.await?) .await
.map_err(DatabaseError::from)
} }
pub async fn delete_by_uid( pub async fn delete_by_uid(
@ -109,6 +111,8 @@ impl DbController {
.execute(conn.deref_mut()) .execute(conn.deref_mut())
.await?; .await?;
Self::get(conn, self.id).await Self::get(conn, self.id)
.await?
.ok_or(DatabaseError::UpdateGetError)
} }
} }

View file

@ -12,6 +12,7 @@ pub enum DatabaseError {
NotFound, NotFound,
Protected, Protected,
UpdateError, UpdateError,
UpdateGetError,
Unknown, Unknown,
} }
@ -40,17 +41,20 @@ impl Serialize for DatabaseError {
impl From<&DatabaseError> for String { impl From<&DatabaseError> for String {
fn from(err: &DatabaseError) -> Self { fn from(err: &DatabaseError) -> Self {
match err { String::from(match err {
DatabaseError::InsertError => String::from("error on inserting into database"), DatabaseError::InsertError => "error on inserting into database",
DatabaseError::InsertGetError => { 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::NotFound => "model was not found in database",
DatabaseError::DeleteError => String::from("error on deleting from database"), DatabaseError::DeleteError => "error on deleting from database",
DatabaseError::Protected => String::from("model is protected"), DatabaseError::Protected => "model is protected",
DatabaseError::UpdateError => String::from("error on updating the model"), DatabaseError::UpdateError => "error on updating the model",
DatabaseError::Unknown => String::from("unknown error"), DatabaseError::UpdateGetError => {
} "error on retrieving updated model from database (your entry was saved)"
}
DatabaseError::Unknown => "unknown error",
})
} }
} }

View file

@ -34,25 +34,22 @@ async fn init_schedule(
periods: DbPeriods, periods: DbPeriods,
) -> Result<(), DatabaseError> { ) -> Result<(), DatabaseError> {
trace!("Initializing schedule {:?}", name); trace!("Initializing schedule {:?}", name);
match DbSchedule::get_by_uid(&mut pool.acquire().await.unwrap(), uid).await { match DbSchedule::get_by_uid(&mut pool.acquire().await.unwrap(), uid).await? {
Ok(_) => Ok(()), Some(_) => Ok(()),
Err(err) => match err { None => {
DatabaseError::NotFound => { trace!("Schedule {:?} not found, inserting", name);
trace!("Schedule {:?} not found, inserting", name); sqlx::query_as!(
sqlx::query_as!( DbSchedule,
DbSchedule, "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *",
"INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", uid,
uid, name,
name, periods,
periods, )
) .fetch_optional(pool)
.fetch_optional(pool) .await?
.await? .ok_or(DatabaseError::InsertGetError)
.ok_or(DatabaseError::InsertGetError) .map(|_| ())
.map(|_| ()) }
}
_ => Err(err),
},
} }
} }

View file

@ -25,27 +25,30 @@ impl DbRelay {
.await?) .await?)
} }
pub async fn get(conn: &mut PoolConnection<Sqlite>, id: i64) -> Result<DbRelay, DatabaseError> { pub async fn get(
sqlx::query_as!(DbRelay, "SELECT * FROM relays WHERE id = ?", id) conn: &mut PoolConnection<Sqlite>,
.fetch_optional(conn.deref_mut()) id: i64,
.await ) -> Result<Option<DbRelay>, DatabaseError> {
.map(|s| s.ok_or(DatabaseError::NotFound))? 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( pub async fn get_by_controller_and_num(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
controller: &DbController, controller: &DbController,
number: i64, number: i64,
) -> Result<DbRelay, DatabaseError> { ) -> Result<Option<DbRelay>, DatabaseError> {
sqlx::query_as!( Ok(sqlx::query_as!(
DbRelay, DbRelay,
"SELECT * FROM relays WHERE controller_id = ? AND number = ?", "SELECT * FROM relays WHERE controller_id = ? AND number = ?",
controller.id, controller.id,
number number
) )
.fetch_optional(conn.deref_mut()) .fetch_optional(conn.deref_mut())
.await .await?)
.map(|s| s.ok_or(DatabaseError::NotFound))?
} }
pub async fn get_by_tag( pub async fn get_by_tag(
@ -102,14 +105,18 @@ impl DbRelay {
.execute(conn.deref_mut()) .execute(conn.deref_mut())
.await?; .await?;
DbRelay::get(conn, self.id).await DbRelay::get(conn, self.id)
.await?
.ok_or(DatabaseError::UpdateGetError)
} }
pub async fn get_controller( pub async fn get_controller(
&self, &self,
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
) -> Result<DbController, DatabaseError> { ) -> Result<DbController, DatabaseError> {
DbController::get(conn, self.controller_id).await DbController::get(conn, self.controller_id)
.await?
.ok_or(DatabaseError::NotFound)
} }
pub async fn get_tags( pub async fn get_tags(

View file

@ -27,25 +27,26 @@ impl DbSchedule {
pub async fn get_all( pub async fn get_all(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
) -> Result<Vec<DbSchedule>, DatabaseError> { ) -> Result<Vec<DbSchedule>, DatabaseError> {
Ok(sqlx::query_as!(DbSchedule, "SELECT * FROM schedules") sqlx::query_as!(DbSchedule, "SELECT * FROM schedules")
.fetch_all(conn.deref_mut()) .fetch_all(conn.deref_mut())
.await?) .await
.map_err(DatabaseError::from)
} }
pub async fn get( pub async fn get(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
id: i64, id: i64,
) -> Result<DbSchedule, DatabaseError> { ) -> Result<Option<DbSchedule>, DatabaseError> {
sqlx::query_as!(DbSchedule, "SELECT * FROM schedules WHERE id = ?", id) sqlx::query_as!(DbSchedule, "SELECT * FROM schedules WHERE id = ?", id)
.fetch_optional(conn.deref_mut()) .fetch_optional(conn.deref_mut())
.await .await
.map(|s| s.ok_or(DatabaseError::NotFound))? .map_err(DatabaseError::from)
} }
pub async fn get_by_uid( pub async fn get_by_uid(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
filter_uid: &ScheduleUid, filter_uid: &ScheduleUid,
) -> Result<DbSchedule, DatabaseError> { ) -> Result<Option<DbSchedule>, DatabaseError> {
sqlx::query_as!( sqlx::query_as!(
DbSchedule, DbSchedule,
"SELECT * FROM schedules WHERE uid = ?", "SELECT * FROM schedules WHERE uid = ?",
@ -53,16 +54,17 @@ impl DbSchedule {
) )
.fetch_optional(conn.deref_mut()) .fetch_optional(conn.deref_mut())
.await .await
.map(|s| s.ok_or(DatabaseError::NotFound))? .map_err(DatabaseError::from)
} }
pub async fn get_by_tag( pub async fn get_by_tag(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
tag: &DbTag, tag: &DbTag,
) -> Result<Vec<DbSchedule>, DatabaseError> { ) -> Result<Vec<DbSchedule>, 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()) .fetch_all(conn.deref_mut())
.await?) .await
.map_err(DatabaseError::from)
} }
pub async fn delete_by_uid( pub async fn delete_by_uid(
@ -123,7 +125,9 @@ impl DbSchedule {
.execute(conn.deref_mut()) .execute(conn.deref_mut())
.await?; .await?;
DbSchedule::get(conn, self.id).await DbSchedule::get(conn, self.id)
.await?
.ok_or(DatabaseError::UpdateGetError)
} }
pub async fn get_tags( pub async fn get_tags(

View file

@ -35,32 +35,34 @@ impl DbTag {
.ok_or(DatabaseError::InsertGetError) .ok_or(DatabaseError::InsertGetError)
} }
pub async fn get(conn: &mut PoolConnection<Sqlite>, id: i64) -> Result<DbTag, DatabaseError> { pub async fn get(
conn: &mut PoolConnection<Sqlite>,
id: i64,
) -> Result<Option<DbTag>, DatabaseError> {
sqlx::query_as!(DbTag, "SELECT * FROM tags WHERE id = ?", id) sqlx::query_as!(DbTag, "SELECT * FROM tags WHERE id = ?", id)
.fetch_optional(conn.deref_mut()) .fetch_optional(conn.deref_mut())
.await .await
.map(|t| t.ok_or(DatabaseError::NotFound))? .map_err(DatabaseError::from)
} }
pub async fn get_by_tag_or_create( pub async fn get_by_tag_or_create(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
target_tag: &str, target_tag: &str,
) -> Result<DbTag, DatabaseError> { ) -> Result<DbTag, DatabaseError> {
match DbTag::get_by_tag(conn, target_tag).await { match DbTag::get_by_tag(conn, target_tag).await? {
Ok(tag) => Ok(tag), Some(tag) => Ok(tag),
Err(DatabaseError::NotFound) => DbTag::create(conn, target_tag).await, None => DbTag::create(conn, target_tag).await,
Err(e) => Err(e),
} }
} }
pub async fn get_by_tag( pub async fn get_by_tag(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
target_tag: &str, target_tag: &str,
) -> Result<DbTag, DatabaseError> { ) -> Result<Option<DbTag>, DatabaseError> {
sqlx::query_as!(DbTag, "SELECT * FROM tags WHERE tag = ?", target_tag) sqlx::query_as!(DbTag, "SELECT * FROM tags WHERE tag = ?", target_tag)
.fetch_optional(conn.deref_mut()) .fetch_optional(conn.deref_mut())
.await .await
.map(|t| t.ok_or(DatabaseError::NotFound))? .map_err(DatabaseError::from)
} }
pub async fn link_relay( pub async fn link_relay(

View file

@ -39,7 +39,9 @@ pub async fn tagged(
let mut pool_conn = pool.acquire().await?; let mut pool_conn = pool.acquire().await?;
let (tag,) = path.into_inner(); 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?; 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 (schedule_uid,) = path.into_inner();
let uid = ScheduleUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?; 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); let return_schedule = Schedule::from_schedule(schedule, &mut pool_conn);
Ok(HttpResponse::Ok().json(return_schedule)) Ok(HttpResponse::Ok().json(return_schedule))
@ -136,7 +140,9 @@ pub async fn update(
let (schedule_uid,) = path.into_inner(); let (schedule_uid,) = path.into_inner();
let uid = ScheduleUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?; 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 let schedule = schedule
.update(&mut pool_conn, data.name.as_str(), &data.periods) .update(&mut pool_conn, data.name.as_str(), &data.periods)

View file

@ -38,8 +38,7 @@ impl Schedule {
impl Relay { impl Relay {
pub fn from_db_relay(relay: db::DbRelay, conn: &mut PoolConnection<Sqlite>) -> Self { pub fn from_db_relay(relay: db::DbRelay, conn: &mut PoolConnection<Sqlite>) -> Self {
let relay = relay.clone(); let relay = relay.clone();
let controller = let controller = executor::block_on(relay.get_controller(conn)).unwrap();
executor::block_on(db::DbController::get(conn, relay.controller_id)).unwrap();
let tags = executor::block_on(relay.get_tags(conn)).unwrap(); let tags = executor::block_on(relay.get_tags(conn)).unwrap();
Relay { Relay {