Skip to content

Commit

Permalink
Merge pull request #1002 from SeaQL/better-errors
Browse files Browse the repository at this point in the history
Better error system
  • Loading branch information
tyt2y3 authored Oct 6, 2022
2 parents ae198e6 + a44017f commit 5d752e6
Show file tree
Hide file tree
Showing 20 changed files with 242 additions and 163 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ uuid = { version = "^1", features = ["serde", "v4"], optional = true }
ouroboros = "0.15"
url = "^2.2"
once_cell = "1.8"
thiserror = "^1"

[dev-dependencies]
smol = { version = "^1.2" }
Expand Down
5 changes: 1 addition & 4 deletions issues/324/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ macro_rules! impl_try_from_u64_err {
($newtype: ident) => {
impl sea_orm::TryFromU64 for $newtype {
fn try_from_u64(_n: u64) -> Result<Self, sea_orm::DbErr> {
Err(sea_orm::DbErr::Exec(format!(
"{} cannot be converted from u64",
stringify!($newtype)
)))
Err(sea_orm::DbErr::ConvertFromU64(stringify!($newtype)))
}
}
};
Expand Down
7 changes: 2 additions & 5 deletions issues/400/src/model.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::marker::PhantomData;
use sea_orm::entity::prelude::*;
use std::marker::PhantomData;

#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "model")]
Expand Down Expand Up @@ -31,10 +31,7 @@ impl<T> From<AccountId<T>> for Uuid {

impl<T> sea_orm::TryFromU64 for AccountId<T> {
fn try_from_u64(_n: u64) -> Result<Self, sea_orm::DbErr> {
Err(sea_orm::DbErr::Exec(format!(
"{} cannot be converted from u64",
stringify!(AccountId<T>)
)))
Err(sea_orm::DbErr::ConvertFromU64(stringify!(AccountId<T>)))
}
}

Expand Down
4 changes: 2 additions & 2 deletions sea-orm-macros/src/derives/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStrea
))
}

/// Implement a column using for an enum using [DeriveColumn](sea_orm::DeriveColumn)
/// Implement a column for an enum using [DeriveColumn](sea_orm::DeriveColumn)
pub fn impl_col_from_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
let data_enum = match data {
Data::Enum(data_enum) => data_enum,
Expand Down Expand Up @@ -99,7 +99,7 @@ pub fn impl_col_from_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream>
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s {
#(#columns),*,
_ => Err(sea_orm::ColumnFromStrErr(format!("Failed to parse '{}' as `{}`", s, stringify!(#ident)))),
_ => Err(sea_orm::ColumnFromStrErr(s.to_owned())),
}
}
}
Expand Down
12 changes: 9 additions & 3 deletions src/database/db_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ impl ConnectionTrait for DatabaseConnection {
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.execute(stmt).await,
#[cfg(feature = "mock")]
DatabaseConnection::MockDatabaseConnection(conn) => conn.execute(stmt),
DatabaseConnection::Disconnected => Err(DbErr::Conn("Disconnected".to_owned())),
DatabaseConnection::Disconnected => {
Err(DbErr::Conn(RuntimeErr::Internal("Disconnected".to_owned())))
}
}
}

Expand All @@ -132,7 +134,9 @@ impl ConnectionTrait for DatabaseConnection {
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.query_one(stmt).await,
#[cfg(feature = "mock")]
DatabaseConnection::MockDatabaseConnection(conn) => conn.query_one(stmt),
DatabaseConnection::Disconnected => Err(DbErr::Conn("Disconnected".to_owned())),
DatabaseConnection::Disconnected => {
Err(DbErr::Conn(RuntimeErr::Internal("Disconnected".to_owned())))
}
}
}

Expand All @@ -148,7 +152,9 @@ impl ConnectionTrait for DatabaseConnection {
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.query_all(stmt).await,
#[cfg(feature = "mock")]
DatabaseConnection::MockDatabaseConnection(conn) => conn.query_all(stmt),
DatabaseConnection::Disconnected => Err(DbErr::Conn("Disconnected".to_owned())),
DatabaseConnection::Disconnected => {
Err(DbErr::Conn(RuntimeErr::Internal("Disconnected".to_owned())))
}
}
}

Expand Down
10 changes: 7 additions & 3 deletions src/database/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ impl MockDatabaseTrait for MockDatabase {
result: ExecResultHolder::Mock(std::mem::take(&mut self.exec_results[counter])),
})
} else {
Err(DbErr::Exec("`exec_results` buffer is empty.".to_owned()))
Err(DbErr::Exec(RuntimeErr::Internal(
"`exec_results` buffer is empty.".to_owned(),
)))
}
}

Expand All @@ -121,7 +123,9 @@ impl MockDatabaseTrait for MockDatabase {
})
.collect())
} else {
Err(DbErr::Query("`query_results` buffer is empty.".to_owned()))
Err(DbErr::Query(RuntimeErr::Internal(
"`query_results` buffer is empty.".to_owned(),
)))
}
}

Expand Down Expand Up @@ -176,7 +180,7 @@ impl MockRow {
where
T: ValueType,
{
T::try_from(self.values.get(col).unwrap().clone()).map_err(|e| DbErr::Query(e.to_string()))
T::try_from(self.values.get(col).unwrap().clone()).map_err(|e| DbErr::Type(e.to_string()))
}

/// An iterator over the keys and values of a mock row
Expand Down
6 changes: 3 additions & 3 deletions src/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub use stream::*;
use tracing::instrument;
pub use transaction::*;

use crate::DbErr;
use crate::{DbErr, RuntimeErr};

/// Defines a database
#[derive(Debug, Default)]
Expand Down Expand Up @@ -75,10 +75,10 @@ impl Database {
if crate::MockDatabaseConnector::accepts(&opt.url) {
return crate::MockDatabaseConnector::connect(&opt.url).await;
}
Err(DbErr::Conn(format!(
Err(DbErr::Conn(RuntimeErr::Internal(format!(
"The connection string '{}' has no supporting driver.",
opt.url
)))
))))
}
}

Expand Down
49 changes: 31 additions & 18 deletions src/database/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,17 @@ impl DatabaseTransaction {
}
}
}

#[cfg(feature = "sqlx-dep")]
fn map_err_ignore_not_found<T: std::fmt::Debug>(
err: Result<Option<T>, sqlx::Error>,
) -> Result<Option<T>, DbErr> {
if let Err(sqlx::Error::RowNotFound) = err {
Ok(None)
} else {
err.map_err(|e| sqlx_error_to_query_err(e))
}
}
}

impl Drop for DatabaseTransaction {
Expand All @@ -258,68 +269,69 @@ impl ConnectionTrait for DatabaseTransaction {
async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr> {
debug_print!("{}", stmt);

let _res = match &mut *self.conn.lock().await {
match &mut *self.conn.lock().await {
#[cfg(feature = "sqlx-mysql")]
InnerConnection::MySql(conn) => {
let query = crate::driver::sqlx_mysql::sqlx_query(&stmt);
crate::metric::metric!(self.metric_callback, &stmt, {
query.execute(conn).await.map(Into::into)
})
.map_err(sqlx_error_to_exec_err)
}
#[cfg(feature = "sqlx-postgres")]
InnerConnection::Postgres(conn) => {
let query = crate::driver::sqlx_postgres::sqlx_query(&stmt);
crate::metric::metric!(self.metric_callback, &stmt, {
query.execute(conn).await.map(Into::into)
})
.map_err(sqlx_error_to_exec_err)
}
#[cfg(feature = "sqlx-sqlite")]
InnerConnection::Sqlite(conn) => {
let query = crate::driver::sqlx_sqlite::sqlx_query(&stmt);
crate::metric::metric!(self.metric_callback, &stmt, {
query.execute(conn).await.map(Into::into)
})
.map_err(sqlx_error_to_exec_err)
}
#[cfg(feature = "mock")]
InnerConnection::Mock(conn) => return conn.execute(stmt),
#[allow(unreachable_patterns)]
_ => unreachable!(),
};
#[cfg(feature = "sqlx-dep")]
_res.map_err(sqlx_error_to_exec_err)
}
}

#[instrument(level = "trace")]
#[allow(unused_variables)]
async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
debug_print!("{}", stmt);

let _res = match &mut *self.conn.lock().await {
match &mut *self.conn.lock().await {
#[cfg(feature = "sqlx-mysql")]
InnerConnection::MySql(conn) => {
let query = crate::driver::sqlx_mysql::sqlx_query(&stmt);
query.fetch_one(conn).await.map(|row| Some(row.into()))
Self::map_err_ignore_not_found(
query.fetch_one(conn).await.map(|row| Some(row.into())),
)
}
#[cfg(feature = "sqlx-postgres")]
InnerConnection::Postgres(conn) => {
let query = crate::driver::sqlx_postgres::sqlx_query(&stmt);
query.fetch_one(conn).await.map(|row| Some(row.into()))
Self::map_err_ignore_not_found(
query.fetch_one(conn).await.map(|row| Some(row.into())),
)
}
#[cfg(feature = "sqlx-sqlite")]
InnerConnection::Sqlite(conn) => {
let query = crate::driver::sqlx_sqlite::sqlx_query(&stmt);
query.fetch_one(conn).await.map(|row| Some(row.into()))
Self::map_err_ignore_not_found(
query.fetch_one(conn).await.map(|row| Some(row.into())),
)
}
#[cfg(feature = "mock")]
InnerConnection::Mock(conn) => return conn.query_one(stmt),
#[allow(unreachable_patterns)]
_ => unreachable!(),
};
#[cfg(feature = "sqlx-dep")]
if let Err(sqlx::Error::RowNotFound) = _res {
Ok(None)
} else {
_res.map_err(sqlx_error_to_query_err)
}
}

Expand All @@ -328,14 +340,15 @@ impl ConnectionTrait for DatabaseTransaction {
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr> {
debug_print!("{}", stmt);

let _res = match &mut *self.conn.lock().await {
match &mut *self.conn.lock().await {
#[cfg(feature = "sqlx-mysql")]
InnerConnection::MySql(conn) => {
let query = crate::driver::sqlx_mysql::sqlx_query(&stmt);
query
.fetch_all(conn)
.await
.map(|rows| rows.into_iter().map(|r| r.into()).collect())
.map_err(sqlx_error_to_query_err)
}
#[cfg(feature = "sqlx-postgres")]
InnerConnection::Postgres(conn) => {
Expand All @@ -344,6 +357,7 @@ impl ConnectionTrait for DatabaseTransaction {
.fetch_all(conn)
.await
.map(|rows| rows.into_iter().map(|r| r.into()).collect())
.map_err(sqlx_error_to_query_err)
}
#[cfg(feature = "sqlx-sqlite")]
InnerConnection::Sqlite(conn) => {
Expand All @@ -352,14 +366,13 @@ impl ConnectionTrait for DatabaseTransaction {
.fetch_all(conn)
.await
.map(|rows| rows.into_iter().map(|r| r.into()).collect())
.map_err(sqlx_error_to_query_err)
}
#[cfg(feature = "mock")]
InnerConnection::Mock(conn) => return conn.query_all(stmt),
#[allow(unreachable_patterns)]
_ => unreachable!(),
};
#[cfg(feature = "sqlx-dep")]
_res.map_err(sqlx_error_to_query_err)
}
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/driver/sqlx_common.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use crate::DbErr;
use crate::{DbErr, RuntimeErr};

/// Converts an [sqlx::error] execution error to a [DbErr]
pub fn sqlx_error_to_exec_err(err: sqlx::Error) -> DbErr {
DbErr::Exec(err.to_string())
DbErr::Exec(RuntimeErr::SqlxError(err))
}

/// Converts an [sqlx::error] query error to a [DbErr]
pub fn sqlx_error_to_query_err(err: sqlx::Error) -> DbErr {
DbErr::Query(err.to_string())
DbErr::Query(RuntimeErr::SqlxError(err))
}

/// Converts an [sqlx::error] connection error to a [DbErr]
pub fn sqlx_error_to_conn_err(err: sqlx::Error) -> DbErr {
DbErr::Conn(err.to_string())
DbErr::Conn(RuntimeErr::SqlxError(err))
}
28 changes: 8 additions & 20 deletions src/driver/sqlx_mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl SqlxMySqlConnector {
let mut opt = options
.url
.parse::<MySqlConnectOptions>()
.map_err(|e| DbErr::Conn(e.to_string()))?;
.map_err(sqlx_error_to_conn_err)?;
use sqlx::ConnectOptions;
if !options.sqlx_logging {
opt.disable_statement_logging();
Expand Down Expand Up @@ -89,9 +89,7 @@ impl SqlxMySqlPoolConnection {
}
})
} else {
Err(DbErr::Exec(
"Failed to acquire connection from pool.".to_owned(),
))
Err(DbErr::ConnectionAcquire)
}
}

Expand All @@ -107,14 +105,12 @@ impl SqlxMySqlPoolConnection {
Ok(row) => Ok(Some(row.into())),
Err(err) => match err {
sqlx::Error::RowNotFound => Ok(None),
_ => Err(DbErr::Query(err.to_string())),
_ => Err(sqlx_error_to_query_err(err)),
},
}
})
} else {
Err(DbErr::Query(
"Failed to acquire connection from pool.".to_owned(),
))
Err(DbErr::ConnectionAcquire)
}
}

Expand All @@ -132,9 +128,7 @@ impl SqlxMySqlPoolConnection {
}
})
} else {
Err(DbErr::Query(
"Failed to acquire connection from pool.".to_owned(),
))
Err(DbErr::ConnectionAcquire)
}
}

Expand All @@ -150,9 +144,7 @@ impl SqlxMySqlPoolConnection {
self.metric_callback.clone(),
)))
} else {
Err(DbErr::Query(
"Failed to acquire connection from pool.".to_owned(),
))
Err(DbErr::ConnectionAcquire)
}
}

Expand All @@ -162,9 +154,7 @@ impl SqlxMySqlPoolConnection {
if let Ok(conn) = self.pool.acquire().await {
DatabaseTransaction::new_mysql(conn, self.metric_callback.clone()).await
} else {
Err(DbErr::Query(
"Failed to acquire connection from pool.".to_owned(),
))
Err(DbErr::ConnectionAcquire)
}
}

Expand All @@ -185,9 +175,7 @@ impl SqlxMySqlPoolConnection {
.map_err(|e| TransactionError::Connection(e))?;
transaction.run(callback).await
} else {
Err(TransactionError::Connection(DbErr::Query(
"Failed to acquire connection from pool.".to_owned(),
)))
Err(TransactionError::Connection(DbErr::ConnectionAcquire))
}
}

Expand Down
Loading

0 comments on commit 5d752e6

Please sign in to comment.