Skip to main content

sea_orm/entity/
active_model.rs

1use super::{ActiveValue, ActiveValue::*};
2use crate::{
3    ColumnTrait, Condition, ConnectionTrait, DbBackend, DeleteResult, EntityName, EntityTrait,
4    IdenStatic, Iterable, PrimaryKeyArity, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter,
5    Related, RelatedSelfVia, RelationDef, RelationTrait, Value,
6    error::*,
7    query::{
8        clear_key_on_active_model, column_tuple_in_condition, get_key_from_active_model,
9        set_key_on_active_model,
10    },
11};
12use sea_query::ValueTuple;
13use std::fmt::Debug;
14
15/// `ActiveModel` is a type for constructing `INSERT` and `UPDATE` statements for a particular table.
16///
17/// Like [Model][ModelTrait], it represents a database record and each field represents a column.
18///
19/// But unlike [Model][ModelTrait], it also stores [additional state][ActiveValue] for every field,
20/// and fields are not guaranteed to have a value.
21///
22/// This allows you to:
23///
24/// - omit columns from the query,
25/// - know which columns have changed after editing a record.
26pub trait ActiveModelTrait: Clone + Debug {
27    /// The Entity this ActiveModel belongs to
28    type Entity: EntityTrait;
29
30    /// Get a mutable [ActiveValue] from an ActiveModel
31    fn take(&mut self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
32
33    /// Get a immutable [ActiveValue] from an ActiveModel
34    fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
35
36    /// Set the Value of a ActiveModel field, panic if failed
37    fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) {
38        self.try_set(c, v)
39            .unwrap_or_else(|e| panic!("Failed to set value for {:?}: {e:?}", c.as_column_ref()))
40    }
41
42    /// Set the Value of a ActiveModel field if value is different, panic if failed
43    fn set_if_not_equals(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
44
45    /// Set the Value of a ActiveModel field, return error if failed
46    fn try_set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) -> Result<(), DbErr>;
47
48    /// Set the state of an [ActiveValue] to the not set state
49    fn not_set(&mut self, c: <Self::Entity as EntityTrait>::Column);
50
51    /// Check the state of a [ActiveValue]
52    fn is_not_set(&self, c: <Self::Entity as EntityTrait>::Column) -> bool;
53
54    /// Create an ActiveModel with all fields to NotSet
55    fn default() -> Self;
56
57    /// Create an ActiveModel with all fields to Set(default_value) if Default is implemented, NotSet otherwise
58    fn default_values() -> Self;
59
60    /// Reset the value from [ActiveValue::Unchanged] to [ActiveValue::Set],
61    /// leaving [ActiveValue::NotSet] untouched.
62    fn reset(&mut self, c: <Self::Entity as EntityTrait>::Column);
63
64    /// Reset all values from [ActiveValue::Unchanged] to [ActiveValue::Set],
65    /// leaving [ActiveValue::NotSet] untouched.
66    fn reset_all(mut self) -> Self {
67        for col in <Self::Entity as EntityTrait>::Column::iter() {
68            self.reset(col);
69        }
70        self
71    }
72
73    /// Get the primary key of the ActiveModel, only if it's fully specified.
74    fn get_primary_key_value(&self) -> Option<ValueTuple> {
75        let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
76        macro_rules! next {
77            () => {
78                self.get(cols.next()?.into_column()).into_value()?
79            };
80        }
81        match <<<Self::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType as PrimaryKeyArity>::ARITY {
82            1 => {
83                let s1 = next!();
84                Some(ValueTuple::One(s1))
85            }
86            2 => {
87                let s1 = next!();
88                let s2 = next!();
89                Some(ValueTuple::Two(s1, s2))
90            }
91            3 => {
92                let s1 = next!();
93                let s2 = next!();
94                let s3 = next!();
95                Some(ValueTuple::Three(s1, s2, s3))
96            }
97            len => {
98                let mut vec = Vec::with_capacity(len);
99                for _ in 0..len {
100                    let s = next!();
101                    vec.push(s);
102                }
103                Some(ValueTuple::Many(vec))
104            }
105        }
106    }
107
108    /// Perform an `INSERT` operation on the ActiveModel
109    ///
110    /// # Example (Postgres)
111    ///
112    /// ```
113    /// # use sea_orm::{error::*, tests_cfg::*, *};
114    /// #
115    /// # #[cfg(feature = "mock")]
116    /// # pub fn main() -> Result<(), DbErr> {
117    /// #
118    /// # let db = MockDatabase::new(DbBackend::Postgres)
119    /// #     .append_query_results([
120    /// #         [cake::Model {
121    /// #             id: 15,
122    /// #             name: "Apple Pie".to_owned(),
123    /// #         }],
124    /// #     ])
125    /// #     .into_connection();
126    /// #
127    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
128    ///
129    /// let apple = cake::ActiveModel {
130    ///     name: Set("Apple Pie".to_owned()),
131    ///     ..Default::default()
132    /// };
133    ///
134    /// assert_eq!(
135    ///     apple.insert(&db)?,
136    ///     cake::Model {
137    ///         id: 15,
138    ///         name: "Apple Pie".to_owned(),
139    ///     }
140    /// );
141    ///
142    /// assert_eq!(
143    ///     db.into_transaction_log(),
144    ///     [Transaction::from_sql_and_values(
145    ///         DbBackend::Postgres,
146    ///         r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id", "name""#,
147    ///         ["Apple Pie".into()]
148    ///     )]
149    /// );
150    /// #
151    /// # Ok(())
152    /// # }
153    /// ```
154    ///
155    /// # Example (MySQL)
156    ///
157    /// ```
158    /// # use sea_orm::{error::*, tests_cfg::*, *};
159    /// #
160    /// # #[cfg(feature = "mock")]
161    /// # pub fn main() -> Result<(), DbErr> {
162    /// #
163    /// # let db = MockDatabase::new(DbBackend::MySql)
164    /// #     .append_query_results([
165    /// #         [cake::Model {
166    /// #             id: 15,
167    /// #             name: "Apple Pie".to_owned(),
168    /// #         }],
169    /// #     ])
170    /// #     .append_exec_results([
171    /// #         MockExecResult {
172    /// #             last_insert_id: 15,
173    /// #             rows_affected: 1,
174    /// #         },
175    /// #     ])
176    /// #     .into_connection();
177    /// #
178    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
179    ///
180    /// let apple = cake::ActiveModel {
181    ///     name: Set("Apple Pie".to_owned()),
182    ///     ..Default::default()
183    /// };
184    ///
185    /// assert_eq!(
186    ///     apple.insert(&db)?,
187    ///     cake::Model {
188    ///         id: 15,
189    ///         name: "Apple Pie".to_owned(),
190    ///     }
191    /// );
192    ///
193    /// assert_eq!(
194    ///     db.into_transaction_log(),
195    ///     [
196    ///         Transaction::from_sql_and_values(
197    ///             DbBackend::MySql,
198    ///             r#"INSERT INTO `cake` (`name`) VALUES (?)"#,
199    ///             ["Apple Pie".into()]
200    ///         ),
201    ///         Transaction::from_sql_and_values(
202    ///             DbBackend::MySql,
203    ///             r#"SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = ? LIMIT ?"#,
204    ///             [15.into(), 1u64.into()]
205    ///         )
206    ///     ]
207    /// );
208    /// #
209    /// # Ok(())
210    /// # }
211    /// ```
212    fn insert<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
213    where
214        <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
215        Self: ActiveModelBehavior,
216        C: ConnectionTrait,
217    {
218        let am = ActiveModelBehavior::before_save(self, db, true)?;
219        let model = <Self::Entity as EntityTrait>::insert(am).exec_with_returning(db)?;
220        Self::after_save(model, db, true)
221    }
222
223    /// Perform the `UPDATE` operation on an ActiveModel
224    ///
225    /// # Example (Postgres)
226    ///
227    /// ```
228    /// # use sea_orm::{error::*, tests_cfg::*, *};
229    /// #
230    /// # #[cfg(feature = "mock")]
231    /// # pub fn main() -> Result<(), DbErr> {
232    /// #
233    /// # let db = MockDatabase::new(DbBackend::Postgres)
234    /// #     .append_query_results([
235    /// #         [fruit::Model {
236    /// #             id: 1,
237    /// #             name: "Orange".to_owned(),
238    /// #             cake_id: None,
239    /// #         }],
240    /// #     ])
241    /// #     .into_connection();
242    /// #
243    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
244    ///
245    /// let orange = fruit::ActiveModel {
246    ///     id: Set(1),
247    ///     name: Set("Orange".to_owned()),
248    ///     ..Default::default()
249    /// };
250    ///
251    /// assert_eq!(
252    ///     orange.update(&db)?,
253    ///     fruit::Model {
254    ///         id: 1,
255    ///         name: "Orange".to_owned(),
256    ///         cake_id: None,
257    ///     }
258    /// );
259    ///
260    /// assert_eq!(
261    ///     db.into_transaction_log(),
262    ///     [Transaction::from_sql_and_values(
263    ///         DbBackend::Postgres,
264    ///         r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2 RETURNING "id", "name", "cake_id""#,
265    ///         ["Orange".into(), 1i32.into()]
266    ///     )]);
267    /// #
268    /// # Ok(())
269    /// # }
270    /// ```
271    ///
272    /// # Example (MySQL)
273    ///
274    /// ```
275    /// # use sea_orm::{error::*, tests_cfg::*, *};
276    /// #
277    /// # #[cfg(feature = "mock")]
278    /// # pub fn main() -> Result<(), DbErr> {
279    /// #
280    /// # let db = MockDatabase::new(DbBackend::MySql)
281    /// #     .append_query_results([
282    /// #         [fruit::Model {
283    /// #             id: 1,
284    /// #             name: "Orange".to_owned(),
285    /// #             cake_id: None,
286    /// #         }],
287    /// #     ])
288    /// #     .append_exec_results([
289    /// #         MockExecResult {
290    /// #             last_insert_id: 0,
291    /// #             rows_affected: 1,
292    /// #         },
293    /// #     ])
294    /// #     .into_connection();
295    /// #
296    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
297    ///
298    /// let orange = fruit::ActiveModel {
299    ///     id: Set(1),
300    ///     name: Set("Orange".to_owned()),
301    ///     ..Default::default()
302    /// };
303    ///
304    /// assert_eq!(
305    ///     orange.update(&db)?,
306    ///     fruit::Model {
307    ///         id: 1,
308    ///         name: "Orange".to_owned(),
309    ///         cake_id: None,
310    ///     }
311    /// );
312    ///
313    /// assert_eq!(
314    ///     db.into_transaction_log(),
315    ///     [
316    ///         Transaction::from_sql_and_values(
317    ///             DbBackend::MySql,
318    ///             r#"UPDATE `fruit` SET `name` = ? WHERE `fruit`.`id` = ?"#,
319    ///             ["Orange".into(), 1i32.into()]
320    ///         ),
321    ///         Transaction::from_sql_and_values(
322    ///             DbBackend::MySql,
323    ///             r#"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`id` = ? LIMIT ?"#,
324    ///             [1i32.into(), 1u64.into()]
325    ///         )]);
326    /// #
327    /// # Ok(())
328    /// # }
329    /// ```
330    fn update<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
331    where
332        <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
333        Self: ActiveModelBehavior,
334        C: ConnectionTrait,
335    {
336        let am = ActiveModelBehavior::before_save(self, db, false)?;
337        let model: <Self::Entity as EntityTrait>::Model = Self::Entity::update(am).exec(db)?;
338        Self::after_save(model, db, false)
339    }
340
341    /// Insert the model if primary key is `NotSet`, update otherwise.
342    /// Only works if the entity has auto increment primary key.
343    fn save<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
344    where
345        <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
346        Self: ActiveModelBehavior,
347        C: ConnectionTrait,
348    {
349        let res = if !self.is_update() {
350            self.insert(db)
351        } else {
352            self.update(db)
353        }?;
354        Ok(res.into_active_model())
355    }
356
357    /// Returns true if the primary key is fully-specified
358    #[doc(hidden)]
359    fn is_update(&self) -> bool {
360        let mut is_update = true;
361        for key in <Self::Entity as EntityTrait>::PrimaryKey::iter() {
362            let col = key.into_column();
363            if self.is_not_set(col) {
364                is_update = false;
365                break;
366            }
367        }
368        is_update
369    }
370
371    /// Delete an active model by its primary key
372    ///
373    /// # Example
374    ///
375    /// ```
376    /// # use sea_orm::{error::*, tests_cfg::*, *};
377    /// #
378    /// # #[cfg(feature = "mock")]
379    /// # pub fn main() -> Result<(), DbErr> {
380    /// #
381    /// # let db = MockDatabase::new(DbBackend::Postgres)
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(3),
394    ///     ..Default::default()
395    /// };
396    ///
397    /// let delete_result = orange.delete(&db)?;
398    ///
399    /// assert_eq!(delete_result.rows_affected, 1);
400    ///
401    /// assert_eq!(
402    ///     db.into_transaction_log(),
403    ///     [Transaction::from_sql_and_values(
404    ///         DbBackend::Postgres,
405    ///         r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
406    ///         [3i32.into()]
407    ///     )]
408    /// );
409    /// #
410    /// # Ok(())
411    /// # }
412    /// ```
413    fn delete<'a, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
414    where
415        Self: ActiveModelBehavior,
416        C: ConnectionTrait,
417    {
418        let am = ActiveModelBehavior::before_delete(self, db)?;
419        let am_clone = am.clone();
420        let delete_res = Self::Entity::delete(am).exec(db)?;
421        ActiveModelBehavior::after_delete(am_clone, db)?;
422        Ok(delete_res)
423    }
424
425    /// Set the corresponding attributes in the ActiveModel from a JSON value
426    ///
427    /// Note that this method will not alter the primary key values in ActiveModel.
428    #[cfg(feature = "with-json")]
429    fn set_from_json(&mut self, json: serde_json::Value) -> Result<(), DbErr>
430    where
431        Self: crate::TryIntoModel<<Self::Entity as EntityTrait>::Model>,
432        <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
433        for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
434            serde::de::Deserialize<'de> + serde::Serialize,
435    {
436        use crate::Iterable;
437
438        // Backup primary key values
439        let primary_key_values: Vec<(<Self::Entity as EntityTrait>::Column, ActiveValue<Value>)> =
440            <<Self::Entity as EntityTrait>::PrimaryKey>::iter()
441                .map(|pk| (pk.into_column(), self.take(pk.into_column())))
442                .collect();
443
444        // Replace all values in ActiveModel
445        *self = Self::from_json(json)?;
446
447        // Restore primary key values
448        for (col, active_value) in primary_key_values {
449            match active_value {
450                ActiveValue::Unchanged(v) | ActiveValue::Set(v) => self.set(col, v),
451                NotSet => self.not_set(col),
452            }
453        }
454
455        Ok(())
456    }
457
458    /// Create ActiveModel from a JSON value
459    #[cfg(feature = "with-json")]
460    fn from_json(mut json: serde_json::Value) -> Result<Self, DbErr>
461    where
462        Self: crate::TryIntoModel<<Self::Entity as EntityTrait>::Model>,
463        <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
464        for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
465            serde::de::Deserialize<'de> + serde::Serialize,
466    {
467        use crate::{IdenStatic, Iterable};
468
469        let serde_json::Value::Object(obj) = &json else {
470            return Err(DbErr::Json(format!(
471                "invalid type: expected JSON object for {}",
472                <<Self as ActiveModelTrait>::Entity as IdenStatic>::as_str(&Default::default())
473            )));
474        };
475
476        // Mark down which attribute exists in the JSON object
477        let mut json_keys: Vec<(<Self::Entity as EntityTrait>::Column, bool)> = Vec::new();
478
479        for col in <<Self::Entity as EntityTrait>::Column>::iter() {
480            let key = col.json_key();
481            let has_key = obj.contains_key(key);
482            json_keys.push((col, has_key));
483        }
484
485        // Create dummy model with dummy values
486        let dummy_model = Self::default_values();
487        if let Ok(dummy_model) = dummy_model.try_into_model() {
488            if let Ok(mut dummy_json) = serde_json::to_value(&dummy_model) {
489                let serde_json::Value::Object(merged) = &mut dummy_json else {
490                    unreachable!();
491                };
492                let serde_json::Value::Object(obj) = json else {
493                    unreachable!();
494                };
495                // overwrite dummy values with input values
496                for (key, value) in obj {
497                    merged.insert(key, value);
498                }
499                json = dummy_json;
500            }
501        }
502
503        // Convert JSON object into ActiveModel via Model
504        let model: <Self::Entity as EntityTrait>::Model =
505            serde_json::from_value(json).map_err(json_err)?;
506        let mut am = model.into_active_model();
507
508        // Transform attribute that exists in JSON object into ActiveValue::Set, otherwise ActiveValue::NotSet
509        for (col, json_key_exists) in json_keys {
510            match (json_key_exists, am.get(col)) {
511                (true, ActiveValue::Set(value) | ActiveValue::Unchanged(value)) => {
512                    am.set(col, value);
513                }
514                _ => {
515                    am.not_set(col);
516                }
517            }
518        }
519
520        Ok(am)
521    }
522
523    /// Create a Vec of ActiveModels from an Arrow RecordBatch.
524    ///
525    /// Each row in the RecordBatch becomes one ActiveModel.
526    /// Columns are matched by name (using [`ColumnTrait::as_str`](crate::ColumnTrait::as_str)).
527    /// Columns present in the RecordBatch are marked as `Set`;
528    /// columns absent from the RecordBatch are marked as `NotSet`.
529    ///
530    /// Supported column types: integers (i8–i64, u8–u64), floats (f32, f64),
531    /// `String`/`Text`, `Boolean`, and date/time types (with `with-chrono` or `with-time`).
532    /// Null values in nullable columns are handled.
533    ///
534    /// When both `with-chrono` and `with-time` features are enabled, chrono values
535    /// are attempted first. If the model uses time-crate types, the conversion
536    /// automatically falls back to the time-crate representation.
537    #[cfg(feature = "with-arrow")]
538    fn from_arrow(batch: &arrow::array::RecordBatch) -> Result<Vec<Self>, DbErr> {
539        use crate::{IdenStatic, Iterable, with_arrow::arrow_array_to_value};
540
541        let num_rows = batch.num_rows();
542        let mut results = Vec::with_capacity(num_rows);
543
544        for row in 0..num_rows {
545            let mut am = Self::default();
546
547            for col in <<Self::Entity as EntityTrait>::Column>::iter() {
548                let col_name = col.as_str();
549
550                if let Some(arrow_col) = batch.column_by_name(col_name) {
551                    let col_def = col.def();
552                    let col_type = col_def.get_column_type();
553                    let value = arrow_array_to_value(arrow_col.as_ref(), col_type, row)?;
554
555                    // When both chrono and time features are enabled, the primary
556                    // conversion produces chrono Values for date/time columns.
557                    // If the model's field uses time-crate types, try_set will fail;
558                    // retry with the time-crate alternative.
559                    #[cfg(all(feature = "with-chrono", feature = "with-time"))]
560                    {
561                        use crate::with_arrow::{arrow_array_to_value_alt, is_datetime_column};
562                        match am.try_set(col, value) {
563                            Ok(()) => {}
564                            Err(first_err) if is_datetime_column(col_type) => {
565                                if let Some(alt_value) =
566                                    arrow_array_to_value_alt(arrow_col.as_ref(), col_type, row)?
567                                {
568                                    am.try_set(col, alt_value)?;
569                                } else {
570                                    return Err(first_err);
571                                }
572                            }
573                            Err(e) => return Err(e),
574                        }
575                    }
576
577                    #[cfg(not(all(feature = "with-chrono", feature = "with-time")))]
578                    am.try_set(col, value)?;
579                } else {
580                    am.not_set(col);
581                }
582            }
583
584            results.push(am);
585        }
586
587        Ok(results)
588    }
589
590    /// Convert a slice of ActiveModels into an Arrow [`RecordBatch`](arrow::array::RecordBatch).
591    ///
592    /// The `schema` determines the output columns: each schema field is matched
593    /// to an entity column by name (using [`ColumnTrait::as_str`](crate::ColumnTrait::as_str)).
594    /// Columns marked `Set` or `Unchanged` contribute their value;
595    /// `NotSet` columns become null in the output.
596    ///
597    /// Typical usage together with [`ArrowSchema`](crate::ArrowSchema):
598    /// ```ignore
599    /// let schema = MyEntity::arrow_schema();
600    /// let batch = MyActiveModel::to_arrow(&models, &schema)?;
601    /// ```
602    #[cfg(feature = "with-arrow")]
603    fn to_arrow(
604        models: &[Self],
605        schema: &arrow::datatypes::Schema,
606    ) -> Result<arrow::array::RecordBatch, DbErr> {
607        use crate::{Iterable, with_arrow::option_values_to_arrow_array};
608        use std::sync::Arc;
609
610        let mut columns: Vec<Arc<dyn arrow::array::Array>> =
611            Vec::with_capacity(schema.fields().len());
612
613        for field in schema.fields() {
614            let field_name = field.name();
615
616            // Find the entity column whose name matches this schema field
617            let entity_col =
618                <<Self::Entity as EntityTrait>::Column>::iter().find(|c| c.as_str() == field_name);
619
620            if let Some(col) = entity_col {
621                let values: Vec<Option<Value>> = models
622                    .iter()
623                    .map(|m| match m.get(col) {
624                        ActiveValue::Set(v) | ActiveValue::Unchanged(v) => Some(v),
625                        ActiveValue::NotSet => None,
626                    })
627                    .collect();
628
629                let array = option_values_to_arrow_array(&values, field.data_type())?;
630                columns.push(array);
631            } else {
632                // Field in schema but not in entity → null column
633                let array = arrow::array::new_null_array(field.data_type(), models.len());
634                columns.push(array);
635            }
636        }
637
638        arrow::array::RecordBatch::try_new(Arc::new(schema.clone()), columns)
639            .map_err(|e| DbErr::Type(format!("Failed to create RecordBatch: {e}")))
640    }
641
642    /// Return `true` if any attribute of `ActiveModel` is `Set`
643    fn is_changed(&self) -> bool {
644        <Self::Entity as EntityTrait>::Column::iter()
645            .any(|col| matches!(self.get(col), ActiveValue::Set(_)))
646    }
647
648    #[doc(hidden)]
649    /// Set the key to parent's key value for a belongs to relation.
650    fn set_parent_key<R, AM>(&mut self, model: &AM) -> Result<(), DbErr>
651    where
652        R: EntityTrait,
653        AM: ActiveModelTrait<Entity = R>,
654        Self::Entity: Related<R>,
655    {
656        let rel_def = Self::Entity::to();
657
658        if rel_def.is_owner {
659            return Err(DbErr::Type(format!(
660                "Relation from {} to {} is not belongs_to",
661                <Self::Entity as Default>::default().as_str(),
662                <R as Default>::default().as_str()
663            )));
664        }
665
666        let values = get_key_from_active_model(&rel_def.to_col, model)?;
667
668        set_key_on_active_model(&rel_def.from_col, self, values)?;
669
670        Ok(())
671    }
672
673    #[doc(hidden)]
674    fn set_parent_key_for<R, AM>(
675        &mut self,
676        model: &AM,
677        rel: <Self::Entity as EntityTrait>::Relation,
678    ) -> Result<(), DbErr>
679    where
680        R: EntityTrait,
681        AM: ActiveModelTrait<Entity = R>,
682    {
683        let rel_def = rel.def();
684
685        if rel_def.is_owner {
686            return Err(DbErr::Type(format!("Relation {rel:?} is not belongs_to")));
687        }
688
689        let values = get_key_from_active_model(&rel_def.to_col, model)?;
690
691        set_key_on_active_model(&rel_def.from_col, self, values)?;
692
693        Ok(())
694    }
695
696    #[doc(hidden)]
697    fn set_parent_key_for_def<R, AM>(
698        &mut self,
699        model: &AM,
700        rel_def: &RelationDef,
701    ) -> Result<(), DbErr>
702    where
703        R: EntityTrait,
704        AM: ActiveModelTrait<Entity = R>,
705    {
706        if rel_def.is_owner {
707            return Err(DbErr::Type(format!(
708                "Relation {rel_def:?} is not belongs_to"
709            )));
710        }
711
712        let values = get_key_from_active_model(&rel_def.to_col, model)?;
713
714        set_key_on_active_model(&rel_def.from_col, self, values)?;
715
716        Ok(())
717    }
718
719    #[doc(hidden)]
720    fn set_parent_key_for_self_rev<AM>(
721        &mut self,
722        model: &AM,
723        rel: <Self::Entity as EntityTrait>::Relation,
724    ) -> Result<(), DbErr>
725    where
726        AM: ActiveModelTrait<Entity = Self::Entity>,
727    {
728        let rel_def = rel.def();
729
730        if !rel_def.is_owner {
731            return Err(DbErr::Type(format!("Relation {rel:?} is not owner")));
732        }
733
734        let values = get_key_from_active_model(&rel_def.from_col, model)?;
735
736        set_key_on_active_model(&rel_def.to_col, self, values)?;
737
738        Ok(())
739    }
740
741    #[doc(hidden)]
742    /// Clear parent association if the relation is optional and return true
743    fn clear_parent_key<R>(&mut self) -> Result<bool, DbErr>
744    where
745        R: EntityTrait,
746        Self::Entity: Related<R>,
747    {
748        let rel_def = Self::Entity::to();
749
750        if rel_def.is_owner {
751            return Err(DbErr::Type(format!(
752                "Relation from {} to {} is not belongs_to",
753                <Self::Entity as Default>::default().as_str(),
754                <R as Default>::default().as_str()
755            )));
756        }
757
758        clear_key_on_active_model(&rel_def.from_col, self)
759    }
760
761    #[doc(hidden)]
762    fn clear_parent_key_for_self_rev(
763        &mut self,
764        rel: <Self::Entity as EntityTrait>::Relation,
765    ) -> Result<bool, DbErr> {
766        let rel_def = rel.def();
767
768        if !rel_def.is_owner {
769            return Err(DbErr::Type(format!("Relation {rel:?} is not owner")));
770        }
771
772        clear_key_on_active_model(&rel_def.to_col, self)
773    }
774
775    #[doc(hidden)]
776    /// Get the key value of belongs to relation
777    fn get_parent_key<R>(&self) -> Result<ValueTuple, DbErr>
778    where
779        R: EntityTrait,
780        Self::Entity: Related<R>,
781    {
782        let rel_def = Self::Entity::to();
783
784        if rel_def.is_owner {
785            return Err(DbErr::Type(format!(
786                "Relation from {} to {} is not belongs_to",
787                <Self::Entity as Default>::default().as_str(),
788                <R as Default>::default().as_str()
789            )));
790        }
791
792        get_key_from_active_model(&rel_def.from_col, self)
793    }
794
795    #[doc(hidden)]
796    /// Get the key value of belongs to relation
797    fn get_parent_key_for(
798        &self,
799        rel: <Self::Entity as EntityTrait>::Relation,
800    ) -> Result<ValueTuple, DbErr> {
801        let rel_def = rel.def();
802
803        if rel_def.is_owner {
804            return Err(DbErr::Type(format!("Relation {rel:?} is not belongs_to")));
805        }
806
807        get_key_from_active_model(&rel_def.from_col, self)
808    }
809
810    #[doc(hidden)]
811    fn find_belongs_to_self(
812        &self,
813        rel: <Self::Entity as EntityTrait>::Relation,
814        db_backend: DbBackend,
815    ) -> Result<crate::query::Select<Self::Entity>, DbErr> {
816        let rel_def = rel.def();
817
818        if !rel_def.is_owner {
819            return Err(DbErr::Type(format!(
820                "Relation {rel:?} is not has_one / has_many"
821            )));
822        }
823
824        let id = get_key_from_active_model(&rel_def.from_col, self)?;
825
826        Ok(Self::Entity::find().filter(
827            column_tuple_in_condition(
828                &<Self::Entity as Default>::default().table_ref(),
829                &rel_def.to_col,
830                &[id],
831                db_backend,
832            )
833            .expect(""),
834        ))
835    }
836
837    #[doc(hidden)]
838    fn find_belongs_to_model<AM>(
839        rel_def: &RelationDef,
840        belongs_to: &AM,
841        db_backend: DbBackend,
842    ) -> Result<crate::query::Select<Self::Entity>, DbErr>
843    where
844        AM: ActiveModelTrait,
845    {
846        if rel_def.is_owner {
847            return Err(DbErr::Type(format!(
848                "Relation {rel_def:?} is not belongs_to"
849            )));
850        }
851
852        let id = get_key_from_active_model(&rel_def.to_col, belongs_to)?;
853        Ok(<Self::Entity as EntityTrait>::find().filter(
854            column_tuple_in_condition(&rel_def.from_tbl, &rel_def.from_col, &[id], db_backend)
855                .expect(""),
856        ))
857    }
858
859    /// Find related Models belonging to self
860    fn find_related<R>(&self, _: R) -> crate::query::Select<R>
861    where
862        R: EntityTrait,
863        Self::Entity: Related<R>,
864    {
865        Self::Entity::find_related().belongs_to_active_model(self)
866    }
867
868    /// Like find_related, but infer type from `AM`
869    #[doc(hidden)]
870    fn find_related_of<AM>(&self, _: &[AM]) -> crate::query::Select<AM::Entity>
871    where
872        AM: ActiveModelTrait,
873        Self::Entity: Related<AM::Entity>,
874    {
875        self.find_related(AM::Entity::default())
876    }
877
878    /// Establish links between self and a related Entity for a many-to-many relation.
879    /// New associations will be added, and leftovers can be optionally deleted.
880    #[doc(hidden)]
881    fn establish_links<J, R, RM, C>(
882        &self,
883        _: J,
884        related_models: &[RM],
885        delete_leftover: bool,
886        db: &C,
887    ) -> Result<(), DbErr>
888    where
889        R: EntityTrait,
890        RM: ActiveModelTrait<Entity = R>,
891        J: EntityTrait + Related<R> + Related<Self::Entity>,
892        J::Model: IntoActiveModel<J::ActiveModel>,
893        J::ActiveModel: ActiveModelBehavior,
894        C: ConnectionTrait,
895    {
896        let left = <J as Related<Self::Entity>>::to();
897        let right = <J as Related<R>>::to();
898
899        establish_links::<_, J, _, C>(self, related_models, left, right, delete_leftover, db)
900    }
901
902    /// Establish links for self-referencing many-to-many relation
903    #[doc(hidden)]
904    fn establish_links_self<J, RM, C>(
905        &self,
906        _: J,
907        related_models: &[RM],
908        delete_leftover: bool,
909        db: &C,
910    ) -> Result<(), DbErr>
911    where
912        RM: ActiveModelTrait<Entity = Self::Entity>,
913        J: EntityTrait,
914        J::Model: IntoActiveModel<J::ActiveModel>,
915        J::ActiveModel: ActiveModelBehavior,
916        C: ConnectionTrait,
917        Self::Entity: RelatedSelfVia<J>,
918    {
919        let left = <Self::Entity as RelatedSelfVia<J>>::via().rev();
920        let right = <Self::Entity as RelatedSelfVia<J>>::to();
921
922        establish_links::<_, J, _, C>(self, related_models, left, right, delete_leftover, db)
923    }
924
925    /// Establish links for self-referencing many-to-many relation, but left-right reversed
926    #[doc(hidden)]
927    fn establish_links_self_rev<J, RM, C>(
928        &self,
929        _: J,
930        related_models: &[RM],
931        delete_leftover: bool,
932        db: &C,
933    ) -> Result<(), DbErr>
934    where
935        RM: ActiveModelTrait<Entity = Self::Entity>,
936        J: EntityTrait,
937        J::Model: IntoActiveModel<J::ActiveModel>,
938        J::ActiveModel: ActiveModelBehavior,
939        C: ConnectionTrait,
940        Self::Entity: RelatedSelfVia<J>,
941    {
942        let left = <Self::Entity as RelatedSelfVia<J>>::to();
943        let right = <Self::Entity as RelatedSelfVia<J>>::via().rev();
944
945        establish_links::<_, J, _, C>(self, related_models, left, right, delete_leftover, db)
946    }
947
948    /// Inverse of establish link, break links between two many-to-many models
949    #[doc(hidden)]
950    fn delete_links<J, C>(&self, _: J, db: &C) -> Result<DeleteResult, DbErr>
951    where
952        J: EntityTrait + Related<Self::Entity>,
953        C: ConnectionTrait,
954    {
955        let rel_def = <J as Related<Self::Entity>>::to();
956        let id = get_key_from_active_model(&rel_def.to_col, self)?;
957
958        J::delete_many()
959            .filter(
960                column_tuple_in_condition(
961                    &rel_def.from_tbl,
962                    &rel_def.from_col,
963                    &[id],
964                    db.get_database_backend(),
965                )
966                .expect(""),
967            )
968            .exec(db)
969    }
970
971    /// Like `delete_links` but for self-referencing relations
972    #[doc(hidden)]
973    fn delete_links_self<J, C>(&self, _: J, db: &C) -> Result<DeleteResult, DbErr>
974    where
975        J: EntityTrait,
976        C: ConnectionTrait,
977        Self::Entity: RelatedSelfVia<J>,
978    {
979        let left = <Self::Entity as RelatedSelfVia<J>>::via().rev();
980        let right = <Self::Entity as RelatedSelfVia<J>>::to();
981
982        let id = get_key_from_active_model(&left.to_col, self)?;
983
984        if left.to_col != right.to_col {
985            return Err(DbErr::Type("Expect Self Referencing Relation".into()));
986        }
987
988        J::delete_many()
989            .filter(
990                Condition::any()
991                    .add(
992                        column_tuple_in_condition(
993                            &left.from_tbl,
994                            &left.from_col,
995                            std::slice::from_ref(&id),
996                            db.get_database_backend(),
997                        )
998                        .expect(""),
999                    )
1000                    .add(
1001                        column_tuple_in_condition(
1002                            &right.from_tbl,
1003                            &right.from_col,
1004                            std::slice::from_ref(&id),
1005                            db.get_database_backend(),
1006                        )
1007                        .expect(""),
1008                    ),
1009            )
1010            .exec(db)
1011    }
1012}
1013
1014/// A Trait for overriding the ActiveModel behavior
1015///
1016/// ### Example
1017/// ```ignore
1018/// use sea_orm::entity::prelude::*;
1019///
1020///  // Use [DeriveEntity] to derive the EntityTrait automatically
1021/// #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
1022/// pub struct Entity;
1023///
1024/// /// The [EntityName] describes the name of a table
1025/// impl EntityName for Entity {
1026///     fn table_name(&self) -> &'static str {
1027///         "cake"
1028///     }
1029/// }
1030///
1031/// // Derive the ActiveModel
1032/// #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
1033/// pub struct Model {
1034///     pub id: i32,
1035///     pub name: String,
1036/// }
1037///
1038/// impl ActiveModelBehavior for ActiveModel {}
1039/// ```
1040/// See module level docs [crate::entity] for a full example
1041#[allow(unused_variables)]
1042pub trait ActiveModelBehavior: ActiveModelTrait {
1043    /// Create a new ActiveModel with default values. This is also called by `Default::default()`.
1044    ///
1045    /// You can override it like the following:
1046    ///
1047    /// ```ignore
1048    /// fn new() -> Self {
1049    ///     Self {
1050    ///         status: Set(Status::New),
1051    ///         ..ActiveModelTrait::default()
1052    ///     }
1053    /// }
1054    /// ```
1055    fn new() -> Self {
1056        <Self as ActiveModelTrait>::default()
1057    }
1058
1059    /// Will be called before `ActiveModel::insert`, `ActiveModel::update`, and `ActiveModel::save`
1060    fn before_save<C>(self, db: &C, insert: bool) -> Result<Self, DbErr>
1061    where
1062        C: ConnectionTrait,
1063    {
1064        Ok(self)
1065    }
1066
1067    /// Will be called after `ActiveModel::insert`, `ActiveModel::update`, and `ActiveModel::save`
1068    fn after_save<C>(
1069        model: <Self::Entity as EntityTrait>::Model,
1070        db: &C,
1071        insert: bool,
1072    ) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
1073    where
1074        C: ConnectionTrait,
1075    {
1076        Ok(model)
1077    }
1078
1079    /// Will be called before `ActiveModel::delete`
1080    fn before_delete<C>(self, db: &C) -> Result<Self, DbErr>
1081    where
1082        C: ConnectionTrait,
1083    {
1084        Ok(self)
1085    }
1086
1087    /// Will be called after `ActiveModel::delete`
1088    fn after_delete<C>(self, db: &C) -> Result<Self, DbErr>
1089    where
1090        C: ConnectionTrait,
1091    {
1092        Ok(self)
1093    }
1094}
1095
1096/// A Trait for any type that can be converted into an ActiveModel
1097pub trait IntoActiveModel<A>
1098where
1099    A: ActiveModelTrait,
1100{
1101    /// Method to call to perform the conversion
1102    fn into_active_model(self) -> A;
1103}
1104
1105impl<A> IntoActiveModel<A> for A
1106where
1107    A: ActiveModelTrait,
1108{
1109    fn into_active_model(self) -> A {
1110        self
1111    }
1112}
1113
1114fn establish_links<EM, J, RM, C>(
1115    model: &EM,
1116    related_models: &[RM],
1117    left: RelationDef,
1118    right: RelationDef,
1119    delete_leftover: bool,
1120    db: &C,
1121) -> Result<(), DbErr>
1122where
1123    EM: ActiveModelTrait,
1124    RM: ActiveModelTrait,
1125    J: EntityTrait,
1126    J::Model: IntoActiveModel<J::ActiveModel>,
1127    J::ActiveModel: ActiveModelBehavior,
1128    C: ConnectionTrait,
1129{
1130    let mut require_leftover = true;
1131
1132    if related_models.is_empty() {
1133        // if there are no related models, then there is no risk of insert conflict
1134        require_leftover = false;
1135    }
1136
1137    let primary_key = J::primary_key_identity();
1138    if require_leftover
1139        && primary_key.fully_contains(&left.from_col)
1140        && primary_key.fully_contains(&right.from_col)
1141    {
1142        // if the primary key is a composite key of the two relations
1143        // we can use on conflict no action safely
1144        require_leftover = false;
1145    }
1146
1147    let mut leftover = Vec::new();
1148    if delete_leftover || require_leftover {
1149        for item in <J::ActiveModel as ActiveModelTrait>::find_belongs_to_model(
1150            &left,
1151            model,
1152            db.get_database_backend(),
1153        )?
1154        .all(db)?
1155        {
1156            let item = item.into_active_model();
1157            let key = get_key_from_active_model(&right.from_col, &item)?;
1158            leftover.push((item, key));
1159        }
1160    }
1161    let leftover = leftover; // un-mut
1162
1163    let mut via_models = Vec::new();
1164    let mut all_keys = std::collections::HashSet::new();
1165
1166    for related_model in related_models {
1167        let mut via: J::ActiveModel = ActiveModelBehavior::new();
1168        via.set_parent_key_for_def(model, &left)?;
1169        via.set_parent_key_for_def(related_model, &right)?;
1170        let via_key = get_key_from_active_model(&right.from_col, &via)?;
1171        if !leftover.iter().any(|t| t.1 == via_key) {
1172            // if not already exist, save for insert
1173            via_models.push(via);
1174        }
1175        if delete_leftover {
1176            all_keys.insert(via_key);
1177        }
1178    }
1179
1180    if delete_leftover {
1181        let mut to_delete = Vec::new();
1182        for (leftover, key) in leftover {
1183            if !all_keys.contains(&key) {
1184                to_delete.push(
1185                    leftover
1186                        .get_primary_key_value()
1187                        .expect("item is a full model"),
1188                );
1189            }
1190        }
1191        if !to_delete.is_empty() {
1192            J::delete_many()
1193                .filter_by_value_tuples(&to_delete, db.get_database_backend())
1194                .exec(db)?;
1195        }
1196    }
1197
1198    if !via_models.is_empty() {
1199        // insert new junctions
1200        J::insert_many(via_models)
1201            .on_conflict_do_nothing()
1202            .exec(db)?;
1203    }
1204
1205    Ok(())
1206}
1207
1208#[cfg(test)]
1209mod tests {
1210    use crate::{DbErr, entity::*, tests_cfg::*};
1211    use pretty_assertions::assert_eq;
1212
1213    #[cfg(feature = "with-json")]
1214    use serde_json::json;
1215
1216    #[test]
1217    #[cfg(feature = "macros")]
1218    fn test_derive_into_active_model_1() {
1219        mod my_fruit {
1220            pub use super::fruit::*;
1221            use crate as sea_orm;
1222            use crate::entity::prelude::*;
1223
1224            #[derive(DeriveIntoActiveModel)]
1225            pub struct NewFruit {
1226                // id is omitted
1227                pub name: String,
1228                // it is required as opposed to optional in Model
1229                pub cake_id: i32,
1230            }
1231        }
1232
1233        assert_eq!(
1234            my_fruit::NewFruit {
1235                name: "Apple".to_owned(),
1236                cake_id: 1,
1237            }
1238            .into_active_model(),
1239            fruit::ActiveModel {
1240                id: NotSet,
1241                name: Set("Apple".to_owned()),
1242                cake_id: Set(Some(1)),
1243            }
1244        );
1245    }
1246
1247    #[test]
1248    #[cfg(feature = "macros")]
1249    fn test_derive_into_active_model_2() {
1250        use crate as sea_orm;
1251        use crate::entity::prelude::*;
1252
1253        #[derive(DeriveIntoActiveModel)]
1254        #[sea_orm(active_model = "fruit::ActiveModel")]
1255        struct RequiredFruitName {
1256            name: String,
1257        }
1258
1259        assert_eq!(
1260            RequiredFruitName {
1261                name: "Apple Pie".to_owned(),
1262            }
1263            .into_active_model(),
1264            fruit::ActiveModel {
1265                id: NotSet,
1266                name: Set("Apple Pie".to_owned()),
1267                cake_id: NotSet,
1268            }
1269        );
1270
1271        #[derive(DeriveIntoActiveModel)]
1272        #[sea_orm(active_model = "fruit::ActiveModel")]
1273        struct OptionalFruitName {
1274            name: Option<String>,
1275        }
1276
1277        assert_eq!(
1278            OptionalFruitName {
1279                name: Some("Apple Pie".to_owned()),
1280            }
1281            .into_active_model(),
1282            fruit::ActiveModel {
1283                id: NotSet,
1284                name: Set("Apple Pie".to_owned()),
1285                cake_id: NotSet,
1286            }
1287        );
1288
1289        assert_eq!(
1290            OptionalFruitName { name: None }.into_active_model(),
1291            fruit::ActiveModel {
1292                id: NotSet,
1293                name: NotSet,
1294                cake_id: NotSet,
1295            }
1296        );
1297
1298        #[derive(DeriveIntoActiveModel)]
1299        #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
1300        struct RequiredAndNotNullFruitCake {
1301            cake_id: i32,
1302        }
1303
1304        assert_eq!(
1305            RequiredAndNotNullFruitCake { cake_id: 1 }.into_active_model(),
1306            fruit::ActiveModel {
1307                id: NotSet,
1308                name: NotSet,
1309                cake_id: Set(Some(1)),
1310            }
1311        );
1312
1313        #[derive(DeriveIntoActiveModel)]
1314        #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
1315        struct OptionalAndNotNullFruitCake {
1316            cake_id: Option<i32>,
1317        }
1318
1319        assert_eq!(
1320            OptionalAndNotNullFruitCake { cake_id: Some(1) }.into_active_model(),
1321            fruit::ActiveModel {
1322                id: NotSet,
1323                name: NotSet,
1324                cake_id: Set(Some(1)),
1325            }
1326        );
1327
1328        assert_eq!(
1329            OptionalAndNotNullFruitCake { cake_id: None }.into_active_model(),
1330            fruit::ActiveModel {
1331                id: NotSet,
1332                name: NotSet,
1333                cake_id: NotSet,
1334            }
1335        );
1336
1337        #[derive(DeriveIntoActiveModel)]
1338        #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
1339        struct OptionalAndNullableFruitCake {
1340            cake_id: Option<Option<i32>>,
1341        }
1342
1343        assert_eq!(
1344            OptionalAndNullableFruitCake {
1345                cake_id: Some(Some(1)),
1346            }
1347            .into_active_model(),
1348            fruit::ActiveModel {
1349                id: NotSet,
1350                name: NotSet,
1351                cake_id: Set(Some(1)),
1352            }
1353        );
1354
1355        assert_eq!(
1356            OptionalAndNullableFruitCake {
1357                cake_id: Some(None),
1358            }
1359            .into_active_model(),
1360            fruit::ActiveModel {
1361                id: NotSet,
1362                name: NotSet,
1363                cake_id: Set(None),
1364            }
1365        );
1366
1367        assert_eq!(
1368            OptionalAndNullableFruitCake { cake_id: None }.into_active_model(),
1369            fruit::ActiveModel {
1370                id: NotSet,
1371                name: NotSet,
1372                cake_id: NotSet,
1373            }
1374        );
1375    }
1376
1377    #[test]
1378    #[cfg(feature = "macros")]
1379    fn test_derive_try_into_model_1() {
1380        mod my_fruit {
1381            use crate as sea_orm;
1382            use crate::entity::prelude::*;
1383
1384            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1385            #[sea_orm(table_name = "fruit")]
1386            pub struct Model {
1387                #[sea_orm(primary_key)]
1388                pub id: i32,
1389                pub name: String,
1390                pub cake_id: Option<i32>,
1391            }
1392
1393            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1394            pub enum Relation {}
1395
1396            impl ActiveModelBehavior for ActiveModel {}
1397        }
1398        assert_eq!(
1399            my_fruit::ActiveModel {
1400                id: Set(1),
1401                name: Set("Pineapple".to_owned()),
1402                cake_id: Set(None),
1403            }
1404            .try_into_model()
1405            .unwrap(),
1406            my_fruit::Model {
1407                id: 1,
1408                name: "Pineapple".to_owned(),
1409                cake_id: None,
1410            }
1411        );
1412
1413        assert_eq!(
1414            my_fruit::ActiveModel {
1415                id: Set(2),
1416                name: Set("Apple".to_owned()),
1417                cake_id: Set(Some(1)),
1418            }
1419            .try_into_model()
1420            .unwrap(),
1421            my_fruit::Model {
1422                id: 2,
1423                name: "Apple".to_owned(),
1424                cake_id: Some(1),
1425            }
1426        );
1427
1428        assert_eq!(
1429            my_fruit::ActiveModel {
1430                id: Set(1),
1431                name: NotSet,
1432                cake_id: Set(None),
1433            }
1434            .try_into_model(),
1435            Err(DbErr::AttrNotSet(String::from("name")))
1436        );
1437
1438        assert_eq!(
1439            my_fruit::ActiveModel {
1440                id: Set(1),
1441                name: Set("Pineapple".to_owned()),
1442                cake_id: NotSet,
1443            }
1444            .try_into_model(),
1445            Err(DbErr::AttrNotSet(String::from("cake_id")))
1446        );
1447    }
1448
1449    #[test]
1450    #[cfg(feature = "macros")]
1451    fn test_derive_try_into_model_2() {
1452        mod my_fruit {
1453            use crate as sea_orm;
1454            use crate::entity::prelude::*;
1455
1456            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1457            #[sea_orm(table_name = "fruit")]
1458            pub struct Model {
1459                #[sea_orm(primary_key)]
1460                pub id: i32,
1461                pub name: String,
1462                #[sea_orm(ignore)]
1463                pub cake_id: Option<i32>,
1464            }
1465
1466            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1467            pub enum Relation {}
1468
1469            impl ActiveModelBehavior for ActiveModel {}
1470        }
1471        assert_eq!(
1472            my_fruit::ActiveModel {
1473                id: Set(1),
1474                name: Set("Pineapple".to_owned()),
1475            }
1476            .try_into_model()
1477            .unwrap(),
1478            my_fruit::Model {
1479                id: 1,
1480                name: "Pineapple".to_owned(),
1481                cake_id: None,
1482            }
1483        );
1484    }
1485
1486    #[test]
1487    #[cfg(feature = "macros")]
1488    fn test_derive_try_into_model_3() {
1489        mod my_fruit {
1490            use crate as sea_orm;
1491            use crate::entity::prelude::*;
1492
1493            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1494            #[sea_orm(table_name = "fruit")]
1495            pub struct Model {
1496                #[sea_orm(primary_key)]
1497                pub id: i32,
1498                #[sea_orm(ignore)]
1499                pub name: String,
1500                pub cake_id: Option<i32>,
1501            }
1502
1503            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1504            pub enum Relation {}
1505
1506            impl ActiveModelBehavior for ActiveModel {}
1507        }
1508        assert_eq!(
1509            my_fruit::ActiveModel {
1510                id: Set(1),
1511                cake_id: Set(Some(1)),
1512            }
1513            .try_into_model()
1514            .unwrap(),
1515            my_fruit::Model {
1516                id: 1,
1517                name: "".to_owned(),
1518                cake_id: Some(1),
1519            }
1520        );
1521    }
1522
1523    #[test]
1524    #[cfg(feature = "with-json")]
1525    fn test_active_model_set_from_json_1() {
1526        assert_eq!(
1527            cake::ActiveModel::from_json(json!({
1528                "id": 1,
1529                "name": "Apple Pie",
1530            }))
1531            .unwrap(),
1532            cake::ActiveModel {
1533                id: Set(1),
1534                name: Set("Apple Pie".to_owned()),
1535            }
1536        );
1537
1538        assert_eq!(
1539            cake::ActiveModel::from_json(json!({
1540                "id": 1,
1541            }))
1542            .unwrap(),
1543            cake::ActiveModel {
1544                id: Set(1),
1545                name: NotSet,
1546            }
1547        );
1548
1549        assert_eq!(
1550            cake::ActiveModel::from_json(json!({
1551                "name": "Apple Pie",
1552            }))
1553            .unwrap(),
1554            cake::ActiveModel {
1555                id: NotSet,
1556                name: Set("Apple Pie".to_owned()),
1557            }
1558        );
1559
1560        let mut cake: cake::ActiveModel = Default::default();
1561        cake.set_from_json(json!({
1562            "name": "Apple Pie",
1563        }))
1564        .unwrap();
1565        assert_eq!(
1566            cake,
1567            cake::ActiveModel {
1568                id: NotSet,
1569                name: Set("Apple Pie".to_owned()),
1570            }
1571        );
1572    }
1573
1574    #[test]
1575    #[cfg(feature = "with-json")]
1576    fn test_active_model_set_from_json_2() -> Result<(), DbErr> {
1577        let mut fruit: fruit::ActiveModel = Default::default();
1578
1579        fruit.set_from_json(json!({
1580            "name": "Apple",
1581        }))?;
1582        assert_eq!(
1583            fruit,
1584            fruit::ActiveModel {
1585                id: ActiveValue::NotSet,
1586                name: ActiveValue::Set("Apple".to_owned()),
1587                cake_id: ActiveValue::NotSet,
1588            }
1589        );
1590
1591        assert_eq!(
1592            fruit::ActiveModel::from_json(json!({
1593                "name": "Apple",
1594            }))?,
1595            fruit::ActiveModel {
1596                id: ActiveValue::NotSet,
1597                name: ActiveValue::Set("Apple".to_owned()),
1598                cake_id: ActiveValue::NotSet,
1599            }
1600        );
1601
1602        fruit.set_from_json(json!({
1603            "name": "Apple",
1604            "cake_id": null,
1605        }))?;
1606        assert_eq!(
1607            fruit,
1608            fruit::ActiveModel {
1609                id: ActiveValue::NotSet,
1610                name: ActiveValue::Set("Apple".to_owned()),
1611                cake_id: ActiveValue::Set(None),
1612            }
1613        );
1614
1615        fruit.set_from_json(json!({
1616            "id": null,
1617            "name": "Apple",
1618            "cake_id": 1,
1619        }))?;
1620        assert_eq!(
1621            fruit,
1622            fruit::ActiveModel {
1623                id: ActiveValue::NotSet,
1624                name: ActiveValue::Set("Apple".to_owned()),
1625                cake_id: ActiveValue::Set(Some(1)),
1626            }
1627        );
1628
1629        fruit.set_from_json(json!({
1630            "id": 2,
1631            "name": "Apple",
1632            "cake_id": 1,
1633        }))?;
1634        assert_eq!(
1635            fruit,
1636            fruit::ActiveModel {
1637                id: ActiveValue::NotSet,
1638                name: ActiveValue::Set("Apple".to_owned()),
1639                cake_id: ActiveValue::Set(Some(1)),
1640            }
1641        );
1642
1643        let mut fruit = fruit::ActiveModel {
1644            id: ActiveValue::Set(1),
1645            name: ActiveValue::NotSet,
1646            cake_id: ActiveValue::NotSet,
1647        };
1648        fruit.set_from_json(json!({
1649            "id": 8,
1650            "name": "Apple",
1651            "cake_id": 1,
1652        }))?;
1653        assert_eq!(
1654            fruit,
1655            fruit::ActiveModel {
1656                id: ActiveValue::Set(1),
1657                name: ActiveValue::Set("Apple".to_owned()),
1658                cake_id: ActiveValue::Set(Some(1)),
1659            }
1660        );
1661
1662        Ok(())
1663    }
1664
1665    #[test]
1666    #[cfg(feature = "with-json")]
1667    fn test_active_model_set_from_json_3() -> Result<(), DbErr> {
1668        use crate::*;
1669
1670        let db = MockDatabase::new(DbBackend::Postgres)
1671            .append_exec_results([
1672                MockExecResult {
1673                    last_insert_id: 1,
1674                    rows_affected: 1,
1675                },
1676                MockExecResult {
1677                    last_insert_id: 1,
1678                    rows_affected: 1,
1679                },
1680            ])
1681            .append_query_results([
1682                [fruit::Model {
1683                    id: 1,
1684                    name: "Apple".to_owned(),
1685                    cake_id: None,
1686                }],
1687                [fruit::Model {
1688                    id: 2,
1689                    name: "Orange".to_owned(),
1690                    cake_id: Some(1),
1691                }],
1692            ])
1693            .into_connection();
1694
1695        let mut fruit: fruit::ActiveModel = Default::default();
1696        fruit.set_from_json(json!({
1697            "name": "Apple",
1698        }))?;
1699        fruit.save(&db)?;
1700
1701        let mut fruit = fruit::ActiveModel {
1702            id: Set(2),
1703            ..Default::default()
1704        };
1705        fruit.set_from_json(json!({
1706            "id": 9,
1707            "name": "Orange",
1708            "cake_id": 1,
1709        }))?;
1710        fruit.save(&db)?;
1711
1712        assert_eq!(
1713            db.into_transaction_log(),
1714            [
1715                Transaction::from_sql_and_values(
1716                    DbBackend::Postgres,
1717                    r#"INSERT INTO "fruit" ("name") VALUES ($1) RETURNING "id", "name", "cake_id""#,
1718                    ["Apple".into()],
1719                ),
1720                Transaction::from_sql_and_values(
1721                    DbBackend::Postgres,
1722                    r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
1723                    ["Orange".into(), 1i32.into(), 2i32.into()],
1724                ),
1725            ]
1726        );
1727
1728        Ok(())
1729    }
1730
1731    #[test]
1732    fn test_active_model_is_changed() {
1733        let mut fruit: fruit::ActiveModel = Default::default();
1734        assert!(!fruit.is_changed());
1735
1736        fruit.set(fruit::Column::Name, "apple".into());
1737        assert!(fruit.is_changed());
1738
1739        let mut fruit = fruit::Model {
1740            id: 1,
1741            name: "".into(),
1742            cake_id: None,
1743        };
1744        fruit.set("name".parse().unwrap(), "orange".into());
1745        assert_eq!(fruit.name, "orange");
1746    }
1747
1748    #[test]
1749    fn test_reset_1() {
1750        assert_eq!(
1751            fruit::Model {
1752                id: 1,
1753                name: "Apple".into(),
1754                cake_id: None,
1755            }
1756            .into_active_model(),
1757            fruit::ActiveModel {
1758                id: Unchanged(1),
1759                name: Unchanged("Apple".into()),
1760                cake_id: Unchanged(None)
1761            },
1762        );
1763
1764        assert_eq!(
1765            fruit::Model {
1766                id: 1,
1767                name: "Apple".into(),
1768                cake_id: None,
1769            }
1770            .into_active_model()
1771            .reset_all(),
1772            fruit::ActiveModel {
1773                id: Set(1),
1774                name: Set("Apple".into()),
1775                cake_id: Set(None)
1776            },
1777        );
1778
1779        assert_eq!(
1780            fruit::Model {
1781                id: 1,
1782                name: "Apple".into(),
1783                cake_id: Some(2),
1784            }
1785            .into_active_model(),
1786            fruit::ActiveModel {
1787                id: Unchanged(1),
1788                name: Unchanged("Apple".into()),
1789                cake_id: Unchanged(Some(2)),
1790            },
1791        );
1792
1793        assert_eq!(
1794            fruit::Model {
1795                id: 1,
1796                name: "Apple".into(),
1797                cake_id: Some(2),
1798            }
1799            .into_active_model()
1800            .reset_all(),
1801            fruit::ActiveModel {
1802                id: Set(1),
1803                name: Set("Apple".into()),
1804                cake_id: Set(Some(2)),
1805            },
1806        );
1807    }
1808
1809    #[test]
1810    fn test_reset_2() -> Result<(), DbErr> {
1811        use crate::*;
1812
1813        let db = MockDatabase::new(DbBackend::Postgres)
1814            .append_exec_results(vec![
1815                MockExecResult {
1816                    last_insert_id: 1,
1817                    rows_affected: 1,
1818                },
1819                MockExecResult {
1820                    last_insert_id: 1,
1821                    rows_affected: 1,
1822                },
1823            ])
1824            .append_query_results(vec![
1825                vec![fruit::Model {
1826                    id: 1,
1827                    name: "Apple".to_owned(),
1828                    cake_id: None,
1829                }],
1830                vec![fruit::Model {
1831                    id: 1,
1832                    name: "Apple".to_owned(),
1833                    cake_id: None,
1834                }],
1835            ])
1836            .into_connection();
1837
1838        fruit::Model {
1839            id: 1,
1840            name: "Apple".into(),
1841            cake_id: None,
1842        }
1843        .into_active_model()
1844        .update(&db)?;
1845
1846        fruit::Model {
1847            id: 1,
1848            name: "Apple".into(),
1849            cake_id: None,
1850        }
1851        .into_active_model()
1852        .reset_all()
1853        .update(&db)?;
1854
1855        assert_eq!(
1856            db.into_transaction_log(),
1857            vec![
1858                Transaction::from_sql_and_values(
1859                    DbBackend::Postgres,
1860                    r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit" WHERE "fruit"."id" = $1 LIMIT $2"#,
1861                    vec![1i32.into(), 1u64.into()],
1862                ),
1863                Transaction::from_sql_and_values(
1864                    DbBackend::Postgres,
1865                    r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
1866                    vec!["Apple".into(), Option::<i32>::None.into(), 1i32.into()],
1867                ),
1868            ]
1869        );
1870
1871        Ok(())
1872    }
1873
1874    #[test]
1875    fn test_active_model_default_values() {
1876        assert_eq!(
1877            fruit::ActiveModel::default_values(),
1878            fruit::ActiveModel {
1879                id: Set(0),
1880                name: Set("".into()),
1881                cake_id: Set(None),
1882            },
1883        );
1884
1885        assert_eq!(
1886            lunch_set::ActiveModel::default_values(),
1887            lunch_set::ActiveModel {
1888                id: Set(0),
1889                name: Set("".into()),
1890                tea: NotSet,
1891            },
1892        );
1893    }
1894
1895    #[test]
1896    fn test_active_model_set_parent_key() {
1897        let mut fruit = fruit::Model {
1898            id: 2,
1899            name: "F".into(),
1900            cake_id: None,
1901        }
1902        .into_active_model();
1903
1904        let cake = cake::Model {
1905            id: 4,
1906            name: "C".into(),
1907        }
1908        .into_active_model();
1909
1910        fruit.set_parent_key(&cake).unwrap();
1911
1912        assert_eq!(
1913            fruit,
1914            fruit::ActiveModel {
1915                id: Unchanged(2),
1916                name: Unchanged("F".into()),
1917                cake_id: Set(Some(4)),
1918            }
1919        );
1920
1921        assert!(fruit.clear_parent_key::<cake::Entity>().unwrap());
1922
1923        assert_eq!(
1924            fruit,
1925            fruit::ActiveModel {
1926                id: Unchanged(2),
1927                name: Unchanged("F".into()),
1928                cake_id: Set(None),
1929            }
1930        );
1931
1932        let mut cake_filling = cake_filling::ActiveModel::new();
1933
1934        cake_filling.set_parent_key(&cake).unwrap();
1935
1936        assert_eq!(
1937            cake_filling,
1938            cake_filling::ActiveModel {
1939                cake_id: Set(4),
1940                filling_id: NotSet,
1941            }
1942        );
1943    }
1944}