diff --git a/README.md b/README.md index 6e785e9c..636fe594 100644 --- a/README.md +++ b/README.md @@ -136,12 +136,12 @@ Fruit::update_many() ### Save ```rust let banana = fruit::ActiveModel { - id: Unset(None), + id: NotSet, name: Set("Banana".to_owned()), ..Default::default() }; -// create, because primary key `id` is `Unset` +// create, because primary key `id` is `NotSet` let mut banana = banana.save(db).await?.into_active_model(); banana.name = Set("Banana Mongo".to_owned()); diff --git a/examples/basic/src/operation.rs b/examples/basic/src/operation.rs index 4b84da15..787cbc96 100644 --- a/examples/basic/src/operation.rs +++ b/examples/basic/src/operation.rs @@ -81,7 +81,7 @@ mod form { async fn save_custom_active_model(db: &DbConn) -> Result<(), DbErr> { let pineapple = form::ActiveModel { - id: Unset(None), + id: NotSet, name: Set("Pineapple".to_owned()), }; diff --git a/sea-orm-macros/src/derives/active_model.rs b/sea-orm-macros/src/derives/active_model.rs index d691a724..635897dc 100644 --- a/sea-orm-macros/src/derives/active_model.rs +++ b/sea-orm-macros/src/derives/active_model.rs @@ -80,7 +80,7 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result::Model> for ActiveModel { fn from(m: ::Model) -> Self { Self { - #(#field: sea_orm::unchanged_active_value_not_intended_for_public_use(m.#field)),* + #(#field: sea_orm::ActiveValue::unchanged(m.#field)),* } } } @@ -99,18 +99,18 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result::Column) -> sea_orm::ActiveValue { match c { #(::Column::#name => { - let mut value = sea_orm::ActiveValue::unset(); + let mut value = sea_orm::ActiveValue::not_set(); std::mem::swap(&mut value, &mut self.#field); value.into_wrapped_value() },)* - _ => sea_orm::ActiveValue::unset(), + _ => sea_orm::ActiveValue::not_set(), } } fn get(&self, c: ::Column) -> sea_orm::ActiveValue { match c { #(::Column::#name => self.#field.clone().into_wrapped_value(),)* - _ => sea_orm::ActiveValue::unset(), + _ => sea_orm::ActiveValue::not_set(), } } @@ -121,23 +121,23 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result::Column) { + fn not_set(&mut self, c: ::Column) { match c { - #(::Column::#name => self.#field = sea_orm::ActiveValue::unset(),)* + #(::Column::#name => self.#field = sea_orm::ActiveValue::not_set(),)* _ => {}, } } - fn is_unset(&self, c: ::Column) -> bool { + fn is_not_set(&self, c: ::Column) -> bool { match c { - #(::Column::#name => self.#field.is_unset(),)* + #(::Column::#name => self.#field.is_not_set(),)* _ => panic!("This ActiveModel does not have this field"), } } fn default() -> Self { Self { - #(#field: sea_orm::ActiveValue::unset()),* + #(#field: sea_orm::ActiveValue::not_set()),* } } } diff --git a/src/entity/active_model.rs b/src/entity/active_model.rs index ba02a914..d4f635c0 100644 --- a/src/entity/active_model.rs +++ b/src/entity/active_model.rs @@ -5,35 +5,47 @@ use async_trait::async_trait; use sea_query::{Nullable, ValueTuple}; use std::fmt::Debug; -/// Defines a value from an ActiveModel and its state. -/// The field `value` takes in an [Option] type where `Option::Some(V)` , with `V` holding -/// the value that operations like `UPDATE` are being performed on and -/// the `state` field is either `ActiveValueState::Set` or `ActiveValueState::Unchanged`. -/// [Option::None] in the `value` field indicates no value being performed by an operation -/// and that the `state` field of the [ActiveValue] is set to `ActiveValueState::Unset` . -/// #### Example snippet -/// ```no_run -/// // The code snipped below does an UPDATE operation on a [ActiveValue] -/// // yielding the the SQL statement ` r#"UPDATE "fruit" SET "name" = 'Orange' WHERE "fruit"."id" = 1"# ` +pub use ActiveValue::NotSet; + +/// Defines a stateful value used in ActiveModel. /// +/// There are three possible state represented by three enum variants. +/// - [ActiveValue::Set]: A [Value] was set +/// - [ActiveValue::Unchanged]: A [Value] remain unchanged +/// - [ActiveValue::NotSet]: A NULL value similar to [Option::None] +/// +/// The stateful value is useful when constructing UPDATE SQL statement, +/// see an example below. +/// +/// # Examples +/// +/// ``` /// use sea_orm::tests_cfg::{cake, fruit}; /// use sea_orm::{entity::*, query::*, DbBackend}; /// -/// Update::one(fruit::ActiveModel { -/// id: ActiveValue::set(1), -/// name: ActiveValue::set("Orange".to_owned()), -/// cake_id: ActiveValue::unset(), -/// }) -/// .build(DbBackend::Postgres) -/// .to_string(); +/// // The code snipped below does an UPDATE operation on a `ActiveValue` +/// assert_eq!( +/// Update::one(fruit::ActiveModel { +/// id: ActiveValue::set(1), +/// name: ActiveValue::set("Orange".to_owned()), +/// cake_id: ActiveValue::not_set(), +/// }) +/// .build(DbBackend::Postgres) +/// .to_string(), +/// r#"UPDATE "fruit" SET "name" = 'Orange' WHERE "fruit"."id" = 1"# +/// ); /// ``` -#[derive(Clone, Debug, Default)] -pub struct ActiveValue +#[derive(Clone, Debug)] +pub enum ActiveValue where V: Into, { - value: Option, - state: ActiveValueState, + /// A [Value] was set + Set(V), + /// A [Value] remain unchanged + Unchanged(V), + /// A NULL value similar to [Option::None] + NotSet, } /// Defines a set operation on an [ActiveValue] @@ -45,31 +57,22 @@ where ActiveValue::set(v) } -/// Defines an unset operation on an [ActiveValue] +/// Defines an not set operation on an [ActiveValue] +#[deprecated( + since = "0.5.0", + note = "Please use [`ActiveValue::NotSet`] or [`NotSet`]" +)] #[allow(non_snake_case)] pub fn Unset(_: Option) -> ActiveValue where V: Into, { - ActiveValue::unset() + ActiveValue::not_set() } -// Defines the state of an [ActiveValue] -#[derive(Clone, Debug)] -enum ActiveValueState { - Set, - Unchanged, - Unset, -} - -impl Default for ActiveValueState { - fn default() -> Self { - Self::Unset - } -} - -#[doc(hidden)] -pub fn unchanged_active_value_not_intended_for_public_use(value: V) -> ActiveValue +/// Defines an unchanged operation on an [ActiveValue] +#[allow(non_snake_case)] +pub fn Unchanged(value: V) -> ActiveValue where V: Into, { @@ -93,11 +96,11 @@ pub trait ActiveModelTrait: Clone + Debug { /// Set the Value into an ActiveModel fn set(&mut self, c: ::Column, v: Value); - /// Set the state of an [ActiveValue] to the Unset state - fn unset(&mut self, c: ::Column); + /// Set the state of an [ActiveValue] to the not set state + fn not_set(&mut self, c: ::Column); /// Check the state of a [ActiveValue] - fn is_unset(&self, c: ::Column) -> bool; + fn is_not_set(&self, c: ::Column) -> bool; /// The default implementation of the ActiveModel fn default() -> Self; @@ -378,7 +381,7 @@ pub trait ActiveModelTrait: Clone + Debug { Self::after_save(model, false) } - /// Insert the model if primary key is unset, update otherwise. + /// Insert the model if primary key is not_set, update otherwise. /// Only works if the entity has auto increment primary key. async fn save<'a, C>(self, db: &'a C) -> Result<::Model, DbErr> where @@ -390,7 +393,7 @@ pub trait ActiveModelTrait: Clone + Debug { let mut is_update = true; for key in ::PrimaryKey::iter() { let col = key.into_column(); - if am.is_unset(col) { + if am.is_not_set(col) { is_update = false; break; } @@ -555,7 +558,7 @@ macro_rules! impl_into_active_value { fn into_active_value(self) -> ActiveValue> { match self { Some(value) => Set(Some(value)), - None => Unset(None), + None => NotSet, } } } @@ -564,7 +567,7 @@ macro_rules! impl_into_active_value { fn into_active_value(self) -> ActiveValue> { match self { Some(value) => Set(value), - None => Unset(None), + None => NotSet, } } } @@ -613,74 +616,80 @@ impl_into_active_value!(crate::prelude::Decimal, Set); #[cfg_attr(docsrs, doc(cfg(feature = "with-uuid")))] impl_into_active_value!(crate::prelude::Uuid, Set); +impl Default for ActiveValue +where + V: Into, +{ + fn default() -> Self { + Self::NotSet + } +} + impl ActiveValue where V: Into, { - /// Set the value of an [ActiveValue] and also set its state to `ActiveValueState::Set` + /// Create an [ActiveValue::Set] pub fn set(value: V) -> Self { - Self { - value: Some(value), - state: ActiveValueState::Set, - } + Self::Set(value) } - /// Check if the state of an [ActiveValue] is `ActiveValueState::Set` which returns true + /// Check if the [ActiveValue] is [ActiveValue::Set] pub fn is_set(&self) -> bool { - matches!(self.state, ActiveValueState::Set) + matches!(self, Self::Set(_)) } - pub(crate) fn unchanged(value: V) -> Self { - Self { - value: Some(value), - state: ActiveValueState::Unchanged, - } + /// Create an [ActiveValue::Unchanged] + pub fn unchanged(value: V) -> Self { + Self::Unchanged(value) } - /// Check if the status of the [ActiveValue] is `ActiveValueState::Unchanged` - /// which returns `true` if it is + /// Check if the [ActiveValue] is [ActiveValue::Unchanged] pub fn is_unchanged(&self) -> bool { - matches!(self.state, ActiveValueState::Unchanged) + matches!(self, Self::Unchanged(_)) } - /// Set the `value` field of the ActiveModel to [Option::None] and the - /// `state` field to `ActiveValueState::Unset` - pub fn unset() -> Self { - Self { - value: None, - state: ActiveValueState::Unset, + /// Create an [ActiveValue::NotSet] + pub fn not_set() -> Self { + Self::default() + } + + /// Check if the [ActiveValue] is [ActiveValue::NotSet] + pub fn is_not_set(&self) -> bool { + matches!(self, Self::NotSet) + } + + /// Get the mutable value an [ActiveValue] + /// also setting itself to [ActiveValue::NotSet] + pub fn take(&mut self) -> Option { + match std::mem::take(self) { + ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value), + ActiveValue::NotSet => None, } } - /// Check if the state of an [ActiveValue] is `ActiveValueState::Unset` - /// which returns true if it is - pub fn is_unset(&self) -> bool { - matches!(self.state, ActiveValueState::Unset) - } - - /// Get the mutable value of the `value` field of an [ActiveValue] - /// also setting it's state to `ActiveValueState::Unset` - pub fn take(&mut self) -> Option { - self.state = ActiveValueState::Unset; - self.value.take() - } - - /// Get an owned value of the `value` field of the [ActiveValue] + /// Get an owned value of the [ActiveValue] pub fn unwrap(self) -> V { - self.value.unwrap() + match self { + ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value, + ActiveValue::NotSet => panic!("Cannot unwrap ActiveValue::NotSet"), + } } /// Check is a [Value] exists or not pub fn into_value(self) -> Option { - self.value.map(Into::into) + match self { + ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value.into()), + ActiveValue::NotSet => None, + } } /// Wrap the [Value] into a `ActiveValue` pub fn into_wrapped_value(self) -> ActiveValue { - match self.state { - ActiveValueState::Set => ActiveValue::set(self.into_value().unwrap()), - ActiveValueState::Unchanged => ActiveValue::unchanged(self.into_value().unwrap()), - ActiveValueState::Unset => ActiveValue::unset(), + match self { + Self::Set(value) => ActiveValue::set(value.into()), + Self::Unchanged(value) => ActiveValue::unchanged(value.into()), + Self::NotSet => ActiveValue::not_set(), } } } @@ -690,7 +699,10 @@ where V: Into, { fn as_ref(&self) -> &V { - self.value.as_ref().unwrap() + match self { + ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value, + ActiveValue::NotSet => panic!("Cannot borrow ActiveValue::NotSet"), + } } } @@ -699,7 +711,12 @@ where V: Into + std::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { - self.value.as_ref() == other.value.as_ref() + match (self, other) { + (ActiveValue::Set(l), ActiveValue::Set(r)) => l == r, + (ActiveValue::Unchanged(l), ActiveValue::Unchanged(r)) => l == r, + (ActiveValue::NotSet, ActiveValue::NotSet) => true, + _ => false, + } } } @@ -708,10 +725,10 @@ where V: Into + Nullable, { fn from(value: ActiveValue) -> Self { - match value.state { - ActiveValueState::Set => Set(value.value), - ActiveValueState::Unset => Unset(None), - ActiveValueState::Unchanged => ActiveValue::unchanged(value.value), + match value { + ActiveValue::Set(value) => ActiveValue::set(Some(value)), + ActiveValue::Unchanged(value) => ActiveValue::unchanged(Some(value)), + ActiveValue::NotSet => ActiveValue::not_set(), } } } @@ -746,7 +763,7 @@ mod tests { } .into_active_model(), fruit::ActiveModel { - id: Unset(None), + id: NotSet, name: Set("Apple".to_owned()), cake_id: Set(Some(1)), } @@ -775,8 +792,8 @@ mod tests { } .into_active_model(), fruit::ActiveModel { - id: Unset(None), - name: Unset(None), + id: NotSet, + name: NotSet, cake_id: Set(Some(1)), } ); @@ -787,8 +804,8 @@ mod tests { } .into_active_model(), fruit::ActiveModel { - id: Unset(None), - name: Unset(None), + id: NotSet, + name: NotSet, cake_id: Set(None), } ); @@ -796,9 +813,9 @@ mod tests { assert_eq!( my_fruit::UpdateFruit { cake_id: None }.into_active_model(), fruit::ActiveModel { - id: Unset(None), - name: Unset(None), - cake_id: Unset(None), + id: NotSet, + name: NotSet, + cake_id: NotSet, } ); } diff --git a/src/lib.rs b/src/lib.rs index f5387aeb..81cf98a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -201,12 +201,12 @@ //! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*}; //! # async fn function(db: &DbConn) -> Result<(), DbErr> { //! let banana = fruit::ActiveModel { -//! id: Unset(None), +//! id: NotSet, //! name: Set("Banana".to_owned()), //! ..Default::default() //! }; //! -//! // create, because primary key `id` is `Unset` +//! // create, because primary key `id` is `NotSet` //! let mut banana = banana.save(db).await?.into_active_model(); //! //! banana.name = Set("Banana Mongo".to_owned()); diff --git a/src/query/insert.rs b/src/query/insert.rs index 7cafc44c..563d6474 100644 --- a/src/query/insert.rs +++ b/src/query/insert.rs @@ -63,7 +63,7 @@ where /// /// assert_eq!( /// Insert::one(cake::ActiveModel { - /// id: Unset(None), + /// id: NotSet, /// name: Set("Apple Pie".to_owned()), /// }) /// .build(DbBackend::Postgres) @@ -190,7 +190,7 @@ mod tests { assert_eq!( Insert::::new() .add(cake::ActiveModel { - id: ActiveValue::unset(), + id: ActiveValue::not_set(), name: ActiveValue::set("Apple Pie".to_owned()), }) .build(DbBackend::Postgres) diff --git a/src/query/update.rs b/src/query/update.rs index f12d3b95..a48d19a5 100644 --- a/src/query/update.rs +++ b/src/query/update.rs @@ -236,7 +236,7 @@ mod tests { Update::one(fruit::ActiveModel { id: ActiveValue::set(1), name: ActiveValue::set("Orange".to_owned()), - cake_id: ActiveValue::unset(), + cake_id: ActiveValue::not_set(), }) .build(DbBackend::Postgres) .to_string(), diff --git a/tests/basic.rs b/tests/basic.rs index 96eed084..51f300da 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -53,8 +53,8 @@ async fn crud_cake(db: &DbConn) -> Result<(), DbErr> { assert_eq!( apple, cake::ActiveModel { - id: Set(1), - name: Set("Apple Pie".to_owned()), + id: Unchanged(1), + name: Unchanged("Apple Pie".to_owned()), } );