use async_trait::async_trait;
#[async_trait]
pub trait DBTransactionManager<Tx, Conn>: Send + Sync {
type Error: Send + Sync;
type Tx: DatabaseTransaction<Error = Self::Error> + Send + Sync;
async fn begin_transaction(&mut self) -> Result<Self::Tx, Self::Error>;
async fn commit_transaction(tx: &mut Self::Tx) -> Result<(), Self::Error>;
async fn rollback_transaction(tx: &mut Self::Tx) -> Result<(), Self::Error>;
}
#[async_trait]
pub trait DatabaseTransaction: Send + Sync {
type Error: Send + Sync;
async fn commit(&mut self) -> Result<(), Self::Error>;
async fn rollback(&mut self) -> Result<(), Self::Error>;
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::{
DatabaseBackend, DatabaseConfig, DatabaseName, DatabasePool, TestDatabaseConnection,
TestDatabaseInstance,
};
use std::fmt::Debug;
#[derive(Debug, Clone, Default)]
pub struct MockTransaction {
committed: bool,
rolled_back: bool,
}
impl MockTransaction {
pub fn is_committed(&self) -> bool {
self.committed
}
pub fn is_rolled_back(&self) -> bool {
self.rolled_back
}
}
#[async_trait]
impl DatabaseTransaction for MockTransaction {
type Error = String;
async fn commit(&mut self) -> Result<(), Self::Error> {
self.committed = true;
Ok(())
}
async fn rollback(&mut self) -> Result<(), Self::Error> {
self.rolled_back = true;
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct MockConnection(i32);
impl MockConnection {
pub fn set_value(&mut self, value: i32) {
self.0 = value;
}
pub fn get_value(&self) -> i32 {
self.0
}
}
impl TestDatabaseConnection for MockConnection {
fn connection_string(&self) -> String {
format!("mock://localhost/test{}", self.0)
}
}
#[derive(Debug, Clone)]
pub struct MockPool;
#[async_trait]
impl DatabasePool for MockPool {
type Connection = MockConnection;
type Error = String;
async fn acquire(&self) -> Result<Self::Connection, Self::Error> {
Ok(MockConnection(0))
}
async fn release(&self, _conn: Self::Connection) -> Result<(), Self::Error> {
Ok(())
}
fn connection_string(&self) -> String {
"mock://localhost/test".to_string()
}
}
#[derive(Debug, Clone)]
pub struct MockBackend;
#[async_trait]
impl DatabaseBackend for MockBackend {
type Connection = MockConnection;
type Pool = MockPool;
type Error = String;
async fn new(_config: DatabaseConfig) -> Result<Self, Self::Error> {
Ok(MockBackend)
}
async fn connect(&self, _name: &DatabaseName) -> Result<Self::Connection, Self::Error> {
Ok(MockConnection(0))
}
async fn connect_with_string(
&self,
_connection_string: &str,
) -> Result<Self::Connection, Self::Error> {
Ok(MockConnection(0))
}
async fn create_pool(
&self,
_name: &DatabaseName,
_config: &DatabaseConfig,
) -> Result<Self::Pool, Self::Error> {
Ok(MockPool)
}
async fn create_database(
&self,
_pool: &Self::Pool,
_name: &DatabaseName,
) -> Result<(), Self::Error> {
Ok(())
}
fn drop_database(&self, _name: &DatabaseName) -> Result<(), Self::Error> {
Ok(())
}
fn connection_string(&self, _name: &DatabaseName) -> String {
"mock://localhost/test".to_string()
}
}
#[async_trait]
impl DBTransactionManager<MockTransaction, MockConnection> for TestDatabaseInstance<MockBackend> {
type Error = String;
type Tx = MockTransaction;
async fn begin_transaction(&mut self) -> Result<Self::Tx, Self::Error> {
Ok(MockTransaction::default())
}
async fn commit_transaction(tx: &mut Self::Tx) -> Result<(), Self::Error> {
tx.commit().await
}
async fn rollback_transaction(tx: &mut Self::Tx) -> Result<(), Self::Error> {
tx.rollback().await
}
}
}