From 688891f70618982096e2a57ceaeb32788b7eba70 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sun, 27 Jun 2021 15:57:22 +0800 Subject: [PATCH] Use MockDatabase in doc test --- src/database/connection.rs | 7 +- src/database/transaction.rs | 11 ++ src/entity/active_model.rs | 49 -------- src/entity/base_entity.rs | 225 +++++++++++++++++++++--------------- src/executor/paginator.rs | 19 +-- src/query/mod.rs | 2 +- 6 files changed, 154 insertions(+), 159 deletions(-) diff --git a/src/database/connection.rs b/src/database/connection.rs index e2dfbb9b..96170099 100644 --- a/src/database/connection.rs +++ b/src/database/connection.rs @@ -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 { None } + + pub fn into_transaction_log(self) -> Vec { + let mut mocker = self.as_mock_connection().get_mocker_mutex().lock().unwrap(); + mocker.drain_transaction_log() + } } impl QueryBuilderBackend { diff --git a/src/database/transaction.rs b/src/database/transaction.rs index d31a9303..ff9bba4f 100644 --- a/src/database/transaction.rs +++ b/src/database/transaction.rs @@ -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(sql: &str, values: I) -> Self + where + I: IntoIterator, + { + 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] } diff --git a/src/entity/active_model.rs b/src/entity/active_model.rs index f306cb6a..dd35a423 100644 --- a/src/entity/active_model.rs +++ b/src/entity/active_model.rs @@ -42,17 +42,6 @@ impl Default for ActiveValueState { } } -pub trait OneOrManyActiveModel -where - A: ActiveModelTrait, -{ - fn is_one() -> bool; - fn get_one(self) -> A; - - fn is_many() -> bool; - fn get_many(self) -> Vec; -} - #[doc(hidden)] pub fn unchanged_active_value_not_intended_for_public_use(value: V) -> ActiveValue where @@ -197,44 +186,6 @@ where } } -impl OneOrManyActiveModel 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 { - panic!("not many") - } -} - -impl OneOrManyActiveModel for Vec -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 { - 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(mut am: A, db: &DatabaseConnection) -> Result diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs index 1553acd7..19fe6a52 100644 --- a/src/entity/base_entity.rs +++ b/src/entity/base_entity.rs @@ -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 { 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(values: V) -> Select 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(models: C) -> Insert - where - A: ActiveModelTrait, - C: OneOrManyActiveModel, - { - 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(model: A) -> Insert + fn insert(model: A) -> Insert where A: ActiveModelTrait, { @@ -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(models: I) -> Insert 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(model: A) -> UpdateOne 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 { + 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(model: A) -> DeleteOne where diff --git a/src/executor/paginator.rs b/src/executor/paginator.rs index e40c4dc4..ead5114b 100644 --- a/src/executor/paginator.rs +++ b/src/executor/paginator.rs @@ -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(()) } } diff --git a/src/query/mod.rs b/src/query/mod.rs index 7f32edc5..51060a1e 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -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};