Use MockDatabase in doc test

This commit is contained in:
Chris Tsang 2021-06-27 15:57:22 +08:00
parent a0db19758b
commit 688891f706
6 changed files with 154 additions and 159 deletions

View File

@ -1,4 +1,4 @@
use crate::{ExecErr, ExecResult, QueryErr, QueryResult, Statement};
use crate::{ExecErr, ExecResult, QueryErr, QueryResult, Statement, Transaction};
use sea_query::{
MysqlQueryBuilder, PostgresQueryBuilder, QueryStatementBuilder, SqliteQueryBuilder,
};
@ -118,6 +118,11 @@ impl DatabaseConnection {
pub fn as_mock_connection(&self) -> Option<bool> {
None
}
pub fn into_transaction_log(self) -> Vec<Transaction> {
let mut mocker = self.as_mock_connection().get_mocker_mutex().lock().unwrap();
mocker.drain_transaction_log()
}
}
impl QueryBuilderBackend {

View File

@ -1,4 +1,5 @@
use crate::Statement;
use sea_query::{Value, Values};
#[derive(Debug, Clone, PartialEq)]
pub struct Transaction {
@ -6,6 +7,16 @@ pub struct Transaction {
}
impl Transaction {
pub fn from_sql_and_values<I>(sql: &str, values: I) -> Self
where
I: IntoIterator<Item = Value>,
{
Self::one(Statement {
sql: sql.to_owned(),
values: Some(Values(values.into_iter().collect())),
})
}
/// Create a Transaction with one statement
pub fn one(stmt: Statement) -> Self {
Self { stmts: vec![stmt] }

View File

@ -42,17 +42,6 @@ impl Default for ActiveValueState {
}
}
pub trait OneOrManyActiveModel<A>
where
A: ActiveModelTrait,
{
fn is_one() -> bool;
fn get_one(self) -> A;
fn is_many() -> bool;
fn get_many(self) -> Vec<A>;
}
#[doc(hidden)]
pub fn unchanged_active_value_not_intended_for_public_use<V>(value: V) -> ActiveValue<V>
where
@ -197,44 +186,6 @@ where
}
}
impl<A> OneOrManyActiveModel<A> for A
where
A: ActiveModelTrait,
{
fn is_one() -> bool {
true
}
fn get_one(self) -> A {
self
}
fn is_many() -> bool {
false
}
fn get_many(self) -> Vec<A> {
panic!("not many")
}
}
impl<A> OneOrManyActiveModel<A> for Vec<A>
where
A: ActiveModelTrait,
{
fn is_one() -> bool {
false
}
fn get_one(self) -> A {
panic!("not one")
}
fn is_many() -> bool {
true
}
fn get_many(self) -> Vec<A> {
self
}
}
/// Insert the model if primary key is unset, update otherwise.
/// Only works if the entity has auto increment primary key.
pub async fn save_active_model<A, E>(mut am: A, db: &DatabaseConnection) -> Result<A, ExecErr>

View File

@ -1,7 +1,7 @@
use crate::{
ActiveModelTrait, ColumnTrait, Delete, DeleteOne, FromQueryResult, Insert, ModelTrait,
OneOrManyActiveModel, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, Related,
RelationBuilder, RelationTrait, RelationType, Select, Update, UpdateOne,
PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, Related, RelationBuilder, RelationTrait,
RelationType, Select, Update, UpdateMany, UpdateOne,
};
use sea_query::{Iden, IntoValueTuple};
use std::fmt::Debug;
@ -50,14 +50,27 @@ pub trait EntityTrait: EntityName {
}
/// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder};
/// # #[cfg(feature = "mock")]
/// # use sea_orm::{MockDatabase, Transaction};
/// # let db = MockDatabase::new().into_connection();
/// #
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
///
/// # async_std::task::block_on(async {
/// cake::Entity::find().one(&db).await;
/// cake::Entity::find().all(&db).await;
/// # });
///
/// assert_eq!(
/// cake::Entity::find()
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// r#"SELECT "cake"."id", "cake"."name" FROM "cake""#
/// );
/// db.into_transaction_log(),
/// vec![
/// Transaction::from_sql_and_values(
/// r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#, vec![1u64.into()]
/// ),
/// Transaction::from_sql_and_values(
/// r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![]
/// ),
/// ]);
/// ```
fn find() -> Select<Self> {
Select::new()
@ -65,28 +78,42 @@ pub trait EntityTrait: EntityName {
/// Find a model by primary key
/// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder};
/// # #[cfg(feature = "mock")]
/// # use sea_orm::{MockDatabase, Transaction};
/// # let db = MockDatabase::new().into_connection();
/// #
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
///
/// # async_std::task::block_on(async {
/// cake::Entity::find_by_id(11).all(&db).await;
/// # });
///
/// assert_eq!(
/// cake::Entity::find_by_id(11)
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" = 11"#
/// );
/// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values(
/// r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" = $1"#, vec![11i32.into()]
/// )]);
/// ```
/// Find by composite key
/// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling, sea_query::PostgresQueryBuilder};
/// # #[cfg(feature = "mock")]
/// # use sea_orm::{MockDatabase, Transaction};
/// # let db = MockDatabase::new().into_connection();
/// #
/// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling};
///
/// # async_std::task::block_on(async {
/// cake_filling::Entity::find_by_id((2, 3)).all(&db).await;
/// # });
///
/// assert_eq!(
/// cake_filling::Entity::find_by_id((2, 3))
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// [
/// r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id" FROM "cake_filling""#,
/// r#"WHERE "cake_filling"."cake_id" = 2 AND "cake_filling"."filling_id" = 3"#,
/// ].join(" ")
/// );
/// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values([
/// r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id" FROM "cake_filling""#,
/// r#"WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#,
/// ].join(" ").as_str(),
/// vec![2i32.into(), 3i32.into()]
/// )]);
/// ```
fn find_by_id<V>(values: V) -> Select<Self>
where
@ -108,69 +135,29 @@ pub trait EntityTrait: EntityName {
select
}
/// Insert one
/// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder};
/// # #[cfg(feature = "mock")]
/// # use sea_orm::{MockDatabase, Transaction};
/// # let db = MockDatabase::new().into_connection();
/// #
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
///
/// let apple = cake::ActiveModel {
/// name: Set("Apple Pie".to_owned()),
/// ..Default::default()
/// };
/// assert_eq!(
/// cake::Entity::insert(apple)
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#,
/// );
/// ```
/// Insert many
/// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder};
///
/// let apple = cake::ActiveModel {
/// name: Set("Apple Pie".to_owned()),
/// ..Default::default()
/// };
/// let orange = cake::ActiveModel {
/// name: Set("Orange Scone".to_owned()),
/// ..Default::default()
/// };
/// assert_eq!(
/// cake::Entity::insert(vec![apple, orange])
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie'), ('Orange Scone')"#,
/// );
/// ```
fn insert<A, C>(models: C) -> Insert<A>
where
A: ActiveModelTrait<Entity = Self>,
C: OneOrManyActiveModel<A>,
{
if C::is_one() {
Self::insert_one(models.get_one())
} else if C::is_many() {
Self::insert_many(models.get_many())
} else {
unreachable!()
}
}
/// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder};
/// # async_std::task::block_on(async {
/// cake::Entity::insert(apple).exec(&db).await;
/// # });
///
/// let apple = cake::ActiveModel {
/// name: Set("Apple Pie".to_owned()),
/// ..Default::default()
/// };
/// assert_eq!(
/// cake::Entity::insert_one(apple)
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#,
/// );
/// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values(
/// r#"INSERT INTO "cake" ("name") VALUES ($1)"#, vec!["Apple Pie".into()]
/// )]);
/// ```
fn insert_one<A>(model: A) -> Insert<A>
fn insert<A>(model: A) -> Insert<A>
where
A: ActiveModelTrait<Entity = Self>,
{
@ -178,7 +165,11 @@ pub trait EntityTrait: EntityName {
}
/// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder};
/// # #[cfg(feature = "mock")]
/// # use sea_orm::{MockDatabase, Transaction};
/// # let db = MockDatabase::new().into_connection();
/// #
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
///
/// let apple = cake::ActiveModel {
/// name: Set("Apple Pie".to_owned()),
@ -188,12 +179,17 @@ pub trait EntityTrait: EntityName {
/// name: Set("Orange Scone".to_owned()),
/// ..Default::default()
/// };
///
/// # async_std::task::block_on(async {
/// cake::Entity::insert_many(vec![apple, orange]).exec(&db).await;
/// # });
///
/// assert_eq!(
/// cake::Entity::insert_many(vec![apple, orange])
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie'), ('Orange Scone')"#,
/// );
/// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values(
/// r#"INSERT INTO "cake" ("name") VALUES ($1), ($2)"#,
/// vec!["Apple Pie".into(), "Orange Scone".into()]
/// )]);
/// ```
fn insert_many<A, I>(models: I) -> Insert<A>
where
@ -204,19 +200,27 @@ pub trait EntityTrait: EntityName {
}
/// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit, sea_query::PostgresQueryBuilder};
/// # #[cfg(feature = "mock")]
/// # use sea_orm::{MockDatabase, Transaction};
/// # let db = MockDatabase::new().into_connection();
/// #
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
///
/// let orange = fruit::ActiveModel {
/// id: Set(1),
/// name: Set("Orange".to_owned()),
/// ..Default::default()
/// };
///
/// # async_std::task::block_on(async {
/// fruit::Entity::update(orange).exec(&db).await;
/// # });
///
/// assert_eq!(
/// fruit::Entity::update(orange)
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// r#"UPDATE "fruit" SET "name" = 'Orange' WHERE "fruit"."id" = 1"#,
/// );
/// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values(
/// r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2"#, vec!["Orange".into(), 1i32.into()]
/// )]);
/// ```
fn update<A>(model: A) -> UpdateOne<A>
where
@ -226,18 +230,51 @@ pub trait EntityTrait: EntityName {
}
/// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit, sea_query::PostgresQueryBuilder};
/// # #[cfg(feature = "mock")]
/// # use sea_orm::{MockDatabase, Transaction};
/// # let db = MockDatabase::new().into_connection();
/// #
/// use sea_orm::{entity::*, query::*, tests_cfg::{cake, fruit}, sea_query::{Expr, Value}};
///
/// # async_std::task::block_on(async {
/// fruit::Entity::update_many()
/// .col_expr(fruit::Column::CakeId, Expr::value(Value::Null))
/// .filter(fruit::Column::Name.contains("Apple"))
/// .exec(&db)
/// .await;
/// # });
///
/// assert_eq!(
/// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values(
/// r#"UPDATE "fruit" SET "cake_id" = $1 WHERE "fruit"."name" LIKE $2"#, vec![Value::Null, "%Apple%".into()]
/// )]);
/// ```
fn update_many() -> UpdateMany<Self> {
Update::many(Self::default())
}
/// ```
/// # #[cfg(feature = "mock")]
/// # use sea_orm::{MockDatabase, Transaction};
/// # let db = MockDatabase::new().into_connection();
/// #
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
///
/// let orange = fruit::ActiveModel {
/// id: Set(3),
/// ..Default::default()
/// };
///
/// # async_std::task::block_on(async {
/// fruit::Entity::delete(orange).exec(&db).await;
/// # });
///
/// assert_eq!(
/// fruit::Entity::delete(orange)
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// r#"DELETE FROM "fruit" WHERE "fruit"."id" = 3"#,
/// );
/// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values(
/// r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#, vec![3i32.into()]
/// )]);
/// ```
fn delete<A>(model: A) -> DeleteOne<A>
where

View File

@ -175,9 +175,7 @@ mod tests {
query_builder.build(select.offset(4).limit(2)),
];
let mut mocker = db.as_mock_connection().get_mocker_mutex().lock().unwrap();
assert_eq!(mocker.drain_transaction_log(), Transaction::wrap(stmts));
assert_eq!(db.into_transaction_log(), Transaction::wrap(stmts));
Ok(())
}
@ -211,9 +209,7 @@ mod tests {
query_builder.build(select.offset(4).limit(2)),
];
let mut mocker = db.as_mock_connection().get_mocker_mutex().lock().unwrap();
assert_eq!(mocker.drain_transaction_log(), Transaction::wrap(stmts));
assert_eq!(db.into_transaction_log(), Transaction::wrap(stmts));
Ok(())
}
@ -244,9 +240,8 @@ mod tests {
let query_builder = db.get_query_builder_backend();
let stmts = vec![query_builder.build(&select)];
let mut mocker = db.as_mock_connection().get_mocker_mutex().lock().unwrap();
assert_eq!(mocker.drain_transaction_log(), Transaction::wrap(stmts));
assert_eq!(db.into_transaction_log(), Transaction::wrap(stmts));
Ok(())
}
@ -297,9 +292,7 @@ mod tests {
query_builder.build(select.offset(4).limit(2)),
];
let mut mocker = db.as_mock_connection().get_mocker_mutex().lock().unwrap();
assert_eq!(mocker.drain_transaction_log(), Transaction::wrap(stmts));
assert_eq!(db.into_transaction_log(), Transaction::wrap(stmts));
Ok(())
}
@ -331,9 +324,7 @@ mod tests {
query_builder.build(select.offset(4).limit(2)),
];
let mut mocker = db.as_mock_connection().get_mocker_mutex().lock().unwrap();
assert_eq!(mocker.drain_transaction_log(), Transaction::wrap(stmts));
assert_eq!(db.into_transaction_log(), Transaction::wrap(stmts));
Ok(())
}
}

View File

@ -20,4 +20,4 @@ pub use select::*;
pub use traits::*;
pub use update::*;
pub use crate::executor::{ExecErr, QueryErr};
pub use crate::executor::{ExecErr, InsertResult, QueryErr, UpdateResult};