Skip to content

Commit

Permalink
Unchanged ActiveValue as Set (SeaQL#1177)
Browse files Browse the repository at this point in the history
* Unchanged ActiveValue as Set

* Renaming

* Rename

* Rename methods
  • Loading branch information
billy1624 authored and denwong47 committed Jan 20, 2023
1 parent 01271c3 commit 163835c
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 0 deletions.
7 changes: 7 additions & 0 deletions sea-orm-macros/src/derives/active_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,13 @@ fn derive_active_model(all_fields: IntoIter<Field>) -> syn::Result<TokenStream>
#(#field: sea_orm::ActiveValue::not_set()),*
}
}

fn reset(&mut self, c: <Self::Entity as EntityTrait>::Column) {
match c {
#(<Self::Entity as EntityTrait>::Column::#name => self.#field.reset(),)*
_ => panic!("This ActiveModel does not have this field"),
}
}
}
))
}
Expand Down
150 changes: 150 additions & 0 deletions src/entity/active_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,19 @@ pub trait ActiveModelTrait: Clone + Debug {
/// The default implementation of the ActiveModel
fn default() -> Self;

/// Reset the value from [ActiveValue::Unchanged] to [ActiveValue::Set],
/// leaving [ActiveValue::NotSet] untouched.
fn reset(&mut self, c: <Self::Entity as EntityTrait>::Column);

/// Reset all values from [ActiveValue::Unchanged] to [ActiveValue::Set],
/// leaving [ActiveValue::NotSet] untouched.
fn reset_all(mut self) -> Self {
for col in <Self::Entity as EntityTrait>::Column::iter() {
self.reset(col);
}
self
}

/// Get the primary key of the ActiveModel
#[allow(clippy::question_mark)]
fn get_primary_key_value(&self) -> Option<ValueTuple> {
Expand Down Expand Up @@ -819,6 +832,15 @@ where
Self::NotSet => ActiveValue::not_set(),
}
}

/// Reset the value from [ActiveValue::Unchanged] to [ActiveValue::Set],
/// leaving [ActiveValue::NotSet] untouched.
pub fn reset(&mut self) {
*self = match self.take() {
Some(value) => ActiveValue::Set(value),
None => ActiveValue::NotSet,
};
}
}

impl<V> std::convert::AsRef<V> for ActiveValue<V>
Expand Down Expand Up @@ -1272,4 +1294,132 @@ mod tests {
fruit.set(fruit::Column::Name, "apple".into());
assert!(fruit.is_changed());
}

#[test]
fn test_reset_1() {
assert_eq!(
fruit::Model {
id: 1,
name: "Apple".into(),
cake_id: None,
}
.into_active_model(),
fruit::ActiveModel {
id: Unchanged(1),
name: Unchanged("Apple".into()),
cake_id: Unchanged(None)
},
);

assert_eq!(
fruit::Model {
id: 1,
name: "Apple".into(),
cake_id: None,
}
.into_active_model()
.reset_all(),
fruit::ActiveModel {
id: Set(1),
name: Set("Apple".into()),
cake_id: Set(None)
},
);

assert_eq!(
fruit::Model {
id: 1,
name: "Apple".into(),
cake_id: Some(2),
}
.into_active_model(),
fruit::ActiveModel {
id: Unchanged(1),
name: Unchanged("Apple".into()),
cake_id: Unchanged(Some(2)),
},
);

assert_eq!(
fruit::Model {
id: 1,
name: "Apple".into(),
cake_id: Some(2),
}
.into_active_model()
.reset_all(),
fruit::ActiveModel {
id: Set(1),
name: Set("Apple".into()),
cake_id: Set(Some(2)),
},
);
}

#[smol_potat::test]
async fn test_reset_2() -> Result<(), DbErr> {
use crate::*;

let db = MockDatabase::new(DbBackend::Postgres)
.append_exec_results(vec![
MockExecResult {
last_insert_id: 1,
rows_affected: 1,
},
MockExecResult {
last_insert_id: 1,
rows_affected: 1,
},
])
.append_query_results(vec![
vec![fruit::Model {
id: 1,
name: "Apple".to_owned(),
cake_id: None,
}],
vec![fruit::Model {
id: 1,
name: "Apple".to_owned(),
cake_id: None,
}],
])
.into_connection();

fruit::Model {
id: 1,
name: "Apple".into(),
cake_id: None,
}
.into_active_model()
.update(&db)
.await?;

fruit::Model {
id: 1,
name: "Apple".into(),
cake_id: None,
}
.into_active_model()
.reset_all()
.update(&db)
.await?;

assert_eq!(
db.into_transaction_log(),
vec![
Transaction::from_sql_and_values(
DbBackend::Postgres,
r#"UPDATE "fruit" SET WHERE "fruit"."id" = $1 RETURNING "id", "name", "cake_id""#,
vec![1i32.into()],
),
Transaction::from_sql_and_values(
DbBackend::Postgres,
r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
vec!["Apple".into(), Option::<i32>::None.into(), 1i32.into()],
),
]
);

Ok(())
}
}

0 comments on commit 163835c

Please sign in to comment.