Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better error system #1002

Merged
merged 15 commits into from
Oct 6, 2022
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,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::CannotConvertFromU64(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::CannotConvertFromU64(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 @@ -73,10 +73,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::ConnFromPool)
}
}

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::ConnFromPool)
}
}

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

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::ConnFromPool)
}
}

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::ConnFromPool)
}
}

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::ConnFromPool))
}
}

Expand Down
Loading