sea_orm/entity/
active_model.rs

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