From f5ac84f9156a369b5440370b869b90b2876e6446 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Wed, 30 Jun 2021 23:42:12 +0800 Subject: [PATCH] Rework DbErr --- src/database/mock.rs | 4 ++-- src/database/mod.rs | 2 +- src/driver/mod.rs | 4 ++++ src/driver/sqlx_common.rs | 9 +++++++++ src/driver/sqlx_mysql.rs | 32 ++++++++++++++++++----------- src/driver/sqlx_sqlite.rs | 32 ++++++++++++++++++----------- src/entity/active_model.rs | 6 +++--- src/error.rs | 41 ++++++++------------------------------ src/executor/query.rs | 6 +++--- 9 files changed, 70 insertions(+), 66 deletions(-) create mode 100644 src/driver/sqlx_common.rs diff --git a/src/database/mock.rs b/src/database/mock.rs index c57ef63e..7b208a72 100644 --- a/src/database/mock.rs +++ b/src/database/mock.rs @@ -75,7 +75,7 @@ impl MockDatabaseTrait for MockDatabase { result: ExecResultHolder::Mock(std::mem::take(&mut self.exec_results[counter])), }) } else { - Err(DbErr::Exec) + Err(DbErr::Exec("`exec_results` buffer is empty.".to_owned())) } } @@ -93,7 +93,7 @@ impl MockDatabaseTrait for MockDatabase { }) .collect()) } else { - Err(DbErr::Query) + Err(DbErr::Query("`query_results` buffer is empty.".to_owned())) } } diff --git a/src/database/mod.rs b/src/database/mod.rs index dd5fc5ea..4ad1b347 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -29,6 +29,6 @@ impl Database { if crate::MockDatabaseConnector::accepts(string) { return crate::MockDatabaseConnector::connect(string).await; } - Err(DbErr::Conn) + Err(DbErr::Conn(format!("The connection string '{}' has no supporting driver.", string))) } } diff --git a/src/driver/mod.rs b/src/driver/mod.rs index 7cb183c3..904e06a9 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -1,5 +1,7 @@ #[cfg(feature = "mock")] mod mock; +#[cfg(feature = "sqlx-dep")] +mod sqlx_common; #[cfg(feature = "sqlx-mysql")] mod sqlx_mysql; #[cfg(feature = "sqlx-sqlite")] @@ -7,6 +9,8 @@ mod sqlx_sqlite; #[cfg(feature = "mock")] pub use mock::*; +#[cfg(feature = "sqlx-dep")] +pub use sqlx_common::*; #[cfg(feature = "sqlx-mysql")] pub use sqlx_mysql::*; #[cfg(feature = "sqlx-sqlite")] diff --git a/src/driver/sqlx_common.rs b/src/driver/sqlx_common.rs new file mode 100644 index 00000000..5b1f7b35 --- /dev/null +++ b/src/driver/sqlx_common.rs @@ -0,0 +1,9 @@ +use crate::DbErr; + +pub fn sqlx_error_to_exec_err(err: sqlx::Error) -> DbErr { + DbErr::Exec(err.to_string()) +} + +pub fn sqlx_error_to_query_err(err: sqlx::Error) -> DbErr { + DbErr::Query(err.to_string()) +} diff --git a/src/driver/sqlx_mysql.rs b/src/driver/sqlx_mysql.rs index 7ecbd5a2..ebea0a32 100644 --- a/src/driver/sqlx_mysql.rs +++ b/src/driver/sqlx_mysql.rs @@ -8,6 +8,8 @@ use sea_query_driver_mysql::bind_query; use crate::{debug_print, error::*, executor::*, DatabaseConnection, Statement}; +use super::sqlx_common::*; + pub struct SqlxMySqlConnector; pub struct SqlxMySqlPoolConnection { @@ -25,7 +27,7 @@ impl SqlxMySqlConnector { SqlxMySqlPoolConnection { pool }, )) } else { - Err(DbErr::Conn) + Err(DbErr::Conn("Failed to connect.".to_owned())) } } } @@ -42,11 +44,13 @@ impl SqlxMySqlPoolConnection { let query = sqlx_query(&stmt); if let Ok(conn) = &mut self.pool.acquire().await { - if let Ok(res) = query.execute(conn).await { - return Ok(res.into()); + match query.execute(conn).await { + Ok(res) => Ok(res.into()), + Err(err) => Err(sqlx_error_to_exec_err(err)), } + } else { + Err(DbErr::Exec("Failed to acquire connection from pool.".to_owned())) } - Err(DbErr::Exec) } pub async fn query_one(&self, stmt: Statement) -> Result, DbErr> { @@ -54,13 +58,15 @@ impl SqlxMySqlPoolConnection { let query = sqlx_query(&stmt); if let Ok(conn) = &mut self.pool.acquire().await { - if let Ok(row) = query.fetch_one(conn).await { - Ok(Some(row.into())) - } else { - Ok(None) + match query.fetch_one(conn).await { + Ok(row) => Ok(Some(row.into())), + Err(err) => match err { + sqlx::Error::RowNotFound => Ok(None), + _ => Err(DbErr::Query(err.to_string())), + }, } } else { - Err(DbErr::Query) + Err(DbErr::Query("Failed to acquire connection from pool.".to_owned())) } } @@ -69,11 +75,13 @@ impl SqlxMySqlPoolConnection { let query = sqlx_query(&stmt); if let Ok(conn) = &mut self.pool.acquire().await { - if let Ok(rows) = query.fetch_all(conn).await { - return Ok(rows.into_iter().map(|r| r.into()).collect()); + match query.fetch_all(conn).await { + Ok(rows) => Ok(rows.into_iter().map(|r| r.into()).collect()), + Err(err) => Err(sqlx_error_to_query_err(err)), } + } else { + Err(DbErr::Query("Failed to acquire connection from pool.".to_owned())) } - Err(DbErr::Query) } } diff --git a/src/driver/sqlx_sqlite.rs b/src/driver/sqlx_sqlite.rs index 161e010e..ecd0ba4f 100644 --- a/src/driver/sqlx_sqlite.rs +++ b/src/driver/sqlx_sqlite.rs @@ -8,6 +8,8 @@ use sea_query_driver_sqlite::bind_query; use crate::{debug_print, error::*, executor::*, DatabaseConnection, Statement}; +use super::sqlx_common::*; + pub struct SqlxSqliteConnector; pub struct SqlxSqlitePoolConnection { @@ -25,7 +27,7 @@ impl SqlxSqliteConnector { SqlxSqlitePoolConnection { pool }, )) } else { - Err(DbErr::Conn) + Err(DbErr::Conn("Failed to connect.".to_owned())) } } } @@ -42,11 +44,13 @@ impl SqlxSqlitePoolConnection { let query = sqlx_query(&stmt); if let Ok(conn) = &mut self.pool.acquire().await { - if let Ok(res) = query.execute(conn).await { - return Ok(res.into()); + match query.execute(conn).await { + Ok(res) => Ok(res.into()), + Err(err) => Err(sqlx_error_to_exec_err(err)), } + } else { + Err(DbErr::Exec("Failed to acquire connection from pool.".to_owned())) } - Err(DbErr::Exec) } pub async fn query_one(&self, stmt: Statement) -> Result, DbErr> { @@ -54,13 +58,15 @@ impl SqlxSqlitePoolConnection { let query = sqlx_query(&stmt); if let Ok(conn) = &mut self.pool.acquire().await { - if let Ok(row) = query.fetch_one(conn).await { - Ok(Some(row.into())) - } else { - Ok(None) + match query.fetch_one(conn).await { + Ok(row) => Ok(Some(row.into())), + Err(err) => match err { + sqlx::Error::RowNotFound => Ok(None), + _ => Err(DbErr::Query(err.to_string())), + }, } } else { - Err(DbErr::Query) + Err(DbErr::Query("Failed to acquire connection from pool.".to_owned())) } } @@ -69,11 +75,13 @@ impl SqlxSqlitePoolConnection { let query = sqlx_query(&stmt); if let Ok(conn) = &mut self.pool.acquire().await { - if let Ok(rows) = query.fetch_all(conn).await { - return Ok(rows.into_iter().map(|r| r.into()).collect()); + match query.fetch_all(conn).await { + Ok(rows) => Ok(rows.into_iter().map(|r| r.into()).collect()), + Err(err) => Err(sqlx_error_to_query_err(err)), } + } else { + Err(DbErr::Query("Failed to acquire connection from pool.".to_owned())) } - Err(DbErr::Query) } } diff --git a/src/entity/active_model.rs b/src/entity/active_model.rs index 31a1345d..96486dda 100644 --- a/src/entity/active_model.rs +++ b/src/entity/active_model.rs @@ -223,11 +223,11 @@ where // TODO: if the entity does not have auto increment primary key, then last_insert_id is a wrong value if ::auto_increment() && res.last_insert_id != 0 { let find = E::find_by_id(res.last_insert_id).one(db); - let res = find.await; - let model: Option = res?; + let found = find.await; + let model: Option = found?; match model { Some(model) => Ok(model.into_active_model()), - None => Err(DbErr::Exec), + None => Err(DbErr::Exec(format!("Failed to find inserted item: {} {}", E::default().to_string(), res.last_insert_id))), } } else { Ok(A::default()) diff --git a/src/error.rs b/src/error.rs index 712df544..68f2313f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,41 +1,16 @@ -use std::{error, fmt}; - #[derive(Debug)] pub enum DbErr { - Conn, - Exec, - Query, - #[cfg(feature = "sqlx-dep")] - Sqlx(sqlx::Error), + Conn(String), + Exec(String), + Query(String), } -impl fmt::Display for DbErr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl std::fmt::Display for DbErr { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::Conn => write!(f, "{:?}", "Connection Error"), - Self::Exec => write!(f, "{:?}", "Execution Error"), - Self::Query => write!(f, "{:?}", "Query Error"), - #[cfg(feature = "sqlx-dep")] - Self::Sqlx(e) => write!(f, "{:?}", e), + Self::Conn(s) => write!(f, "Connection Error: {}", s), + Self::Exec(s) => write!(f, "Execution Error: {}", s), + Self::Query(s) => write!(f, "Query Error: {}", s), } } } - -impl error::Error for DbErr { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match self { - Self::Conn => None, - Self::Exec => None, - Self::Query => None, - #[cfg(feature = "sqlx-dep")] - Self::Sqlx(e) => Some(e), - } - } -} - -#[cfg(feature = "sqlx-dep")] -impl From for DbErr { - fn from(sqlx_err: sqlx::Error) -> Self { - Self::Sqlx(sqlx_err) - } -} diff --git a/src/executor/query.rs b/src/executor/query.rs index 1452a4d6..1d23a013 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -56,12 +56,12 @@ macro_rules! try_getable_all { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - Ok(row.try_get(column.as_str())?) + row.try_get(column.as_str()).map_err(crate::sqlx_error_to_query_err) } #[cfg(feature = "sqlx-sqlite")] QueryResultRow::SqlxSqlite(row) => { use sqlx::Row; - Ok(row.try_get(column.as_str())?) + row.try_get(column.as_str()).map_err(crate::sqlx_error_to_query_err) } #[cfg(feature = "mock")] QueryResultRow::Mock(row) => Ok(row.try_get(column.as_str())?), @@ -109,7 +109,7 @@ macro_rules! try_getable_mysql { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - Ok(row.try_get(column.as_str())?) + row.try_get(column.as_str()).map_err(crate::sqlx_error_to_query_err) } #[cfg(feature = "sqlx-sqlite")] QueryResultRow::SqlxSqlite(_) => {