sea_orm/entity/
active_model.rs

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