diff --git a/src/entity/active_model.rs b/src/entity/active_model.rs index cfcb0bbdf..7cdd9071c 100644 --- a/src/entity/active_model.rs +++ b/src/entity/active_model.rs @@ -69,11 +69,11 @@ pub trait ActiveModelTrait: Clone + Debug { async fn insert(self, db: &DatabaseConnection) -> Result where + Self: ActiveModelBehavior, ::Model: IntoActiveModel, { - let am = self; - let exec = ::insert(am).exec(db); - let res = exec.await?; + let am = ActiveModelBehavior::before_save(self, true, db)?; + let res = ::insert(am).exec(db).await?; // Assume valid last_insert_id is not equals to Default::default() if res.last_insert_id != <::PrimaryKey as PrimaryKeyTrait>::ValueType::default() @@ -81,18 +81,23 @@ pub trait ActiveModelTrait: Clone + Debug { let found = ::find_by_id(res.last_insert_id) .one(db) .await?; - match found { + let am = match found { Some(model) => Ok(model.into_active_model()), None => Err(DbErr::Exec("Failed to find inserted item".to_owned())), - } + }?; + ActiveModelBehavior::after_save(am, true, db) } else { Ok(Self::default()) } } - async fn update(self, db: &DatabaseConnection) -> Result { - let exec = Self::Entity::update(self).exec(db); - exec.await + async fn update(self, db: &DatabaseConnection) -> Result + where + Self: ActiveModelBehavior, + { + let am = ActiveModelBehavior::before_save(self, false, db)?; + let am = Self::Entity::update(am).exec(db).await?; + ActiveModelBehavior::after_save(am, false, db) } /// Insert the model if primary key is unset, update otherwise. @@ -103,7 +108,6 @@ pub trait ActiveModelTrait: Clone + Debug { ::Model: IntoActiveModel, { let mut am = self; - am = ActiveModelBehavior::before_save(am); let mut is_update = true; for key in ::PrimaryKey::iter() { let col = key.into_column(); @@ -117,7 +121,6 @@ pub trait ActiveModelTrait: Clone + Debug { } else { am = am.update(db).await?; } - am = ActiveModelBehavior::after_save(am); Ok(am) } @@ -126,14 +129,16 @@ pub trait ActiveModelTrait: Clone + Debug { where Self: ActiveModelBehavior, { - let mut am = self; - am = ActiveModelBehavior::before_delete(am); - let exec = Self::Entity::delete(am).exec(db); - exec.await + let am = ActiveModelBehavior::before_delete(self, db)?; + let am_clone = am.clone(); + let delete_res = Self::Entity::delete(am).exec(db).await?; + ActiveModelBehavior::after_delete(am_clone, db)?; + Ok(delete_res) } } /// Behaviors for users to override +#[allow(unused_variables)] pub trait ActiveModelBehavior: ActiveModelTrait { /// Create a new ActiveModel with default values. Also used by `Default::default()`. fn new() -> Self { @@ -141,18 +146,23 @@ pub trait ActiveModelBehavior: ActiveModelTrait { } /// Will be called before saving - fn before_save(self) -> Self { - self + fn before_save(self, insert: bool, db: &DatabaseConnection) -> Result { + Ok(self) } /// Will be called after saving - fn after_save(self) -> Self { - self + fn after_save(self, insert: bool, db: &DatabaseConnection) -> Result { + Ok(self) } /// Will be called before deleting - fn before_delete(self) -> Self { - self + fn before_delete(self, db: &DatabaseConnection) -> Result { + Ok(self) + } + + /// Will be called after deleting + fn after_delete(self, db: &DatabaseConnection) -> Result { + Ok(self) } } diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index 8d87a4b20..72143c9cd 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -1,9 +1,10 @@ pub use crate::{ error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType, - DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity, - DeriveEntityModel, DeriveModel, DerivePrimaryKey, DeriveRelation, EntityName, EntityTrait, - EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, ModelTrait, PrimaryKeyToColumn, - PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, RelationTrait, Select, Value, + DatabaseConnection, DbConn, DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, + DeriveCustomColumn, DeriveEntity, DeriveEntityModel, DeriveModel, DerivePrimaryKey, + DeriveRelation, EntityName, EntityTrait, EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, + ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult, Related, + RelationDef, RelationTrait, Select, Value, }; #[cfg(feature = "with-json")] diff --git a/src/executor/insert.rs b/src/executor/insert.rs index d580f110e..a44867f78 100644 --- a/src/executor/insert.rs +++ b/src/executor/insert.rs @@ -1,6 +1,6 @@ use crate::{ - error::*, ActiveModelTrait, DatabaseConnection, DbBackend, EntityTrait, Insert, PrimaryKeyTrait, - Statement, TryFromU64, + error::*, ActiveModelTrait, DatabaseConnection, DbBackend, EntityTrait, Insert, + PrimaryKeyTrait, Statement, TryFromU64, }; use sea_query::InsertStatement; use std::{future::Future, marker::PhantomData}; diff --git a/tests/common/bakery_chain/applog.rs b/tests/common/bakery_chain/applog.rs index 03b06d61a..1f83ca8f9 100644 --- a/tests/common/bakery_chain/applog.rs +++ b/tests/common/bakery_chain/applog.rs @@ -5,6 +5,7 @@ use sea_orm::entity::prelude::*; pub struct Model { #[sea_orm(primary_key)] pub id: i32, + pub action: String, pub json: Json, pub created_at: DateTimeWithTimeZone, } diff --git a/tests/common/setup/schema.rs b/tests/common/setup/schema.rs index 64f31dfe7..550a371bf 100644 --- a/tests/common/setup/schema.rs +++ b/tests/common/setup/schema.rs @@ -301,6 +301,7 @@ pub async fn create_log_table(db: &DbConn) -> Result { .auto_increment() .primary_key(), ) + .col(ColumnDef::new(applog::Column::Action).string().not_null()) .col(ColumnDef::new(applog::Column::Json).json().not_null()) .col( ColumnDef::new(applog::Column::CreatedAt) diff --git a/tests/timestamp_tests.rs b/tests/timestamp_tests.rs index 1897323cb..beca5593f 100644 --- a/tests/timestamp_tests.rs +++ b/tests/timestamp_tests.rs @@ -16,6 +16,7 @@ async fn main() -> Result<(), DbErr> { pub async fn create_applog(db: &DatabaseConnection) -> Result<(), DbErr> { let log = applog::Model { id: 1, + action: "Testing".to_owned(), json: Json::String("HI".to_owned()), created_at: "2021-09-17T17:50:20+08:00".parse().unwrap(), };