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