Rework DbErr

This commit is contained in:
Chris Tsang 2021-06-30 23:42:12 +08:00
parent dd8d8c3431
commit f5ac84f915
9 changed files with 70 additions and 66 deletions

View File

@ -75,7 +75,7 @@ impl MockDatabaseTrait for MockDatabase {
result: ExecResultHolder::Mock(std::mem::take(&mut self.exec_results[counter])), result: ExecResultHolder::Mock(std::mem::take(&mut self.exec_results[counter])),
}) })
} else { } else {
Err(DbErr::Exec) Err(DbErr::Exec("`exec_results` buffer is empty.".to_owned()))
} }
} }
@ -93,7 +93,7 @@ impl MockDatabaseTrait for MockDatabase {
}) })
.collect()) .collect())
} else { } else {
Err(DbErr::Query) Err(DbErr::Query("`query_results` buffer is empty.".to_owned()))
} }
} }

View File

@ -29,6 +29,6 @@ impl Database {
if crate::MockDatabaseConnector::accepts(string) { if crate::MockDatabaseConnector::accepts(string) {
return crate::MockDatabaseConnector::connect(string).await; return crate::MockDatabaseConnector::connect(string).await;
} }
Err(DbErr::Conn) Err(DbErr::Conn(format!("The connection string '{}' has no supporting driver.", string)))
} }
} }

View File

@ -1,5 +1,7 @@
#[cfg(feature = "mock")] #[cfg(feature = "mock")]
mod mock; mod mock;
#[cfg(feature = "sqlx-dep")]
mod sqlx_common;
#[cfg(feature = "sqlx-mysql")] #[cfg(feature = "sqlx-mysql")]
mod sqlx_mysql; mod sqlx_mysql;
#[cfg(feature = "sqlx-sqlite")] #[cfg(feature = "sqlx-sqlite")]
@ -7,6 +9,8 @@ mod sqlx_sqlite;
#[cfg(feature = "mock")] #[cfg(feature = "mock")]
pub use mock::*; pub use mock::*;
#[cfg(feature = "sqlx-dep")]
pub use sqlx_common::*;
#[cfg(feature = "sqlx-mysql")] #[cfg(feature = "sqlx-mysql")]
pub use sqlx_mysql::*; pub use sqlx_mysql::*;
#[cfg(feature = "sqlx-sqlite")] #[cfg(feature = "sqlx-sqlite")]

View File

@ -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())
}

View File

