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