1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
use crate::{ debug_print, error::*, DatabaseConnection, DbBackend, ExecResult, MockDatabase, QueryResult, Statement, Transaction, }; use std::sync::{ atomic::{AtomicUsize, Ordering}, Mutex, }; pub struct MockDatabaseConnector; pub struct MockDatabaseConnection { counter: AtomicUsize, mocker: Mutex<Box<dyn MockDatabaseTrait>>, } pub trait MockDatabaseTrait: Send { fn execute(&mut self, counter: usize, stmt: Statement) -> Result<ExecResult, DbErr>; fn query(&mut self, counter: usize, stmt: Statement) -> Result<Vec<QueryResult>, DbErr>; fn drain_transaction_log(&mut self) -> Vec<Transaction>; fn get_database_backend(&self) -> DbBackend; } impl MockDatabaseConnector { pub fn accepts(string: &str) -> bool { #[cfg(feature = "sqlx-mysql")] if crate::SqlxMySqlConnector::accepts(string) { return true; } #[cfg(feature = "sqlx-postgres")] if crate::SqlxPostgresConnector::accepts(string) { return true; } #[cfg(feature = "sqlx-sqlite")] if crate::SqlxSqliteConnector::accepts(string) { return true; } false } pub async fn connect(string: &str) -> Result<DatabaseConnection, DbErr> { macro_rules! connect_mock_db { ( $syntax: expr ) => { Ok(DatabaseConnection::MockDatabaseConnection( MockDatabaseConnection::new(MockDatabase::new($syntax)), )) }; } #[cfg(feature = "sqlx-mysql")] if crate::SqlxMySqlConnector::accepts(string) { return connect_mock_db!(DbBackend::MySql); } #[cfg(feature = "sqlx-postgres")] if crate::SqlxPostgresConnector::accepts(string) { return connect_mock_db!(DbBackend::Postgres); } #[cfg(feature = "sqlx-sqlite")] if crate::SqlxSqliteConnector::accepts(string) { return connect_mock_db!(DbBackend::Sqlite); } connect_mock_db!(DbBackend::Postgres) } } impl MockDatabaseConnection { pub fn new<M: 'static>(m: M) -> Self where M: MockDatabaseTrait, { Self { counter: AtomicUsize::new(0), mocker: Mutex::new(Box::new(m)), } } pub fn get_mocker_mutex(&self) -> &Mutex<Box<dyn MockDatabaseTrait>> { &self.mocker } pub async fn execute(&self, statement: Statement) -> Result<ExecResult, DbErr> { debug_print!("{}", statement); let counter = self.counter.fetch_add(1, Ordering::SeqCst); self.mocker.lock().unwrap().execute(counter, statement) } pub async fn query_one(&self, statement: Statement) -> Result<Option<QueryResult>, DbErr> { debug_print!("{}", statement); let counter = self.counter.fetch_add(1, Ordering::SeqCst); let result = self.mocker.lock().unwrap().query(counter, statement)?; Ok(result.into_iter().next()) } pub async fn query_all(&self, statement: Statement) -> Result<Vec<QueryResult>, DbErr> { debug_print!("{}", statement); let counter = self.counter.fetch_add(1, Ordering::SeqCst); self.mocker.lock().unwrap().query(counter, statement) } pub fn get_database_backend(&self) -> DbBackend { self.mocker.lock().unwrap().get_database_backend() } }