sea_orm/entity/
active_model.rs

1use crate::{
2    error::*, ConnectionTrait, DeleteResult, EntityTrait, Iterable, PrimaryKeyArity,
3    PrimaryKeyToColumn, PrimaryKeyTrait, Value,
4};
5use async_trait::async_trait;
6use sea_query::{Nullable, ValueTuple};
7use std::fmt::Debug;
8
9pub use ActiveValue::{NotSet, Set, Unchanged};
10
11/// Defines a stateful value used in ActiveModel.
12///
13/// There are three possible state represented by three enum variants.
14/// - [ActiveValue::Set]: A defined [Value] actively being set
15/// - [ActiveValue::Unchanged]: A defined [Value] remain unchanged
16/// - [ActiveValue::NotSet]: An undefined [Value]
17///
18/// The stateful value is useful when constructing UPDATE SQL statement,
19/// see an example below.
20///
21/// # Examples
22///
23/// ```
24/// use sea_orm::tests_cfg::{cake, fruit};
25/// use sea_orm::{entity::*, query::*, DbBackend};
26///
27/// // The code snipped below does an UPDATE operation on a `ActiveValue`
28/// assert_eq!(
29///     Update::one(fruit::ActiveModel {
30///         id: ActiveValue::set(1),
31///         name: ActiveValue::set("Orange".to_owned()),
32///         cake_id: ActiveValue::not_set(),
33///     })
34///     .build(DbBackend::Postgres)
35///     .to_string(),
36///     r#"UPDATE "fruit" SET "name" = 'Orange' WHERE "fruit"."id" = 1"#
37/// );
38/// ```
39#[derive(Clone, Debug)]
40pub enum ActiveValue<V>
41where
42    V: Into<Value>,
43{
44    /// A defined [Value] actively being set
45    Set(V),
46    /// A defined [Value] remain unchanged
47    Unchanged(V),
48    /// An undefined [Value]
49    NotSet,
50}
51
52/// Defines an not set operation on an [ActiveValue]
53#[deprecated(
54    since = "0.5.0",
55    note = "Please use [`ActiveValue::NotSet`] or [`NotSet`]"
56)]
57#[allow(non_snake_case)]
58pub fn Unset<V>(_: Option<bool>) -> ActiveValue<V>
59where
60    V: Into<Value>,
61{
62    ActiveValue::not_set()
63}
64
65/// A Trait for ActiveModel to perform Create, Update or Delete operation.
66/// The type must also implement the [EntityTrait].
67/// See module level docs [crate::entity] for a full example
68#[async_trait]
69pub trait ActiveModelTrait: Clone + Debug {
70    /// The Entity this ActiveModel belongs to
71    type Entity: EntityTrait;
72
73    /// Get a mutable [ActiveValue] from an ActiveModel
74    fn take(&mut self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
75
76    /// Get a immutable [ActiveValue] from an ActiveModel
77    fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
78
79    /// Set the Value into an ActiveModel
80    fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
81
82    /// Set the state of an [ActiveValue] to the not set state
83    fn not_set(&mut self, c: <Self::Entity as EntityTrait>::Column);
84
85    /// Check the state of a [ActiveValue]
86    fn is_not_set(&self, c: <Self::Entity as EntityTrait>::Column) -> bool;
87
88    /// The default implementation of the ActiveModel
89    fn default() -> Self;
90
91    /// Reset the value from [ActiveValue::Unchanged] to [ActiveValue::Set],
92    /// leaving [ActiveValue::NotSet] untouched.
93    fn reset(&mut self, c: <Self::Entity as EntityTrait>::Column);
94
95    /// Reset all values from [ActiveValue::Unchanged] to [ActiveValue::Set],
96    /// leaving [ActiveValue::NotSet] untouched.
97    fn reset_all(mut self) -> Self {
98        for col in <Self::Entity as EntityTrait>::Column::iter() {
99            self.reset(col);
100        }
101        self
102    }
103
104    /// Get the primary key of the ActiveModel
105    ///
106    /// # Panics
107    ///
108    /// Panics if arity of primary key exceed maximum arity of [ValueTuple]
109    #[allow(clippy::question_mark)]
110    fn get_primary_key_value(&self) -> Option<ValueTuple> {
111        let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
112        macro_rules! next {
113            () => {
114                if let Some(col) = cols.next() {
115                    if let Some(val) = self.get(col.into_column()).into_value() {
116                        val
117                    } else {
118                        return None;
119                    }
120                } else {
121                    return None;
122                }
123            };
124        }
125        match <<<Self::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType as PrimaryKeyArity>::ARITY {
126            1 => {
127                let s1 = next!();
128                Some(ValueTuple::One(s1))
129            }
130            2 => {
131                let s1 = next!();
132                let s2 = next!();
133                Some(ValueTuple::Two(s1, s2))
134            }
135            3 => {
136                let s1 = next!();
137                let s2 = next!();
138                let s3 = next!();
139                Some(ValueTuple::Three(s1, s2, s3))
140            }
141            len => {
142                let mut vec = Vec::with_capacity(len);
143                for _ in 0..len {
144                    let s = next!();
145                    vec.push(s);
146                }
147                Some(ValueTuple::Many(vec))
148            }
149        }
150    }
151
152    /// Perform an `INSERT` operation on the ActiveModel
153    ///
154    /// # Example (Postgres)
155    ///
156    /// ```
157    /// # use sea_orm::{error::*, tests_cfg::*, *};
158    /// #
159    /// # #[smol_potat::main]
160    /// # #[cfg(feature = "mock")]
161    /// # pub async fn main() -> Result<(), DbErr> {
162    /// #
163    /// # let db = MockDatabase::new(DbBackend::Postgres)
164    /// #     .append_query_results([
165    /// #         [cake::Model {
166    /// #             id: 15,
167    /// #             name: "Apple Pie".to_owned(),
168    /// #         }],
169    /// #     ])
170    /// #     .into_connection();
171    /// #
172    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
173    ///
174    /// let apple = cake::ActiveModel {
175    ///     name: Set("Apple Pie".to_owned()),
176    ///     ..Default::default()
177    /// };
178    ///
179    /// assert_eq!(
180    ///     apple.insert(&db).await?,
181    ///     cake::Model {
182    ///         id: 15,
183    ///         name: "Apple Pie".to_owned(),
184    ///     }
185    /// );
186    ///
187    /// assert_eq!(
188    ///     db.into_transaction_log(),
189    ///     [Transaction::from_sql_and_values(
190    ///         DbBackend::Postgres,
191    ///         r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id", "name""#,
192    ///         ["Apple Pie".into()]
193    ///     )]
194    /// );
195    /// #
196    /// # Ok(())
197    /// # }
198    /// ```
199    ///
200    /// # Example (MySQL)
201    ///
202    /// ```
203    /// # use sea_orm::{error::*, tests_cfg::*, *};
204    /// #
205    /// # #[smol_potat::main]
206    /// # #[cfg(feature = "mock")]
207    /// # pub async fn main() -> Result<(), DbErr> {
208    /// #
209    /// # let db = MockDatabase::new(DbBackend::MySql)
210    /// #     .append_query_results([
211    /// #         [cake::Model {
212    /// #             id: 15,
213    /// #             name: "Apple Pie".to_owned(),
214    /// #         }],
215    /// #     ])
216    /// #     .append_exec_results([
217    /// #         MockExecResult {
218    /// #             last_insert_id: 15,
219    /// #             rows_affected: 1,
220    /// #         },
221    /// #     ])
222    /// #     .into_connection();
223    /// #
224    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
225    ///
226    /// let apple = cake::ActiveModel {
227    ///     name: Set("Apple Pie".to_owned()),
228    ///     ..Default::default()
229    /// };
230    ///
231    /// assert_eq!(
232    ///     apple.insert(&db).await?,
233    ///     cake::Model {
234    ///         id: 15,
235    ///         name: "Apple Pie".to_owned(),
236    ///     }
237    /// );
238    ///
239    /// assert_eq!(
240    ///     db.into_transaction_log(),
241    ///     [
242    ///         Transaction::from_sql_and_values(
243    ///             DbBackend::MySql,
244    ///             r#"INSERT INTO `cake` (`name`) VALUES (?)"#,
245    ///             ["Apple Pie".into()]
246    ///         ),
247    ///         Transaction::from_sql_and_values(
248    ///             DbBackend::MySql,
249    ///             r#"SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = ? LIMIT ?"#,
250    ///             [15.into(), 1u64.into()]
251    ///         )
252    ///     ]
253    /// );
254    /// #
255    /// # Ok(())
256    /// # }
257    /// ```
258    async fn insert<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
259    where
260        <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
261        Self: ActiveModelBehavior + 'a,
262        C: ConnectionTrait,
263    {
264        let am = ActiveModelBehavior::before_save(self, db, true).await?;
265        let model = <Self::Entity as EntityTrait>::insert(am)
266            .exec_with_returning(db)
267            .await?;
268        Self::after_save(model, db, true).await
269    }
270
271    /// Perform the `UPDATE` operation on an ActiveModel
272    ///
273    /// # Example (Postgres)
274    ///
275    /// ```
276    /// # use sea_orm::{error::*, tests_cfg::*, *};
277    /// #
278    /// # #[smol_potat::main]
279    /// # #[cfg(feature = "mock")]
280    /// # pub async fn main() -> Result<(), DbErr> {
281    /// #
282    /// # let db = MockDatabase::new(DbBackend::Postgres)
283    /// #     .append_query_results([
284    /// #         [fruit::Model {
285    /// #             id: 1,
286    /// #             name: "Orange".to_owned(),
287    /// #             cake_id: None,
288    /// #         }],
289    /// #     ])
290    /// #     .into_connection();
291    /// #
292    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
293    ///
294    /// let orange = fruit::ActiveModel {
295    ///     id: Set(1),
296    ///     name: Set("Orange".to_owned()),
297    ///     ..Default::default()
298    /// };
299    ///
300    /// assert_eq!(
301    ///     orange.update(&db).await?,
302    ///     fruit::Model {
303    ///         id: 1,
304    ///         name: "Orange".to_owned(),
305    ///         cake_id: None,
306    ///     }
307    /// );
308    ///
309    /// assert_eq!(
310    ///     db.into_transaction_log(),
311    ///     [Transaction::from_sql_and_values(
312    ///         DbBackend::Postgres,
313    ///         r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2 RETURNING "id", "name", "cake_id""#,
314    ///         ["Orange".into(), 1i32.into()]
315    ///     )]);
316    /// #
317    /// # Ok(())
318    /// # }
319    /// ```
320    ///
321    /// # Example (MySQL)
322    ///
323    /// ```
324    /// # use sea_orm::{error::*, tests_cfg::*, *};
325    /// #
326    /// # #[smol_potat::main]
327    /// # #[cfg(feature = "mock")]
328    /// # pub async fn main() -> Result<(), DbErr> {
329    /// #
330    /// # let db = MockDatabase::new(DbBackend::MySql)
331    /// #     .append_query_results([
332    /// #         [fruit::Model {
333    /// #             id: 1,
334    /// #             name: "Orange".to_owned(),
335    /// #             cake_id: None,
336    /// #         }],
337    /// #     ])
338    /// #     .append_exec_results([
339    /// #         MockExecResult {
340    /// #             last_insert_id: 0,
341    /// #             rows_affected: 1,
342    /// #         },
343    /// #     ])
344    /// #     .into_connection();
345    /// #
346    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
347    ///
348    /// let orange = fruit::ActiveModel {
349    ///     id: Set(1),
350    ///     name: Set("Orange".to_owned()),
351    ///     ..Default::default()
352    /// };
353    ///
354    /// assert_eq!(
355    ///     orange.update(&db).await?,
356    ///     fruit::Model {
357    ///         id: 1,
358    ///         name: "Orange".to_owned(),
359    ///         cake_id: None,
360    ///     }
361    /// );
362    ///
363    /// assert_eq!(
364    ///     db.into_transaction_log(),
365    ///     [
366    ///         Transaction::from_sql_and_values(
367    ///             DbBackend::MySql,
368    ///             r#"UPDATE `fruit` SET `name` = ? WHERE `fruit`.`id` = ?"#,
369    ///             ["Orange".into(), 1i32.into()]
370    ///         ),
371    ///         Transaction::from_sql_and_values(
372    ///             DbBackend::MySql,
373    ///             r#"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`id` = ? LIMIT ?"#,
374    ///             [1i32.into(), 1u64.into()]
375    ///         )]);
376    /// #
377    /// # Ok(())
378    /// # }
379    /// ```
380    async fn update<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
381    where
382        <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
383        Self: ActiveModelBehavior + 'a,
384        C: ConnectionTrait,
385    {
386        let am = ActiveModelBehavior::before_save(self, db, false).await?;
387        let model: <Self::Entity as EntityTrait>::Model = Self::Entity::update(am).exec(db).await?;
388        Self::after_save(model, db, false).await
389    }
390
391    /// Insert the model if primary key is `NotSet`, update otherwise.
392    /// Only works if the entity has auto increment primary key.
393    async fn save<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
394    where
395        <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
396        Self: ActiveModelBehavior + 'a,
397        C: ConnectionTrait,
398    {
399        let mut is_update = true;
400        for key in <Self::Entity as EntityTrait>::PrimaryKey::iter() {
401            let col = key.into_column();
402            if self.is_not_set(col) {
403                is_update = false;
404                break;
405            }
406        }
407        let res = if !is_update {
408            self.insert(db).await
409        } else {
410            self.update(db).await
411        }?;
412        Ok(res.into_active_model())
413    }
414
415    /// Delete an active model by its primary key
416    ///
417    /// # Example
418    ///
419    /// ```
420    /// # use sea_orm::{error::*, tests_cfg::*, *};
421    /// #
422    /// # #[smol_potat::main]
423    /// # #[cfg(feature = "mock")]
424    /// # pub async fn main() -> Result<(), DbErr> {
425    /// #
426    /// # let db = MockDatabase::new(DbBackend::Postgres)
427    /// #     .append_exec_results([
428    /// #         MockExecResult {
429    /// #             last_insert_id: 0,
430    /// #             rows_affected: 1,
431    /// #         },
432    /// #     ])
433    /// #     .into_connection();
434    /// #
435    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
436    ///
437    /// let orange = fruit::ActiveModel {
438    ///     id: Set(3),
439    ///     ..Default::default()
440    /// };
441    ///
442    /// let delete_result = orange.delete(&db).await?;
443    ///
444    /// assert_eq!(delete_result.rows_affected, 1);
445    ///
446    /// assert_eq!(
447    ///     db.into_transaction_log(),
448    ///     [Transaction::from_sql_and_values(
449    ///         DbBackend::Postgres,
450    ///         r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
451    ///         [3i32.into()]
452    ///     )]
453    /// );
454    /// #
455    /// # Ok(())
456    /// # }
457    /// ```
458    async fn delete<'a, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
459    where
460        Self: ActiveModelBehavior + 'a,
461        C: ConnectionTrait,
462    {
463        let am = ActiveModelBehavior::before_delete(self, db).await?;
464        let am_clone = am.clone();
465        let delete_res = Self::Entity::delete(am).exec(db).await?;
466        ActiveModelBehavior::after_delete(am_clone, db).await?;
467        Ok(delete_res)
468    }
469
470    /// Set the corresponding attributes in the ActiveModel from a JSON value
471    ///
472    /// Note that this method will not alter the primary key values in ActiveModel.
473    #[cfg(feature = "with-json")]
474    fn set_from_json(&mut self, json: serde_json::Value) -> Result<(), DbErr>
475    where
476        <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
477        for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
478            serde::de::Deserialize<'de>,
479    {
480        use crate::Iterable;
481
482        // Backup primary key values
483        let primary_key_values: Vec<(<Self::Entity as EntityTrait>::Column, ActiveValue<Value>)> =
484            <<Self::Entity as EntityTrait>::PrimaryKey>::iter()
485                .map(|pk| (pk.into_column(), self.take(pk.into_column())))
486                .collect();
487
488        // Replace all values in ActiveModel
489        *self = Self::from_json(json)?;
490
491        // Restore primary key values
492        for (col, active_value) in primary_key_values {
493            match active_value {
494                ActiveValue::Unchanged(v) | ActiveValue::Set(v) => self.set(col, v),
495                NotSet => self.not_set(col),
496            }
497        }
498
499        Ok(())
500    }
501
502    /// Create ActiveModel from a JSON value
503    #[cfg(feature = "with-json")]
504    fn from_json(json: serde_json::Value) -> Result<Self, DbErr>
505    where
506        <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
507        for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
508            serde::de::Deserialize<'de>,
509    {
510        use crate::{IdenStatic, Iterable};
511
512        let serde_json::Value::Object(obj) = &json else {
513            return Err(DbErr::Json(format!(
514                "invalid type: expected JSON object for {}",
515                <<Self as ActiveModelTrait>::Entity as IdenStatic>::as_str(&Default::default())
516            )));
517        };
518
519        // Mark down which attribute exists in the JSON object
520        let mut json_keys: Vec<(<Self::Entity as EntityTrait>::Column, bool)> = Vec::new();
521
522        for col in <<Self::Entity as EntityTrait>::Column>::iter() {
523            let key = col.as_str();
524            let has_key = obj.contains_key(key);
525            json_keys.push((col, has_key));
526        }
527
528        // Convert JSON object into ActiveModel via Model
529        let model: <Self::Entity as EntityTrait>::Model =
530            serde_json::from_value(json).map_err(json_err)?;
531        let mut am = model.into_active_model();
532
533        // Transform attribute that exists in JSON object into ActiveValue::Set, otherwise ActiveValue::NotSet
534        for (col, json_key_exists) in json_keys {
535            match (json_key_exists, am.get(col)) {
536                (true, ActiveValue::Set(value) | ActiveValue::Unchanged(value)) => {
537                    am.set(col, value);
538                }
539                _ => {
540                    am.not_set(col);
541                }
542            }
543        }
544
545        Ok(am)
546    }
547
548    /// Return `true` if any attribute of `ActiveModel` is `Set`
549    fn is_changed(&self) -> bool {
550        <Self::Entity as EntityTrait>::Column::iter()
551            .any(|col| self.get(col).is_set() && !self.get(col).is_unchanged())
552    }
553}
554
555/// A Trait for overriding the ActiveModel behavior
556///
557/// ### Example
558/// ```ignore
559/// use sea_orm::entity::prelude::*;
560///
561///  // Use [DeriveEntity] to derive the EntityTrait automatically
562/// #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
563/// pub struct Entity;
564///
565/// /// The [EntityName] describes the name of a table
566/// impl EntityName for Entity {
567///     fn table_name(&self) -> &str {
568///         "cake"
569///     }
570/// }
571///
572/// // Derive the ActiveModel
573/// #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
574/// pub struct Model {
575///     pub id: i32,
576///     pub name: String,
577/// }
578///
579/// impl ActiveModelBehavior for ActiveModel {}
580/// ```
581/// See module level docs [crate::entity] for a full example
582#[allow(unused_variables)]
583#[async_trait]
584pub trait ActiveModelBehavior: ActiveModelTrait {
585    /// Create a new ActiveModel with default values. Also used by `Default::default()`.
586    fn new() -> Self {
587        <Self as ActiveModelTrait>::default()
588    }
589
590    /// Will be called before `ActiveModel::insert`, `ActiveModel::update`, and `ActiveModel::save`
591    async fn before_save<C>(self, db: &C, insert: bool) -> Result<Self, DbErr>
592    where
593        C: ConnectionTrait,
594    {
595        Ok(self)
596    }
597
598    /// Will be called after `ActiveModel::insert`, `ActiveModel::update`, and `ActiveModel::save`
599    async fn after_save<C>(
600        model: <Self::Entity as EntityTrait>::Model,
601        db: &C,
602        insert: bool,
603    ) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
604    where
605        C: ConnectionTrait,
606    {
607        Ok(model)
608    }
609
610    /// Will be called before `ActiveModel::delete`
611    async fn before_delete<C>(self, db: &C) -> Result<Self, DbErr>
612    where
613        C: ConnectionTrait,
614    {
615        Ok(self)
616    }
617
618    /// Will be called after `ActiveModel::delete`
619    async fn after_delete<C>(self, db: &C) -> Result<Self, DbErr>
620    where
621        C: ConnectionTrait,
622    {
623        Ok(self)
624    }
625}
626
627/// A Trait for any type that can be converted into an ActiveModel
628pub trait IntoActiveModel<A>
629where
630    A: ActiveModelTrait,
631{
632    /// Method to call to perform the conversion
633    fn into_active_model(self) -> A;
634}
635
636impl<A> IntoActiveModel<A> for A
637where
638    A: ActiveModelTrait,
639{
640    fn into_active_model(self) -> A {
641        self
642    }
643}
644
645/// Any type that can be converted into an [ActiveValue]
646pub trait IntoActiveValue<V>
647where
648    V: Into<Value>,
649{
650    /// Method to perform the conversion
651    fn into_active_value(self) -> ActiveValue<V>;
652}
653
654impl<V> IntoActiveValue<Option<V>> for Option<V>
655where
656    V: IntoActiveValue<V> + Into<Value> + Nullable,
657{
658    fn into_active_value(self) -> ActiveValue<Option<V>> {
659        match self {
660            Some(value) => Set(Some(value)),
661            None => NotSet,
662        }
663    }
664}
665
666impl<V> IntoActiveValue<Option<V>> for Option<Option<V>>
667where
668    V: IntoActiveValue<V> + Into<Value> + Nullable,
669{
670    fn into_active_value(self) -> ActiveValue<Option<V>> {
671        match self {
672            Some(value) => Set(value),
673            None => NotSet,
674        }
675    }
676}
677
678macro_rules! impl_into_active_value {
679    ($ty: ty) => {
680        impl IntoActiveValue<$ty> for $ty {
681            fn into_active_value(self) -> ActiveValue<$ty> {
682                Set(self)
683            }
684        }
685    };
686}
687
688impl_into_active_value!(bool);
689impl_into_active_value!(i8);
690impl_into_active_value!(i16);
691impl_into_active_value!(i32);
692impl_into_active_value!(i64);
693impl_into_active_value!(u8);
694impl_into_active_value!(u16);
695impl_into_active_value!(u32);
696impl_into_active_value!(u64);
697impl_into_active_value!(f32);
698impl_into_active_value!(f64);
699impl_into_active_value!(&'static str);
700impl_into_active_value!(String);
701impl_into_active_value!(Vec<u8>);
702
703#[cfg(feature = "with-json")]
704#[cfg_attr(docsrs, doc(cfg(feature = "with-json")))]
705impl_into_active_value!(crate::prelude::Json);
706
707#[cfg(feature = "with-chrono")]
708#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
709impl_into_active_value!(crate::prelude::Date);
710
711#[cfg(feature = "with-chrono")]
712#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
713impl_into_active_value!(crate::prelude::Time);
714
715#[cfg(feature = "with-chrono")]
716#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
717impl_into_active_value!(crate::prelude::DateTime);
718
719#[cfg(feature = "with-chrono")]
720#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
721impl_into_active_value!(crate::prelude::DateTimeWithTimeZone);
722
723#[cfg(feature = "with-chrono")]
724#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
725impl_into_active_value!(crate::prelude::DateTimeUtc);
726
727#[cfg(feature = "with-chrono")]
728#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
729impl_into_active_value!(crate::prelude::DateTimeLocal);
730
731#[cfg(feature = "with-rust_decimal")]
732#[cfg_attr(docsrs, doc(cfg(feature = "with-rust_decimal")))]
733impl_into_active_value!(crate::prelude::Decimal);
734
735#[cfg(feature = "with-uuid")]
736#[cfg_attr(docsrs, doc(cfg(feature = "with-uuid")))]
737impl_into_active_value!(crate::prelude::Uuid);
738
739#[cfg(feature = "with-time")]
740#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
741impl_into_active_value!(crate::prelude::TimeDate);
742
743#[cfg(feature = "with-time")]
744#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
745impl_into_active_value!(crate::prelude::TimeTime);
746
747#[cfg(feature = "with-time")]
748#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
749impl_into_active_value!(crate::prelude::TimeDateTime);
750
751#[cfg(feature = "with-time")]
752#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
753impl_into_active_value!(crate::prelude::TimeDateTimeWithTimeZone);
754
755#[cfg(feature = "with-ipnetwork")]
756#[cfg_attr(docsrs, doc(cfg(feature = "with-ipnetwork")))]
757impl_into_active_value!(crate::prelude::IpNetwork);
758
759impl<V> Default for ActiveValue<V>
760where
761    V: Into<Value>,
762{
763    /// Create an [ActiveValue::NotSet]
764    fn default() -> Self {
765        Self::NotSet
766    }
767}
768
769impl<V> ActiveValue<V>
770where
771    V: Into<Value>,
772{
773    /// Create an [ActiveValue::Set]
774    pub fn set(value: V) -> Self {
775        Self::Set(value)
776    }
777
778    /// Check if the [ActiveValue] is [ActiveValue::Set]
779    pub fn is_set(&self) -> bool {
780        matches!(self, Self::Set(_))
781    }
782
783    /// Create an [ActiveValue::Unchanged]
784    pub fn unchanged(value: V) -> Self {
785        Self::Unchanged(value)
786    }
787
788    /// Check if the [ActiveValue] is [ActiveValue::Unchanged]
789    pub fn is_unchanged(&self) -> bool {
790        matches!(self, Self::Unchanged(_))
791    }
792
793    /// Create an [ActiveValue::NotSet]
794    pub fn not_set() -> Self {
795        Self::default()
796    }
797
798    /// Check if the [ActiveValue] is [ActiveValue::NotSet]
799    pub fn is_not_set(&self) -> bool {
800        matches!(self, Self::NotSet)
801    }
802
803    /// Get the mutable value an [ActiveValue]
804    /// also setting itself to [ActiveValue::NotSet]
805    pub fn take(&mut self) -> Option<V> {
806        match std::mem::take(self) {
807            ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value),
808            ActiveValue::NotSet => None,
809        }
810    }
811
812    /// Get an owned value of the [ActiveValue]
813    ///
814    /// # Panics
815    ///
816    /// Panics if it is [ActiveValue::NotSet]
817    pub fn unwrap(self) -> V {
818        match self {
819            ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
820            ActiveValue::NotSet => panic!("Cannot unwrap ActiveValue::NotSet"),
821        }
822    }
823
824    /// Check if a [Value] exists or not
825    pub fn into_value(self) -> Option<Value> {
826        match self {
827            ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value.into()),
828            ActiveValue::NotSet => None,
829        }
830    }
831
832    /// Wrap the [Value] into a `ActiveValue<Value>`
833    pub fn into_wrapped_value(self) -> ActiveValue<Value> {
834        match self {
835            Self::Set(value) => ActiveValue::set(value.into()),
836            Self::Unchanged(value) => ActiveValue::unchanged(value.into()),
837            Self::NotSet => ActiveValue::not_set(),
838        }
839    }
840
841    /// Reset the value from [ActiveValue::Unchanged] to [ActiveValue::Set],
842    /// leaving [ActiveValue::NotSet] untouched.
843    pub fn reset(&mut self) {
844        *self = match self.take() {
845            Some(value) => ActiveValue::Set(value),
846            None => ActiveValue::NotSet,
847        };
848    }
849
850    /// `Set(value)`, except when [`self.is_unchanged()`][ActiveValue#method.is_unchanged]
851    /// and `value` equals the current [Unchanged][ActiveValue::Unchanged] value.
852    ///
853    /// This is useful when you have an [Unchanged][ActiveValue::Unchanged] value from the database,
854    /// then update it using this method,
855    /// and then use [`.is_unchanged()`][ActiveValue#method.is_unchanged] to see whether it has *actually* changed.
856    ///
857    /// The same nice effect applies to the entire `ActiveModel`.
858    /// You can now meaningfully use [ActiveModelTrait::is_changed][ActiveModelTrait#method.is_changed]
859    /// to see whether are any changes that need to be saved to the database.
860    ///
861    /// ## Examples
862    ///
863    /// ```
864    /// # use sea_orm::ActiveValue;
865    /// #
866    /// let mut value = ActiveValue::Unchanged("old");
867    ///
868    /// // This wouldn't be the case if we used plain `value = Set("old");`
869    /// value.set_if_not_equals("old");
870    /// assert!(value.is_unchanged());
871    ///
872    /// // Only when we change the actual `&str` value, it becomes `Set`
873    /// value.set_if_not_equals("new");
874    /// assert_eq!(value.is_unchanged(), false);
875    /// assert_eq!(value, ActiveValue::Set("new"));
876    /// ```
877    pub fn set_if_not_equals(&mut self, value: V)
878    where
879        V: PartialEq,
880    {
881        match self {
882            ActiveValue::Unchanged(current) if &value == current => {}
883            _ => *self = ActiveValue::Set(value),
884        }
885    }
886
887    /// Get the inner value, unless `self` is [NotSet][ActiveValue::NotSet].
888    ///
889    /// There's also a panicking version: [ActiveValue::as_ref].
890    ///
891    /// ## Examples
892    ///
893    /// ```
894    /// # use sea_orm::ActiveValue;
895    /// #
896    /// assert_eq!(ActiveValue::Unchanged(42).try_as_ref(), Some(&42));
897    /// assert_eq!(ActiveValue::Set(42).try_as_ref(), Some(&42));
898    /// assert_eq!(ActiveValue::NotSet.try_as_ref(), None::<&i32>);
899    /// ```
900    pub fn try_as_ref(&self) -> Option<&V> {
901        match self {
902            ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value),
903            ActiveValue::NotSet => None,
904        }
905    }
906}
907
908impl<V> std::convert::AsRef<V> for ActiveValue<V>
909where
910    V: Into<Value>,
911{
912    /// # Panics
913    ///
914    /// Panics if it is [ActiveValue::NotSet].
915    ///
916    /// See [ActiveValue::try_as_ref] for a fallible non-panicking version.
917    fn as_ref(&self) -> &V {
918        match self {
919            ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
920            ActiveValue::NotSet => panic!("Cannot borrow ActiveValue::NotSet"),
921        }
922    }
923}
924
925impl<V> PartialEq for ActiveValue<V>
926where
927    V: Into<Value> + std::cmp::PartialEq,
928{
929    fn eq(&self, other: &Self) -> bool {
930        match (self, other) {
931            (ActiveValue::Set(l), ActiveValue::Set(r)) => l == r,
932            (ActiveValue::Unchanged(l), ActiveValue::Unchanged(r)) => l == r,
933            (ActiveValue::NotSet, ActiveValue::NotSet) => true,
934            _ => false,
935        }
936    }
937}
938
939impl<V> From<ActiveValue<V>> for ActiveValue<Option<V>>
940where
941    V: Into<Value> + Nullable,
942{
943    fn from(value: ActiveValue<V>) -> Self {
944        match value {
945            ActiveValue::Set(value) => ActiveValue::set(Some(value)),
946            ActiveValue::Unchanged(value) => ActiveValue::unchanged(Some(value)),
947            ActiveValue::NotSet => ActiveValue::not_set(),
948        }
949    }
950}
951
952#[cfg(test)]
953mod tests {
954    use crate::{entity::*, tests_cfg::*, DbErr};
955    use pretty_assertions::assert_eq;
956
957    #[cfg(feature = "with-json")]
958    use serde_json::json;
959
960    #[test]
961    #[cfg(feature = "macros")]
962    fn test_derive_into_active_model_1() {
963        mod my_fruit {
964            pub use super::fruit::*;
965            use crate as sea_orm;
966            use crate::entity::prelude::*;
967
968            #[derive(DeriveIntoActiveModel)]
969            pub struct NewFruit {
970                // id is omitted
971                pub name: String,
972                // it is required as opposed to optional in Model
973                pub cake_id: i32,
974            }
975        }
976
977        assert_eq!(
978            my_fruit::NewFruit {
979                name: "Apple".to_owned(),
980                cake_id: 1,
981            }
982            .into_active_model(),
983            fruit::ActiveModel {
984                id: NotSet,
985                name: Set("Apple".to_owned()),
986                cake_id: Set(Some(1)),
987            }
988        );
989    }
990
991    #[test]
992    #[cfg(feature = "macros")]
993    fn test_derive_into_active_model_2() {
994        use crate as sea_orm;
995        use crate::entity::prelude::*;
996
997        #[derive(DeriveIntoActiveModel)]
998        #[sea_orm(active_model = "fruit::ActiveModel")]
999        struct FruitName {
1000            name: String,
1001        }
1002
1003        assert_eq!(
1004            FruitName {
1005                name: "Apple Pie".to_owned(),
1006            }
1007            .into_active_model(),
1008            fruit::ActiveModel {
1009                id: NotSet,
1010                name: Set("Apple Pie".to_owned()),
1011                cake_id: NotSet,
1012            }
1013        );
1014
1015        #[derive(DeriveIntoActiveModel)]
1016        #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
1017        struct FruitCake {
1018            cake_id: Option<Option<i32>>,
1019        }
1020
1021        assert_eq!(
1022            FruitCake {
1023                cake_id: Some(Some(1)),
1024            }
1025            .into_active_model(),
1026            fruit::ActiveModel {
1027                id: NotSet,
1028                name: NotSet,
1029                cake_id: Set(Some(1)),
1030            }
1031        );
1032
1033        assert_eq!(
1034            FruitCake {
1035                cake_id: Some(None),
1036            }
1037            .into_active_model(),
1038            fruit::ActiveModel {
1039                id: NotSet,
1040                name: NotSet,
1041                cake_id: Set(None),
1042            }
1043        );
1044
1045        assert_eq!(
1046            FruitCake { cake_id: None }.into_active_model(),
1047            fruit::ActiveModel {
1048                id: NotSet,
1049                name: NotSet,
1050                cake_id: NotSet,
1051            }
1052        );
1053    }
1054
1055    #[test]
1056    #[cfg(feature = "macros")]
1057    fn test_derive_try_into_model_1() {
1058        mod my_fruit {
1059            use crate as sea_orm;
1060            use crate::entity::prelude::*;
1061
1062            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1063            #[sea_orm(table_name = "fruit")]
1064            pub struct Model {
1065                #[sea_orm(primary_key)]
1066                pub id: i32,
1067                pub name: String,
1068                pub cake_id: Option<i32>,
1069            }
1070
1071            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1072            pub enum Relation {}
1073
1074            impl ActiveModelBehavior for ActiveModel {}
1075        }
1076        assert_eq!(
1077            my_fruit::ActiveModel {
1078                id: Set(1),
1079                name: Set("Pineapple".to_owned()),
1080                cake_id: Set(None),
1081            }
1082            .try_into_model()
1083            .unwrap(),
1084            my_fruit::Model {
1085                id: 1,
1086                name: "Pineapple".to_owned(),
1087                cake_id: None,
1088            }
1089        );
1090
1091        assert_eq!(
1092            my_fruit::ActiveModel {
1093                id: Set(2),
1094                name: Set("Apple".to_owned()),
1095                cake_id: Set(Some(1)),
1096            }
1097            .try_into_model()
1098            .unwrap(),
1099            my_fruit::Model {
1100                id: 2,
1101                name: "Apple".to_owned(),
1102                cake_id: Some(1),
1103            }
1104        );
1105
1106        assert_eq!(
1107            my_fruit::ActiveModel {
1108                id: Set(1),
1109                name: NotSet,
1110                cake_id: Set(None),
1111            }
1112            .try_into_model(),
1113            Err(DbErr::AttrNotSet(String::from("name")))
1114        );
1115
1116        assert_eq!(
1117            my_fruit::ActiveModel {
1118                id: Set(1),
1119                name: Set("Pineapple".to_owned()),
1120                cake_id: NotSet,
1121            }
1122            .try_into_model(),
1123            Err(DbErr::AttrNotSet(String::from("cake_id")))
1124        );
1125    }
1126
1127    #[test]
1128    #[cfg(feature = "macros")]
1129    fn test_derive_try_into_model_2() {
1130        mod my_fruit {
1131            use crate as sea_orm;
1132            use crate::entity::prelude::*;
1133
1134            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1135            #[sea_orm(table_name = "fruit")]
1136            pub struct Model {
1137                #[sea_orm(primary_key)]
1138                pub id: i32,
1139                pub name: String,
1140                #[sea_orm(ignore)]
1141                pub cake_id: Option<i32>,
1142            }
1143
1144            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1145            pub enum Relation {}
1146
1147            impl ActiveModelBehavior for ActiveModel {}
1148        }
1149        assert_eq!(
1150            my_fruit::ActiveModel {
1151                id: Set(1),
1152                name: Set("Pineapple".to_owned()),
1153            }
1154            .try_into_model()
1155            .unwrap(),
1156            my_fruit::Model {
1157                id: 1,
1158                name: "Pineapple".to_owned(),
1159                cake_id: None,
1160            }
1161        );
1162    }
1163
1164    #[test]
1165    #[cfg(feature = "macros")]
1166    fn test_derive_try_into_model_3() {
1167        mod my_fruit {
1168            use crate as sea_orm;
1169            use crate::entity::prelude::*;
1170
1171            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1172            #[sea_orm(table_name = "fruit")]
1173            pub struct Model {
1174                #[sea_orm(primary_key)]
1175                pub id: i32,
1176                #[sea_orm(ignore)]
1177                pub name: String,
1178                pub cake_id: Option<i32>,
1179            }
1180
1181            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1182            pub enum Relation {}
1183
1184            impl ActiveModelBehavior for ActiveModel {}
1185        }
1186        assert_eq!(
1187            my_fruit::ActiveModel {
1188                id: Set(1),
1189                cake_id: Set(Some(1)),
1190            }
1191            .try_into_model()
1192            .unwrap(),
1193            my_fruit::Model {
1194                id: 1,
1195                name: "".to_owned(),
1196                cake_id: Some(1),
1197            }
1198        );
1199    }
1200
1201    #[test]
1202    #[cfg(feature = "with-json")]
1203    #[should_panic(
1204        expected = r#"called `Result::unwrap()` on an `Err` value: Json("missing field `id`")"#
1205    )]
1206    fn test_active_model_set_from_json_1() {
1207        let mut cake: cake::ActiveModel = Default::default();
1208
1209        cake.set_from_json(json!({
1210            "name": "Apple Pie",
1211        }))
1212        .unwrap();
1213    }
1214
1215    #[test]
1216    #[cfg(feature = "with-json")]
1217    fn test_active_model_set_from_json_2() -> Result<(), DbErr> {
1218        let mut fruit: fruit::ActiveModel = Default::default();
1219
1220        fruit.set_from_json(json!({
1221            "name": "Apple",
1222        }))?;
1223        assert_eq!(
1224            fruit,
1225            fruit::ActiveModel {
1226                id: ActiveValue::NotSet,
1227                name: ActiveValue::Set("Apple".to_owned()),
1228                cake_id: ActiveValue::NotSet,
1229            }
1230        );
1231
1232        assert_eq!(
1233            fruit::ActiveModel::from_json(json!({
1234                "name": "Apple",
1235            }))?,
1236            fruit::ActiveModel {
1237                id: ActiveValue::NotSet,
1238                name: ActiveValue::Set("Apple".to_owned()),
1239                cake_id: ActiveValue::NotSet,
1240            }
1241        );
1242
1243        fruit.set_from_json(json!({
1244            "name": "Apple",
1245            "cake_id": null,
1246        }))?;
1247        assert_eq!(
1248            fruit,
1249            fruit::ActiveModel {
1250                id: ActiveValue::NotSet,
1251                name: ActiveValue::Set("Apple".to_owned()),
1252                cake_id: ActiveValue::Set(None),
1253            }
1254        );
1255
1256        fruit.set_from_json(json!({
1257            "id": null,
1258            "name": "Apple",
1259            "cake_id": 1,
1260        }))?;
1261        assert_eq!(
1262            fruit,
1263            fruit::ActiveModel {
1264                id: ActiveValue::NotSet,
1265                name: ActiveValue::Set("Apple".to_owned()),
1266                cake_id: ActiveValue::Set(Some(1)),
1267            }
1268        );
1269
1270        fruit.set_from_json(json!({
1271            "id": 2,
1272            "name": "Apple",
1273            "cake_id": 1,
1274        }))?;
1275        assert_eq!(
1276            fruit,
1277            fruit::ActiveModel {
1278                id: ActiveValue::NotSet,
1279                name: ActiveValue::Set("Apple".to_owned()),
1280                cake_id: ActiveValue::Set(Some(1)),
1281            }
1282        );
1283
1284        let mut fruit = fruit::ActiveModel {
1285            id: ActiveValue::Set(1),
1286            name: ActiveValue::NotSet,
1287            cake_id: ActiveValue::NotSet,
1288        };
1289        fruit.set_from_json(json!({
1290            "id": 8,
1291            "name": "Apple",
1292            "cake_id": 1,
1293        }))?;
1294        assert_eq!(
1295            fruit,
1296            fruit::ActiveModel {
1297                id: ActiveValue::Set(1),
1298                name: ActiveValue::Set("Apple".to_owned()),
1299                cake_id: ActiveValue::Set(Some(1)),
1300            }
1301        );
1302
1303        Ok(())
1304    }
1305
1306    #[smol_potat::test]
1307    #[cfg(feature = "with-json")]
1308    async fn test_active_model_set_from_json_3() -> Result<(), DbErr> {
1309        use crate::*;
1310
1311        let db = MockDatabase::new(DbBackend::Postgres)
1312            .append_exec_results([
1313                MockExecResult {
1314                    last_insert_id: 1,
1315                    rows_affected: 1,
1316                },
1317                MockExecResult {
1318                    last_insert_id: 1,
1319                    rows_affected: 1,
1320                },
1321            ])
1322            .append_query_results([
1323                [fruit::Model {
1324                    id: 1,
1325                    name: "Apple".to_owned(),
1326                    cake_id: None,
1327                }],
1328                [fruit::Model {
1329                    id: 2,
1330                    name: "Orange".to_owned(),
1331                    cake_id: Some(1),
1332                }],
1333            ])
1334            .into_connection();
1335
1336        let mut fruit: fruit::ActiveModel = Default::default();
1337        fruit.set_from_json(json!({
1338            "name": "Apple",
1339        }))?;
1340        fruit.save(&db).await?;
1341
1342        let mut fruit = fruit::ActiveModel {
1343            id: Set(2),
1344            ..Default::default()
1345        };
1346        fruit.set_from_json(json!({
1347            "id": 9,
1348            "name": "Orange",
1349            "cake_id": 1,
1350        }))?;
1351        fruit.save(&db).await?;
1352
1353        assert_eq!(
1354            db.into_transaction_log(),
1355            [
1356                Transaction::from_sql_and_values(
1357                    DbBackend::Postgres,
1358                    r#"INSERT INTO "fruit" ("name") VALUES ($1) RETURNING "id", "name", "cake_id""#,
1359                    ["Apple".into()],
1360                ),
1361                Transaction::from_sql_and_values(
1362                    DbBackend::Postgres,
1363                    r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
1364                    ["Orange".into(), 1i32.into(), 2i32.into()],
1365                ),
1366            ]
1367        );
1368
1369        Ok(())
1370    }
1371
1372    #[test]
1373    fn test_active_model_is_changed() {
1374        let mut fruit: fruit::ActiveModel = Default::default();
1375        assert!(!fruit.is_changed());
1376
1377        fruit.set(fruit::Column::Name, "apple".into());
1378        assert!(fruit.is_changed());
1379    }
1380
1381    #[test]
1382    fn test_reset_1() {
1383        assert_eq!(
1384            fruit::Model {
1385                id: 1,
1386                name: "Apple".into(),
1387                cake_id: None,
1388            }
1389            .into_active_model(),
1390            fruit::ActiveModel {
1391                id: Unchanged(1),
1392                name: Unchanged("Apple".into()),
1393                cake_id: Unchanged(None)
1394            },
1395        );
1396
1397        assert_eq!(
1398            fruit::Model {
1399                id: 1,
1400                name: "Apple".into(),
1401                cake_id: None,
1402            }
1403            .into_active_model()
1404            .reset_all(),
1405            fruit::ActiveModel {
1406                id: Set(1),
1407                name: Set("Apple".into()),
1408                cake_id: Set(None)
1409            },
1410        );
1411
1412        assert_eq!(
1413            fruit::Model {
1414                id: 1,
1415                name: "Apple".into(),
1416                cake_id: Some(2),
1417            }
1418            .into_active_model(),
1419            fruit::ActiveModel {
1420                id: Unchanged(1),
1421                name: Unchanged("Apple".into()),
1422                cake_id: Unchanged(Some(2)),
1423            },
1424        );
1425
1426        assert_eq!(
1427            fruit::Model {
1428                id: 1,
1429                name: "Apple".into(),
1430                cake_id: Some(2),
1431            }
1432            .into_active_model()
1433            .reset_all(),
1434            fruit::ActiveModel {
1435                id: Set(1),
1436                name: Set("Apple".into()),
1437                cake_id: Set(Some(2)),
1438            },
1439        );
1440    }
1441
1442    #[smol_potat::test]
1443    async fn test_reset_2() -> Result<(), DbErr> {
1444        use crate::*;
1445
1446        let db = MockDatabase::new(DbBackend::Postgres)
1447            .append_exec_results(vec![
1448                MockExecResult {
1449                    last_insert_id: 1,
1450                    rows_affected: 1,
1451                },
1452                MockExecResult {
1453                    last_insert_id: 1,
1454                    rows_affected: 1,
1455                },
1456            ])
1457            .append_query_results(vec![
1458                vec![fruit::Model {
1459                    id: 1,
1460                    name: "Apple".to_owned(),
1461                    cake_id: None,
1462                }],
1463                vec![fruit::Model {
1464                    id: 1,
1465                    name: "Apple".to_owned(),
1466                    cake_id: None,
1467                }],
1468            ])
1469            .into_connection();
1470
1471        fruit::Model {
1472            id: 1,
1473            name: "Apple".into(),
1474            cake_id: None,
1475        }
1476        .into_active_model()
1477        .update(&db)
1478        .await?;
1479
1480        fruit::Model {
1481            id: 1,
1482            name: "Apple".into(),
1483            cake_id: None,
1484        }
1485        .into_active_model()
1486        .reset_all()
1487        .update(&db)
1488        .await?;
1489
1490        assert_eq!(
1491            db.into_transaction_log(),
1492            vec![
1493                Transaction::from_sql_and_values(
1494                    DbBackend::Postgres,
1495                    r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit" WHERE "fruit"."id" = $1 LIMIT $2"#,
1496                    vec![1i32.into(), 1u64.into()],
1497                ),
1498                Transaction::from_sql_and_values(
1499                    DbBackend::Postgres,
1500                    r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
1501                    vec!["Apple".into(), Option::<i32>::None.into(), 1i32.into()],
1502                ),
1503            ]
1504        );
1505
1506        Ok(())
1507    }
1508}