@ -8,6 +8,8 @@ use sea_query_driver_mysql::bind_query;
use crate::{debug_print, error::*, executor::*, DatabaseConnection, Statement}; use crate::{debug_print, error::*, executor::*, DatabaseConnection, Statement};
use super::sqlx_common::*;
pub struct SqlxMySqlConnector; pub struct SqlxMySqlConnector;
pub struct SqlxMySqlPoolConnection { pub struct SqlxMySqlPoolConnection {
@ -25,7 +27,7 @@ impl SqlxMySqlConnector {
SqlxMySqlPoolConnection { pool }, SqlxMySqlPoolConnection { pool },
)) ))
} else { } else {
Err(DbErr::Conn) Err(DbErr::Conn("Failed to connect.".to_owned()))
} }
} }
} }
@ -42,11 +44,13 @@ impl SqlxMySqlPoolConnection {
let query = sqlx_query(&stmt); let query = sqlx_query(&stmt);
if let Ok(conn) = &mut self.pool.acquire().await { if let Ok(conn) = &mut self.pool.acquire().await {
if let Ok(res) = query.execute(conn).await { match query.execute(conn).await {
return Ok(res.into()); 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<Option<QueryResult>, DbErr> { pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
@ -54,13 +58,15 @@ impl SqlxMySqlPoolConnection {
let query = sqlx_query(&stmt); let query = sqlx_query(&stmt);
if let Ok(conn) = &mut self.pool.acquire().await { if let Ok(conn) = &mut self.pool.acquire().await {
if let Ok(row) = query.fetch_one(conn).await { match query.fetch_one(conn).await {
Ok(Some(row.into())) Ok(row) => Ok(Some(row.into())),
} else { Err(err) => match err {
Ok(None) sqlx::Error::RowNotFound => Ok(None),
_ => Err(DbErr::Query(err.to_string())),
},
} }
} else { } 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); let query = sqlx_query(&stmt);
if let Ok(conn) = &mut self.pool.acquire().await { if let Ok(conn) = &mut self.pool.acquire().await {
if let Ok(rows) = query.fetch_all(conn).await { match query.fetch_all(conn).await {
return Ok(rows.into_iter().map(|r| r.into()).collect()); 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)
} }
} }

View File

@ -8,6 +8,8 @@ use sea_query_driver_sqlite::bind_query;
use crate::{debug_print, error::*, executor::*, DatabaseConnection, Statement}; use crate::{debug_print, error::*, executor::*, DatabaseConnection, Statement};
use super::sqlx_common::*;
pub struct SqlxSqliteConnector; pub struct SqlxSqliteConnector;
pub struct SqlxSqlitePoolConnection { pub struct SqlxSqlitePoolConnection {
@ -25,7 +27,7 @@ impl SqlxSqliteConnector {
SqlxSqlitePoolConnection { pool }, SqlxSqlitePoolConnection { pool },
)) ))
} else { } else {
Err(DbErr::Conn) Err(DbErr::Conn("Failed to connect.".to_owned()))
} }
} }
} }
@ -42,11 +44,13 @@ impl SqlxSqlitePoolConnection {
let query = sqlx_query(&stmt); let query = sqlx_query(&stmt);
if let Ok(conn) = &mut self.pool.acquire().await { if let Ok(conn) = &mut self.pool.acquire().await {
if let Ok(res) = query.execute(conn).await { match query.execute(conn).await {
return Ok(res.into()); 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<Option<QueryResult>, DbErr> { pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
@ -54,13 +58,15 @@ impl SqlxSqlitePoolConnection {
let query = sqlx_query(&stmt); let query = sqlx_query(&stmt);
if let Ok(conn) = &mut self.pool.acquire().await { if let Ok(conn) = &mut self.pool.acquire().await {
if let Ok(row) = query.fetch_one(conn).await { match query.fetch_one(conn).await {
Ok(Some(row.into())) Ok(row) => Ok(Some(row.into())),
} else { Err(err) => match err {
Ok(None) sqlx::Error::RowNotFound => Ok(None),
_ => Err(DbErr::Query(err.to_string())),
},
} }
} else { } 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); let query = sqlx_query(&stmt);
if let Ok(conn) = &mut self.pool.acquire().await { if let Ok(conn) = &mut self.pool.acquire().await {
if let Ok(rows) = query.fetch_all(conn).await { match query.fetch_all(conn).await {
return Ok(rows.into_iter().map(|r| r.into()).collect()); 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)
} }
} }

View File

@ -223,11 +223,11 @@ where
// TODO: if the entity does not have auto increment primary key, then last_insert_id is a wrong value // TODO: if the entity does not have auto increment primary key, then last_insert_id is a wrong value
if <E::PrimaryKey as PrimaryKeyTrait>::auto_increment() && res.last_insert_id != 0 { if <E::PrimaryKey as PrimaryKeyTrait>::auto_increment() && res.last_insert_id != 0 {
let find = E::find_by_id(res.last_insert_id).one(db); let find = E::find_by_id(res.last_insert_id).one(db);
let res = find.await; let found = find.await;
let model: Option<E::Model> = res?; let model: Option<E::Model> = found?;
match model { match model {
Some(model) => Ok(model.into_active_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 { } else {
Ok(A::default()) Ok(A::default())

View File

@ -1,41 +1,16 @@
use std::{error, fmt};
#[derive(Debug)] #[derive(Debug)]
pub enum DbErr { pub enum DbErr {
Conn, Conn(String),
Exec, Exec(String),
Query, Query(String),
#[cfg(feature = "sqlx-dep")]
Sqlx(sqlx::Error),
} }
impl fmt::Display for DbErr { impl std::fmt::Display for DbErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {
Self::Conn => write!(f, "{:?}", "Connection Error"), Self::Conn(s) => write!(f, "Connection Error: {}", s),
Self::Exec => write!(f, "{:?}", "Execution Error"), Self::Exec(s) => write!(f, "Execution Error: {}", s),
Self::Query => write!(f, "{:?}", "Query Error"), Self::Query(s) => write!(f, "Query Error: {}", s),
#[cfg(feature = "sqlx-dep")]
Self::Sqlx(e) => write!(f, "{:?}", e),
} }
} }
} }
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<sqlx::Error> for DbErr {
fn from(sqlx_err: sqlx::Error) -> Self {
Self::Sqlx(sqlx_err)
}
}

View File

@ -56,12 +56,12 @@ macro_rules! try_getable_all {
#[cfg(feature = "sqlx-mysql")] #[cfg(feature = "sqlx-mysql")]
QueryResultRow::SqlxMySql(row) => { QueryResultRow::SqlxMySql(row) => {
use sqlx::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")] #[cfg(feature = "sqlx-sqlite")]
QueryResultRow::SqlxSqlite(row) => { QueryResultRow::SqlxSqlite(row) => {
use sqlx::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")] #[cfg(feature = "mock")]
QueryResultRow::Mock(row) => Ok(row.try_get(column.as_str())?), QueryResultRow::Mock(row) => Ok(row.try_get(column.as_str())?),
@ -109,7 +109,7 @@ macro_rules! try_getable_mysql {
#[cfg(feature = "sqlx-mysql")] #[cfg(feature = "sqlx-mysql")]
QueryResultRow::SqlxMySql(row) => { QueryResultRow::SqlxMySql(row) => {
use sqlx::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")] #[cfg(feature = "sqlx-sqlite")]
QueryResultRow::SqlxSqlite(_) => { QueryResultRow::SqlxSqlite(_) => {