sea-orm/src/database/mock.rs
Billy Chan 62fb43c605
Add unit test for pagination (#20)
* Add unit test for pagination

* End with empty page

* Add more test cases

* Assert transaction log

* Test utils

* Feature gated

* IntoMockRow, derive macro with into MockRow

* Revert derive macro

* WIP

* WIP

* assert_transaction_log
2021-06-18 23:43:07 +08:00

137 lines
3.5 KiB
Rust

use crate::{
Database, DatabaseConnection, ExecErr, ExecResult, ExecResultHolder, MockDatabaseConnection,
MockDatabaseTrait, QueryErr, QueryResult, QueryResultRow, Statement, TypeErr,
};
use sea_query::{Value, ValueType};
use std::collections::BTreeMap;
#[derive(Debug, Default)]
pub struct MockDatabase {
transaction_log: Vec<Statement>,
exec_results: Vec<MockExecResult>,
query_results: Vec<Vec<MockRow>>,
}
#[derive(Clone, Debug, Default)]
pub struct MockExecResult {
pub last_insert_id: u64,
pub rows_affected: u64,
}
#[derive(Clone, Debug)]
pub struct MockRow {
values: BTreeMap<String, Value>,
}
impl MockDatabase {
pub fn new() -> Self {
Default::default()
}
pub fn into_database(self) -> Database {
Database {
connection: DatabaseConnection::MockDatabaseConnection(MockDatabaseConnection::new(
self,
)),
}
}
pub fn append_exec_results(mut self, mut vec: Vec<MockExecResult>) -> Self {
self.exec_results.append(&mut vec);
self
}
pub fn append_query_results<T>(mut self, vec: Vec<Vec<T>>) -> Self
where
T: IntoMockRow,
{
for row in vec.into_iter() {
let row = row.into_iter().map(|vec| vec.into_mock_row()).collect();
self.query_results.push(row);
}
self
}
pub fn into_transaction_log(self) -> Vec<Statement> {
self.transaction_log
}
}
impl MockDatabaseTrait for MockDatabase {
fn execute(&mut self, counter: usize, statement: Statement) -> Result<ExecResult, ExecErr> {
self.transaction_log.push(statement);
if counter < self.exec_results.len() {
Ok(ExecResult {
result: ExecResultHolder::Mock(std::mem::take(&mut self.exec_results[counter])),
})
} else {
Err(ExecErr)
}
}
fn query(
&mut self,
counter: usize,
statement: Statement,
) -> Result<Vec<QueryResult>, QueryErr> {
self.transaction_log.push(statement);
if counter < self.query_results.len() {
Ok(std::mem::take(&mut self.query_results[counter])
.into_iter()
.map(|row| QueryResult {
row: QueryResultRow::Mock(row),
})
.collect())
} else {
Err(QueryErr)
}
}
fn into_transaction_log(&mut self) -> Vec<Statement> {
std::mem::take(&mut self.transaction_log)
}
fn assert_transaction_log(&mut self, stmts: Vec<Statement>) {
for stmt in stmts.iter() {
assert!(!self.transaction_log.is_empty());
let log = self.transaction_log.first().unwrap();
assert_eq!(log.to_string(), stmt.to_string());
self.transaction_log = self.transaction_log.drain(1..).collect();
}
}
}
impl MockRow {
pub fn try_get<T>(&self, col: &str) -> Result<T, TypeErr>
where
T: ValueType,
{
Ok(self.values.get(col).unwrap().clone().unwrap())
}
pub fn into_column_value_tuples(self) -> impl Iterator<Item = (String, Value)> {
self.values.into_iter()
}
}
impl From<BTreeMap<&str, Value>> for MockRow {
fn from(values: BTreeMap<&str, Value>) -> Self {
Self {
values: values.into_iter().map(|(k, v)| (k.to_owned(), v)).collect(),
}
}
}
pub trait IntoMockRow {
fn into_mock_row(self) -> MockRow;
}
impl<T> IntoMockRow for T
where
T: Into<MockRow>,
{
fn into_mock_row(self) -> MockRow {
self.into()
}
}