diff --git a/tests/common/bakery_chain/cake.rs b/tests/common/bakery_chain/cake.rs index 4730394b..cdae08af 100644 --- a/tests/common/bakery_chain/cake.rs +++ b/tests/common/bakery_chain/cake.rs @@ -49,4 +49,76 @@ impl Related for Entity { } } -impl ActiveModelBehavior for ActiveModel {} +impl ActiveModelBehavior for ActiveModel { + fn new() -> Self { + use sea_orm::Set; + Self { + serial: Set(Uuid::new_v4()), + ..ActiveModelTrait::default() + } + } + + fn before_save(self, insert: bool) -> Result { + use rust_decimal_macros::dec; + if let Some(price) = self.price.clone().take() { + if price == dec!(0) { + Err(DbErr::Custom(format!( + "[before_save] Invalid Price, insert: {}", + insert + ))) + } else { + Ok(self) + } + } else { + Err(DbErr::Custom(format!( + "[before_save] Price must be set, insert: {}", + insert + ))) + } + } + + fn after_save(self, insert: bool) -> Result { + use rust_decimal_macros::dec; + if let Some(price) = dbg!(self.price.clone()).take() { + if price < dec!(0) { + Err(DbErr::Custom(format!( + "[after_save] Invalid Price, insert: {}", + insert + ))) + } else { + Ok(self) + } + } else { + Err(DbErr::Custom(format!( + "[after_save] Price must be set, insert: {}", + insert + ))) + } + } + + fn before_delete(self) -> Result { + if let Some(name) = self.name.clone().take() { + if name.contains("(err_on_before_delete)") { + Err(DbErr::Custom( + "[before_delete] Cannot be deleted".to_owned(), + )) + } else { + Ok(self) + } + } else { + Err(DbErr::Custom("[before_delete] Name must be set".to_owned())) + } + } + + fn after_delete(self) -> Result { + if let Some(name) = self.name.clone().take() { + if name.contains("(err_on_after_delete)") { + Err(DbErr::Custom("[after_delete] Cannot be deleted".to_owned())) + } else { + Ok(self) + } + } else { + Err(DbErr::Custom("[after_delete] Name must be set".to_owned())) + } + } +} diff --git a/tests/transaction_tests.rs b/tests/transaction_tests.rs index 6a713e4d..72e20368 100644 --- a/tests/transaction_tests.rs +++ b/tests/transaction_tests.rs @@ -1,9 +1,9 @@ pub mod common; pub use common::{bakery_chain::*, setup::*, TestContext}; +use pretty_assertions::assert_eq; pub use sea_orm::entity::*; -pub use sea_orm::{ConnectionTrait, QueryFilter}; -use sea_orm::{DatabaseTransaction, DbErr}; +pub use sea_orm::*; #[sea_orm_macros::test] #[cfg(any( @@ -105,6 +105,101 @@ fn _transaction_with_reference<'a>( }) } +#[sea_orm_macros::test] +#[cfg(any( + feature = "sqlx-mysql", + feature = "sqlx-sqlite", + feature = "sqlx-postgres" +))] + +#[sea_orm_macros::test] +#[cfg(any( + feature = "sqlx-mysql", + feature = "sqlx-sqlite", + feature = "sqlx-postgres" +))] +pub async fn transaction_with_active_model_behaviour() -> Result<(), DbErr> { + use rust_decimal_macros::dec; + let ctx = TestContext::new("transaction_with_active_model_behaviour_test").await; + + if let Ok(txn) = ctx.db.begin().await { + assert_eq!( + cake::ActiveModel { + name: Set("Cake with invalid price".to_owned()), + price: Set(dec!(0)), + gluten_free: Set(false), + ..Default::default() + } + .save(&txn) + .await, + Err(DbErr::Custom( + "[before_save] Invalid Price, insert: true".to_owned() + )) + ); + + assert_eq!(cake::Entity::find().all(&txn).await?.len(), 0); + + assert_eq!( + cake::ActiveModel { + name: Set("Cake with invalid price".to_owned()), + price: Set(dec!(-10)), + gluten_free: Set(false), + ..Default::default() + } + .save(&txn) + .await, + Err(DbErr::Custom( + "[after_save] Invalid Price, insert: true".to_owned() + )) + ); + + assert_eq!(cake::Entity::find().all(&txn).await?.len(), 1); + + let readonly_cake_1 = cake::ActiveModel { + name: Set("Readonly cake (err_on_before_delete)".to_owned()), + price: Set(dec!(10)), + gluten_free: Set(true), + ..Default::default() + } + .save(&txn) + .await?; + + assert_eq!(cake::Entity::find().all(&txn).await?.len(), 2); + + assert_eq!( + readonly_cake_1.delete(&txn).await.err(), + Some(DbErr::Custom( + "[before_delete] Cannot be deleted".to_owned() + )) + ); + + assert_eq!(cake::Entity::find().all(&txn).await?.len(), 2); + + let readonly_cake_2 = cake::ActiveModel { + name: Set("Readonly cake (err_on_after_delete)".to_owned()), + price: Set(dec!(10)), + gluten_free: Set(true), + ..Default::default() + } + .save(&txn) + .await?; + + assert_eq!(cake::Entity::find().all(&txn).await?.len(), 3); + + assert_eq!( + readonly_cake_2.delete(&txn).await.err(), + Some(DbErr::Custom("[after_delete] Cannot be deleted".to_owned())) + ); + + assert_eq!(cake::Entity::find().all(&txn).await?.len(), 2); + } + + assert_eq!(cake::Entity::find().all(&ctx.db).await?.len(), 0); + + ctx.delete().await; + Ok(()) +} + #[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql",