use sea_orm::{
AccessMode, ConnectionTrait, DatabaseTransaction, DbBackend, DbErr, ExecResult, IsolationLevel,
QueryResult, Statement, TransactionError, TransactionOptions, TransactionTrait,
};
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
#[cfg(not(feature = "test-utils"))]
type Inner = sea_orm::DatabaseConnection;
#[cfg(feature = "test-utils")]
type Inner = crate::db::RuniqueDb;
#[derive(Clone, Debug)]
pub struct ADb(Arc<Inner>);
impl ADb {
pub fn new(inner: Inner) -> Self {
Self(Arc::new(inner))
}
#[cfg(not(feature = "test-utils"))]
pub fn from_connection(conn: sea_orm::DatabaseConnection) -> Self {
Self::new(conn)
}
#[cfg(feature = "test-utils")]
pub fn from_connection(conn: sea_orm::DatabaseConnection) -> Self {
Self::new(crate::db::RuniqueDb::Conn(conn))
}
#[cfg(feature = "test-utils")]
pub(crate) fn into_inner(self) -> Option<Inner> {
Arc::into_inner(self.0)
}
#[cfg(feature = "test-utils")]
pub(crate) fn is_shared(&self) -> bool {
Arc::strong_count(&self.0) > 1
}
pub fn get_database_backend(&self) -> DbBackend {
ConnectionTrait::get_database_backend(self)
}
}
impl std::ops::Deref for ADb {
type Target = Inner;
fn deref(&self) -> &Inner {
&self.0
}
}
impl From<Inner> for ADb {
fn from(inner: Inner) -> Self {
Self::new(inner)
}
}
#[async_trait::async_trait]
impl ConnectionTrait for ADb {
fn get_database_backend(&self) -> DbBackend {
self.0.get_database_backend()
}
async fn execute_raw(&self, stmt: Statement) -> Result<ExecResult, DbErr> {
self.0.execute_raw(stmt).await
}
async fn execute_unprepared(&self, sql: &str) -> Result<ExecResult, DbErr> {
#[cfg(feature = "test-utils")]
let started = std::time::Instant::now();
let result = self.0.execute_unprepared(sql).await;
#[cfg(feature = "test-utils")]
crate::runique_test::logic::builder_test::record(sql, started.elapsed(), result.is_err());
result
}
async fn query_one_raw(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
self.0.query_one_raw(stmt).await
}
async fn query_all_raw(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr> {
self.0.query_all_raw(stmt).await
}
}
#[async_trait::async_trait]
impl TransactionTrait for ADb {
type Transaction = DatabaseTransaction;
async fn begin(&self) -> Result<Self::Transaction, DbErr> {
self.0.begin().await
}
async fn begin_with_config(
&self,
isolation_level: Option<IsolationLevel>,
access_mode: Option<AccessMode>,
) -> Result<Self::Transaction, DbErr> {
self.0.begin_with_config(isolation_level, access_mode).await
}
async fn begin_with_options(
&self,
options: TransactionOptions,
) -> Result<Self::Transaction, DbErr> {
self.0.begin_with_options(options).await
}
async fn transaction<F, T, E>(&self, callback: F) -> Result<T, TransactionError<E>>
where
F: for<'c> FnOnce(
&'c Self::Transaction,
) -> Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'c>>
+ Send,
T: Send,
E: std::fmt::Display + std::fmt::Debug + Send,
{
self.0.transaction(callback).await
}
async fn transaction_with_config<F, T, E>(
&self,
callback: F,
isolation_level: Option<IsolationLevel>,
access_mode: Option<AccessMode>,
) -> Result<T, TransactionError<E>>
where
F: for<'c> FnOnce(
&'c Self::Transaction,
) -> Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'c>>
+ Send,
T: Send,
E: std::fmt::Display + std::fmt::Debug + Send,
{
self.0
.transaction_with_config(callback, isolation_level, access_mode)
.await
}
}