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#[async_trait::async_trait]
27pub trait ActiveModelTrait: Clone + Debug {
28 type Entity: EntityTrait;
30
31 fn take(&mut self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
33
34 fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
36
37 fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) {
39 self.try_set(c, v)
40 .unwrap_or_else(|e| panic!("Failed to set value for {:?}: {e:?}", c.as_column_ref()))
41 }
42
43 fn set_if_not_equals(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
45
46 fn try_set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) -> Result<(), DbErr>;
48
49 fn not_set(&mut self, c: <Self::Entity as EntityTrait>::Column);
51
52 fn is_not_set(&self, c: <Self::Entity as EntityTrait>::Column) -> bool;
54
55 fn default() -> Self;
57
58 fn default_values() -> Self;
60
61 fn reset(&mut self, c: <Self::Entity as EntityTrait>::Column);
64
65 fn reset_all(mut self) -> Self {
68 for col in <Self::Entity as EntityTrait>::Column::iter() {
69 self.reset(col);
70 }
71 self
72 }
73
74 fn get_primary_key_value(&self) -> Option<ValueTuple> {
76 let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
77 macro_rules! next {
78 () => {
79 self.get(cols.next()?.into_column()).into_value()?
80 };
81 }
82 match <<<Self::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType as PrimaryKeyArity>::ARITY {
83 1 => {
84 let s1 = next!();
85 Some(ValueTuple::One(s1))
86 }
87 2 => {
88 let s1 = next!();
89 let s2 = next!();
90 Some(ValueTuple::Two(s1, s2))
91 }
92 3 => {
93 let s1 = next!();
94 let s2 = next!();
95 let s3 = next!();
96 Some(ValueTuple::Three(s1, s2, s3))
97 }
98 len => {
99 let mut vec = Vec::with_capacity(len);
100 for _ in 0..len {
101 let s = next!();
102 vec.push(s);
103 }
104 Some(ValueTuple::Many(vec))
105 }
106 }
107 }
108
109 async fn insert<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
216 where
217 <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
218 Self: ActiveModelBehavior,
219 C: ConnectionTrait,
220 {
221 let am = ActiveModelBehavior::before_save(self, db, true).await?;
222 let model = <Self::Entity as EntityTrait>::insert(am)
223 .exec_with_returning(db)
224 .await?;
225 Self::after_save(model, db, true).await
226 }
227
228 async fn update<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
338 where
339 <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
340 Self: ActiveModelBehavior,
341 C: ConnectionTrait,
342 {
343 let am = ActiveModelBehavior::before_save(self, db, false).await?;
344 let model: <Self::Entity as EntityTrait>::Model = Self::Entity::update(am).exec(db).await?;
345 Self::after_save(model, db, false).await
346 }
347
348 async fn save<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
351 where
352 <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
353 Self: ActiveModelBehavior,
354 C: ConnectionTrait,
355 {
356 let res = if !self.is_update() {
357 self.insert(db).await
358 } else {
359 self.update(db).await
360 }?;
361 Ok(res.into_active_model())
362 }
363
364 #[doc(hidden)]
366 fn is_update(&self) -> bool {
367 let mut is_update = true;
368 for key in <Self::Entity as EntityTrait>::PrimaryKey::iter() {
369 let col = key.into_column();
370 if self.is_not_set(col) {
371 is_update = false;
372 break;
373 }
374 }
375 is_update
376 }
377
378 async fn delete<'a, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
422 where
423 Self: ActiveModelBehavior,
424 C: ConnectionTrait,
425 {
426 let am = ActiveModelBehavior::before_delete(self, db).await?;
427 let am_clone = am.clone();
428 let delete_res = Self::Entity::delete(am).exec(db).await?;
429 ActiveModelBehavior::after_delete(am_clone, db).await?;
430 Ok(delete_res)
431 }
432
433 #[cfg(feature = "with-json")]
437 fn set_from_json(&mut self, json: serde_json::Value) -> Result<(), DbErr>
438 where
439 Self: crate::TryIntoModel<<Self::Entity as EntityTrait>::Model>,
440 <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
441 for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
442 serde::de::Deserialize<'de> + serde::Serialize,
443 {
444 use crate::Iterable;
445
446 let primary_key_values: Vec<(<Self::Entity as EntityTrait>::Column, ActiveValue<Value>)> =
448 <<Self::Entity as EntityTrait>::PrimaryKey>::iter()
449 .map(|pk| (pk.into_column(), self.take(pk.into_column())))
450 .collect();
451
452 *self = Self::from_json(json)?;
454
455 for (col, active_value) in primary_key_values {
457 match active_value {
458 ActiveValue::Unchanged(v) | ActiveValue::Set(v) => self.set(col, v),
459 NotSet => self.not_set(col),
460 }
461 }
462
463 Ok(())
464 }
465
466 #[cfg(feature = "with-json")]
468 fn from_json(mut json: serde_json::Value) -> Result<Self, DbErr>
469 where
470 Self: crate::TryIntoModel<<Self::Entity as EntityTrait>::Model>,
471 <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
472 for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
473 serde::de::Deserialize<'de> + serde::Serialize,
474 {
475 use crate::{IdenStatic, Iterable};
476
477 let serde_json::Value::Object(obj) = &json else {
478 return Err(DbErr::Json(format!(
479 "invalid type: expected JSON object for {}",
480 <<Self as ActiveModelTrait>::Entity as IdenStatic>::as_str(&Default::default())
481 )));
482 };
483
484 let mut json_keys: Vec<(<Self::Entity as EntityTrait>::Column, bool)> = Vec::new();
486
487 for col in <<Self::Entity as EntityTrait>::Column>::iter() {
488 let key = col.json_key();
489 let has_key = obj.contains_key(key);
490 json_keys.push((col, has_key));
491 }
492
493 let dummy_model = Self::default_values();
495 if let Ok(dummy_model) = dummy_model.try_into_model() {
496 if let Ok(mut dummy_json) = serde_json::to_value(&dummy_model) {
497 let serde_json::Value::Object(merged) = &mut dummy_json else {
498 unreachable!();
499 };
500 let serde_json::Value::Object(obj) = json else {
501 unreachable!();
502 };
503 for (key, value) in obj {
505 merged.insert(key, value);
506 }
507 json = dummy_json;
508 }
509 }
510
511 let model: <Self::Entity as EntityTrait>::Model =
513 serde_json::from_value(json).map_err(json_err)?;
514 let mut am = model.into_active_model();
515
516 for (col, json_key_exists) in json_keys {
518 match (json_key_exists, am.get(col)) {
519 (true, ActiveValue::Set(value) | ActiveValue::Unchanged(value)) => {
520 am.set(col, value);
521 }
522 _ => {
523 am.not_set(col);
524 }
525 }
526 }
527
528 Ok(am)
529 }
530
531 #[cfg(feature = "with-arrow")]
546 fn from_arrow(batch: &sea_orm_arrow::arrow::array::RecordBatch) -> Result<Vec<Self>, DbErr> {
547 use crate::{IdenStatic, Iterable, with_arrow::arrow_array_to_value};
548
549 let num_rows = batch.num_rows();
550 let mut results = Vec::with_capacity(num_rows);
551
552 for row in 0..num_rows {
553 let mut am = Self::default();
554
555 for col in <<Self::Entity as EntityTrait>::Column>::iter() {
556 let col_name = col.as_str();
557
558 if let Some(arrow_col) = batch.column_by_name(col_name) {
559 let col_def = col.def();
560 let col_type = col_def.get_column_type();
561 let value = arrow_array_to_value(arrow_col.as_ref(), col_type, row)?;
562
563 #[cfg(all(feature = "with-chrono", feature = "with-time"))]
568 {
569 use crate::with_arrow::{arrow_array_to_value_alt, is_datetime_column};
570 match am.try_set(col, value) {
571 Ok(()) => {}
572 Err(first_err) if is_datetime_column(col_type) => {
573 if let Some(alt_value) =
574 arrow_array_to_value_alt(arrow_col.as_ref(), col_type, row)?
575 {
576 am.try_set(col, alt_value)?;
577 } else {
578 return Err(first_err);
579 }
580 }
581 Err(e) => return Err(e),
582 }
583 }
584
585 #[cfg(not(all(feature = "with-chrono", feature = "with-time")))]
586 am.try_set(col, value)?;
587 } else {
588 am.not_set(col);
589 }
590 }
591
592 results.push(am);
593 }
594
595 Ok(results)
596 }
597
598 #[cfg(feature = "with-arrow")]
611 fn to_arrow(
612 models: &[Self],
613 schema: &sea_orm_arrow::arrow::datatypes::Schema,
614 ) -> Result<sea_orm_arrow::arrow::array::RecordBatch, DbErr> {
615 use crate::{Iterable, with_arrow::option_values_to_arrow_array};
616 use std::sync::Arc;
617
618 let mut columns: Vec<Arc<dyn sea_orm_arrow::arrow::array::Array>> =
619 Vec::with_capacity(schema.fields().len());
620
621 for field in schema.fields() {
622 let field_name = field.name();
623
624 let entity_col =
626 <<Self::Entity as EntityTrait>::Column>::iter().find(|c| c.as_str() == field_name);
627
628 if let Some(col) = entity_col {
629 let values: Vec<Option<Value>> = models
630 .iter()
631 .map(|m| match m.get(col) {
632 ActiveValue::Set(v) | ActiveValue::Unchanged(v) => Some(v),
633 ActiveValue::NotSet => None,
634 })
635 .collect();
636
637 let array = option_values_to_arrow_array(&values, field.data_type())?;
638 columns.push(array);
639 } else {
640 let array =
642 sea_orm_arrow::arrow::array::new_null_array(field.data_type(), models.len());
643 columns.push(array);
644 }
645 }
646
647 sea_orm_arrow::arrow::array::RecordBatch::try_new(Arc::new(schema.clone()), columns)
648 .map_err(|e| DbErr::Type(format!("Failed to create RecordBatch: {e}")))
649 }
650
651 fn is_changed(&self) -> bool {
653 <Self::Entity as EntityTrait>::Column::iter()
654 .any(|col| matches!(self.get(col), ActiveValue::Set(_)))
655 }
656
657 #[doc(hidden)]
658 fn set_parent_key<R, AM>(&mut self, model: &AM) -> Result<(), DbErr>
660 where
661 R: EntityTrait,
662 AM: ActiveModelTrait<Entity = R>,
663 Self::Entity: Related<R>,
664 {
665 let rel_def = Self::Entity::to();
666
667 if rel_def.is_owner {
668 return Err(DbErr::Type(format!(
669 "Relation from {} to {} is not belongs_to",
670 <Self::Entity as Default>::default().as_str(),
671 <R as Default>::default().as_str()
672 )));
673 }
674
675 let values = get_key_from_active_model(&rel_def.to_col, model)?;
676
677 set_key_on_active_model(&rel_def.from_col, self, values)?;
678
679 Ok(())
680 }
681
682 #[doc(hidden)]
683 fn set_parent_key_for<R, AM>(
684 &mut self,
685 model: &AM,
686 rel: <Self::Entity as EntityTrait>::Relation,
687 ) -> Result<(), DbErr>
688 where
689 R: EntityTrait,
690 AM: ActiveModelTrait<Entity = R>,
691 {
692 let rel_def = rel.def();
693
694 if rel_def.is_owner {
695 return Err(DbErr::Type(format!("Relation {rel:?} is not belongs_to")));
696 }
697
698 let values = get_key_from_active_model(&rel_def.to_col, model)?;
699
700 set_key_on_active_model(&rel_def.from_col, self, values)?;
701
702 Ok(())
703 }
704
705 #[doc(hidden)]
706 fn set_parent_key_for_def<R, AM>(
707 &mut self,
708 model: &AM,
709 rel_def: &RelationDef,
710 ) -> Result<(), DbErr>
711 where
712 R: EntityTrait,
713 AM: ActiveModelTrait<Entity = R>,
714 {
715 if rel_def.is_owner {
716 return Err(DbErr::Type(format!(
717 "Relation {rel_def:?} is not belongs_to"
718 )));
719 }
720
721 let values = get_key_from_active_model(&rel_def.to_col, model)?;
722
723 set_key_on_active_model(&rel_def.from_col, self, values)?;
724
725 Ok(())
726 }
727
728 #[doc(hidden)]
729 fn set_parent_key_for_self_rev<AM>(
730 &mut self,
731 model: &AM,
732 rel: <Self::Entity as EntityTrait>::Relation,
733 ) -> Result<(), DbErr>
734 where
735 AM: ActiveModelTrait<Entity = Self::Entity>,
736 {
737 let rel_def = rel.def();
738
739 if !rel_def.is_owner {
740 return Err(DbErr::Type(format!("Relation {rel:?} is not owner")));
741 }
742
743 let values = get_key_from_active_model(&rel_def.from_col, model)?;
744
745 set_key_on_active_model(&rel_def.to_col, self, values)?;
746
747 Ok(())
748 }
749
750 #[doc(hidden)]
751 fn clear_parent_key<R>(&mut self) -> Result<bool, DbErr>
753 where
754 R: EntityTrait,
755 Self::Entity: Related<R>,
756 {
757 let rel_def = Self::Entity::to();
758
759 if rel_def.is_owner {
760 return Err(DbErr::Type(format!(
761 "Relation from {} to {} is not belongs_to",
762 <Self::Entity as Default>::default().as_str(),
763 <R as Default>::default().as_str()
764 )));
765 }
766
767 clear_key_on_active_model(&rel_def.from_col, self)
768 }
769
770 #[doc(hidden)]
771 fn clear_parent_key_for_self_rev(
772 &mut self,
773 rel: <Self::Entity as EntityTrait>::Relation,
774 ) -> Result<bool, DbErr> {
775 let rel_def = rel.def();
776
777 if !rel_def.is_owner {
778 return Err(DbErr::Type(format!("Relation {rel:?} is not owner")));
779 }
780
781 clear_key_on_active_model(&rel_def.to_col, self)
782 }
783
784 #[doc(hidden)]
785 fn get_parent_key<R>(&self) -> Result<ValueTuple, DbErr>
787 where
788 R: EntityTrait,
789 Self::Entity: Related<R>,
790 {
791 let rel_def = Self::Entity::to();
792
793 if rel_def.is_owner {
794 return Err(DbErr::Type(format!(
795 "Relation from {} to {} is not belongs_to",
796 <Self::Entity as Default>::default().as_str(),
797 <R as Default>::default().as_str()
798 )));
799 }
800
801 get_key_from_active_model(&rel_def.from_col, self)
802 }
803
804 #[doc(hidden)]
805 fn get_parent_key_for(
807 &self,
808 rel: <Self::Entity as EntityTrait>::Relation,
809 ) -> Result<ValueTuple, DbErr> {
810 let rel_def = rel.def();
811
812 if rel_def.is_owner {
813 return Err(DbErr::Type(format!("Relation {rel:?} is not belongs_to")));
814 }
815
816 get_key_from_active_model(&rel_def.from_col, self)
817 }
818
819 #[doc(hidden)]
820 fn find_belongs_to_self(
821 &self,
822 rel: <Self::Entity as EntityTrait>::Relation,
823 db_backend: DbBackend,
824 ) -> Result<crate::query::Select<Self::Entity>, DbErr> {
825 let rel_def = rel.def();
826
827 if !rel_def.is_owner {
828 return Err(DbErr::Type(format!(
829 "Relation {rel:?} is not has_one / has_many"
830 )));
831 }
832
833 let id = get_key_from_active_model(&rel_def.from_col, self)?;
834
835 Ok(Self::Entity::find().filter(
836 column_tuple_in_condition(
837 &<Self::Entity as Default>::default().table_ref(),
838 &rel_def.to_col,
839 &[id],
840 db_backend,
841 )
842 .expect(""),
843 ))
844 }
845
846 #[doc(hidden)]
847 fn find_belongs_to_model<AM>(
848 rel_def: &RelationDef,
849 belongs_to: &AM,
850 db_backend: DbBackend,
851 ) -> Result<crate::query::Select<Self::Entity>, DbErr>
852 where
853 AM: ActiveModelTrait,
854 {
855 if rel_def.is_owner {
856 return Err(DbErr::Type(format!(
857 "Relation {rel_def:?} is not belongs_to"
858 )));
859 }
860
861 let id = get_key_from_active_model(&rel_def.to_col, belongs_to)?;
862 Ok(<Self::Entity as EntityTrait>::find().filter(
863 column_tuple_in_condition(&rel_def.from_tbl, &rel_def.from_col, &[id], db_backend)
864 .expect(""),
865 ))
866 }
867
868 fn find_related<R>(&self, _: R) -> crate::query::Select<R>
870 where
871 R: EntityTrait,
872 Self::Entity: Related<R>,
873 {
874 Self::Entity::find_related().belongs_to_active_model(self)
875 }
876
877 #[doc(hidden)]
879 fn find_related_of<AM>(&self, _: &[AM]) -> crate::query::Select<AM::Entity>
880 where
881 AM: ActiveModelTrait,
882 Self::Entity: Related<AM::Entity>,
883 {
884 self.find_related(AM::Entity::default())
885 }
886
887 #[doc(hidden)]
890 async fn establish_links<J, R, RM, C>(
891 &self,
892 _: J,
893 related_models: &[RM],
894 delete_leftover: bool,
895 db: &C,
896 ) -> Result<(), DbErr>
897 where
898 R: EntityTrait,
899 RM: ActiveModelTrait<Entity = R> + Sync,
900 J: EntityTrait + Related<R> + Related<Self::Entity>,
901 J::Model: IntoActiveModel<J::ActiveModel>,
902 J::ActiveModel: ActiveModelBehavior + Send,
903 C: ConnectionTrait,
904 {
905 let left = <J as Related<Self::Entity>>::to();
906 let right = <J as Related<R>>::to();
907
908 establish_links::<_, J, _, C>(self, related_models, left, right, delete_leftover, db).await
909 }
910
911 #[doc(hidden)]
913 async fn establish_links_self<J, RM, C>(
914 &self,
915 _: J,
916 related_models: &[RM],
917 delete_leftover: bool,
918 db: &C,
919 ) -> Result<(), DbErr>
920 where
921 RM: ActiveModelTrait<Entity = Self::Entity> + Sync,
922 J: EntityTrait,
923 J::Model: IntoActiveModel<J::ActiveModel>,
924 J::ActiveModel: ActiveModelBehavior + Send,
925 C: ConnectionTrait,
926 Self::Entity: RelatedSelfVia<J>,
927 {
928 let left = <Self::Entity as RelatedSelfVia<J>>::via().rev();
929 let right = <Self::Entity as RelatedSelfVia<J>>::to();
930
931 establish_links::<_, J, _, C>(self, related_models, left, right, delete_leftover, db).await
932 }
933
934 #[doc(hidden)]
936 async fn establish_links_self_rev<J, RM, C>(
937 &self,
938 _: J,
939 related_models: &[RM],
940 delete_leftover: bool,
941 db: &C,
942 ) -> Result<(), DbErr>
943 where
944 RM: ActiveModelTrait<Entity = Self::Entity> + Sync,
945 J: EntityTrait,
946 J::Model: IntoActiveModel<J::ActiveModel>,
947 J::ActiveModel: ActiveModelBehavior + Send,
948 C: ConnectionTrait,
949 Self::Entity: RelatedSelfVia<J>,
950 {
951 let left = <Self::Entity as RelatedSelfVia<J>>::to();
952 let right = <Self::Entity as RelatedSelfVia<J>>::via().rev();
953
954 establish_links::<_, J, _, C>(self, related_models, left, right, delete_leftover, db).await
955 }
956
957 #[doc(hidden)]
959 async fn delete_links<J, C>(&self, _: J, db: &C) -> Result<DeleteResult, DbErr>
960 where
961 J: EntityTrait + Related<Self::Entity>,
962 C: ConnectionTrait,
963 {
964 let rel_def = <J as Related<Self::Entity>>::to();
965 let id = get_key_from_active_model(&rel_def.to_col, self)?;
966
967 J::delete_many()
968 .filter(
969 column_tuple_in_condition(
970 &rel_def.from_tbl,
971 &rel_def.from_col,
972 &[id],
973 db.get_database_backend(),
974 )
975 .expect(""),
976 )
977 .exec(db)
978 .await
979 }
980
981 #[doc(hidden)]
983 async fn delete_links_self<J, C>(&self, _: J, db: &C) -> Result<DeleteResult, DbErr>
984 where
985 J: EntityTrait,
986 C: ConnectionTrait,
987 Self::Entity: RelatedSelfVia<J>,
988 {
989 let left = <Self::Entity as RelatedSelfVia<J>>::via().rev();
990 let right = <Self::Entity as RelatedSelfVia<J>>::to();
991
992 let id = get_key_from_active_model(&left.to_col, self)?;
993
994 if left.to_col != right.to_col {
995 return Err(DbErr::Type("Expect Self Referencing Relation".into()));
996 }
997
998 J::delete_many()
999 .filter(
1000 Condition::any()
1001 .add(
1002 column_tuple_in_condition(
1003 &left.from_tbl,
1004 &left.from_col,
1005 std::slice::from_ref(&id),
1006 db.get_database_backend(),
1007 )
1008 .expect(""),
1009 )
1010 .add(
1011 column_tuple_in_condition(
1012 &right.from_tbl,
1013 &right.from_col,
1014 std::slice::from_ref(&id),
1015 db.get_database_backend(),
1016 )
1017 .expect(""),
1018 ),
1019 )
1020 .exec(db)
1021 .await
1022 }
1023}
1024
1025#[allow(unused_variables)]
1053#[async_trait::async_trait]
1054pub trait ActiveModelBehavior: ActiveModelTrait {
1055 fn new() -> Self {
1068 <Self as ActiveModelTrait>::default()
1069 }
1070
1071 async fn before_save<C>(self, db: &C, insert: bool) -> Result<Self, DbErr>
1073 where
1074 C: ConnectionTrait,
1075 {
1076 Ok(self)
1077 }
1078
1079 async fn after_save<C>(
1081 model: <Self::Entity as EntityTrait>::Model,
1082 db: &C,
1083 insert: bool,
1084 ) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
1085 where
1086 C: ConnectionTrait,
1087 {
1088 Ok(model)
1089 }
1090
1091 async fn before_delete<C>(self, db: &C) -> Result<Self, DbErr>
1093 where
1094 C: ConnectionTrait,
1095 {
1096 Ok(self)
1097 }
1098
1099 async fn after_delete<C>(self, db: &C) -> Result<Self, DbErr>
1101 where
1102 C: ConnectionTrait,
1103 {
1104 Ok(self)
1105 }
1106}
1107
1108pub trait IntoActiveModel<A>
1193where
1194 A: ActiveModelTrait,
1195{
1196 fn into_active_model(self) -> A;
1198}
1199
1200impl<A> IntoActiveModel<A> for A
1201where
1202 A: ActiveModelTrait,
1203{
1204 fn into_active_model(self) -> A {
1205 self
1206 }
1207}
1208
1209async fn establish_links<EM, J, RM, C>(
1210 model: &EM,
1211 related_models: &[RM],
1212 left: RelationDef,
1213 right: RelationDef,
1214 delete_leftover: bool,
1215 db: &C,
1216) -> Result<(), DbErr>
1217where
1218 EM: ActiveModelTrait,
1219 RM: ActiveModelTrait,
1220 J: EntityTrait,
1221 J::Model: IntoActiveModel<J::ActiveModel>,
1222 J::ActiveModel: ActiveModelBehavior,
1223 C: ConnectionTrait,
1224{
1225 let mut require_leftover = true;
1226
1227 if related_models.is_empty() {
1228 require_leftover = false;
1230 }
1231
1232 let primary_key = J::primary_key_identity();
1233 if require_leftover
1234 && primary_key.fully_contains(&left.from_col)
1235 && primary_key.fully_contains(&right.from_col)
1236 {
1237 require_leftover = false;
1240 }
1241
1242 let mut leftover = Vec::new();
1243 if delete_leftover || require_leftover {
1244 for item in <J::ActiveModel as ActiveModelTrait>::find_belongs_to_model(
1245 &left,
1246 model,
1247 db.get_database_backend(),
1248 )?
1249 .all(db)
1250 .await?
1251 {
1252 let item = item.into_active_model();
1253 let key = get_key_from_active_model(&right.from_col, &item)?;
1254 leftover.push((item, key));
1255 }
1256 }
1257 let leftover = leftover; let mut via_models = Vec::new();
1260 let mut all_keys = std::collections::HashSet::new();
1261
1262 for related_model in related_models {
1263 let mut via: J::ActiveModel = ActiveModelBehavior::new();
1264 via.set_parent_key_for_def(model, &left)?;
1265 via.set_parent_key_for_def(related_model, &right)?;
1266 let via_key = get_key_from_active_model(&right.from_col, &via)?;
1267 if !leftover.iter().any(|t| t.1 == via_key) {
1268 via_models.push(via);
1270 }
1271 if delete_leftover {
1272 all_keys.insert(via_key);
1273 }
1274 }
1275
1276 if delete_leftover {
1277 let mut to_delete = Vec::new();
1278 for (leftover, key) in leftover {
1279 if !all_keys.contains(&key) {
1280 to_delete.push(
1281 leftover
1282 .get_primary_key_value()
1283 .expect("item is a full model"),
1284 );
1285 }
1286 }
1287 if !to_delete.is_empty() {
1288 J::delete_many()
1289 .filter_by_value_tuples(&to_delete, db.get_database_backend())
1290 .exec(db)
1291 .await?;
1292 }
1293 }
1294
1295 if !via_models.is_empty() {
1296 J::insert_many(via_models)
1298 .on_conflict_do_nothing()
1299 .exec(db)
1300 .await?;
1301 }
1302
1303 Ok(())
1304}
1305
1306#[cfg(test)]
1307mod tests {
1308 use crate::{DbErr, entity::*, tests_cfg::*};
1309 use pretty_assertions::assert_eq;
1310
1311 #[cfg(feature = "with-json")]
1312 use serde_json::json;
1313
1314 #[test]
1315 #[cfg(feature = "macros")]
1316 fn test_derive_into_active_model_1() {
1317 mod my_fruit {
1318 pub use super::fruit::*;
1319 use crate as sea_orm;
1320 use crate::entity::prelude::*;
1321
1322 #[derive(DeriveIntoActiveModel)]
1323 pub struct NewFruit {
1324 pub name: String,
1326 pub cake_id: i32,
1328 }
1329 }
1330
1331 assert_eq!(
1332 my_fruit::NewFruit {
1333 name: "Apple".to_owned(),
1334 cake_id: 1,
1335 }
1336 .into_active_model(),
1337 fruit::ActiveModel {
1338 id: NotSet,
1339 name: Set("Apple".to_owned()),
1340 cake_id: Set(Some(1)),
1341 }
1342 );
1343 }
1344
1345 #[test]
1346 #[cfg(feature = "macros")]
1347 fn test_derive_into_active_model_2() {
1348 use crate as sea_orm;
1349 use crate::entity::prelude::*;
1350
1351 #[derive(DeriveIntoActiveModel)]
1352 #[sea_orm(active_model = "fruit::ActiveModel")]
1353 struct RequiredFruitName {
1354 name: String,
1355 }
1356
1357 assert_eq!(
1358 RequiredFruitName {
1359 name: "Apple Pie".to_owned(),
1360 }
1361 .into_active_model(),
1362 fruit::ActiveModel {
1363 id: NotSet,
1364 name: Set("Apple Pie".to_owned()),
1365 cake_id: NotSet,
1366 }
1367 );
1368
1369 #[derive(DeriveIntoActiveModel)]
1370 #[sea_orm(active_model = "fruit::ActiveModel")]
1371 struct OptionalFruitName {
1372 name: Option<String>,
1373 }
1374
1375 assert_eq!(
1376 OptionalFruitName {
1377 name: Some("Apple Pie".to_owned()),
1378 }
1379 .into_active_model(),
1380 fruit::ActiveModel {
1381 id: NotSet,
1382 name: Set("Apple Pie".to_owned()),
1383 cake_id: NotSet,
1384 }
1385 );
1386
1387 assert_eq!(
1388 OptionalFruitName { name: None }.into_active_model(),
1389 fruit::ActiveModel {
1390 id: NotSet,
1391 name: NotSet,
1392 cake_id: NotSet,
1393 }
1394 );
1395
1396 #[derive(DeriveIntoActiveModel)]
1397 #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
1398 struct RequiredAndNotNullFruitCake {
1399 cake_id: i32,
1400 }
1401
1402 assert_eq!(
1403 RequiredAndNotNullFruitCake { cake_id: 1 }.into_active_model(),
1404 fruit::ActiveModel {
1405 id: NotSet,
1406 name: NotSet,
1407 cake_id: Set(Some(1)),
1408 }
1409 );
1410
1411 #[derive(DeriveIntoActiveModel)]
1412 #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
1413 struct OptionalAndNotNullFruitCake {
1414 cake_id: Option<i32>,
1415 }
1416
1417 assert_eq!(
1418 OptionalAndNotNullFruitCake { cake_id: Some(1) }.into_active_model(),
1419 fruit::ActiveModel {
1420 id: NotSet,
1421 name: NotSet,
1422 cake_id: Set(Some(1)),
1423 }
1424 );
1425
1426 assert_eq!(
1427 OptionalAndNotNullFruitCake { cake_id: None }.into_active_model(),
1428 fruit::ActiveModel {
1429 id: NotSet,
1430 name: NotSet,
1431 cake_id: NotSet,
1432 }
1433 );
1434
1435 #[derive(DeriveIntoActiveModel)]
1436 #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
1437 struct OptionalAndNullableFruitCake {
1438 cake_id: Option<Option<i32>>,
1439 }
1440
1441 assert_eq!(
1442 OptionalAndNullableFruitCake {
1443 cake_id: Some(Some(1)),
1444 }
1445 .into_active_model(),
1446 fruit::ActiveModel {
1447 id: NotSet,
1448 name: NotSet,
1449 cake_id: Set(Some(1)),
1450 }
1451 );
1452
1453 assert_eq!(
1454 OptionalAndNullableFruitCake {
1455 cake_id: Some(None),
1456 }
1457 .into_active_model(),
1458 fruit::ActiveModel {
1459 id: NotSet,
1460 name: NotSet,
1461 cake_id: Set(None),
1462 }
1463 );
1464
1465 assert_eq!(
1466 OptionalAndNullableFruitCake { cake_id: None }.into_active_model(),
1467 fruit::ActiveModel {
1468 id: NotSet,
1469 name: NotSet,
1470 cake_id: NotSet,
1471 }
1472 );
1473 }
1474
1475 #[test]
1476 #[cfg(feature = "macros")]
1477 fn test_derive_into_active_model_set_single() {
1478 use crate as sea_orm;
1479 use crate::entity::prelude::*;
1480
1481 #[derive(DeriveIntoActiveModel)]
1482 #[sea_orm(active_model = "fruit::ActiveModel", set(cake_id = "None"))]
1483 struct NewFruit {
1484 name: String,
1485 }
1486
1487 assert_eq!(
1488 NewFruit {
1489 name: "Apple".to_owned(),
1490 }
1491 .into_active_model(),
1492 fruit::ActiveModel {
1493 id: NotSet,
1494 name: Set("Apple".to_owned()),
1495 cake_id: Set(None),
1496 }
1497 );
1498 }
1499
1500 #[test]
1501 #[cfg(feature = "macros")]
1502 fn test_derive_into_active_model_set_multiple() {
1503 use crate as sea_orm;
1504 use crate::entity::prelude::*;
1505
1506 #[derive(DeriveIntoActiveModel)]
1507 #[sea_orm(
1508 active_model = "fruit::ActiveModel",
1509 set(name = "String::from(\"cherry\")", cake_id = "None")
1510 )]
1511 struct IdOnlyFruit {
1512 id: i32,
1513 }
1514 assert_eq!(
1515 IdOnlyFruit { id: 1 }.into_active_model(),
1516 fruit::ActiveModel {
1517 id: Set(1),
1518 name: Set("cherry".to_owned()),
1519 cake_id: Set(None),
1520 }
1521 );
1522
1523 #[derive(DeriveIntoActiveModel)]
1524 #[sea_orm(
1525 active_model = "fruit::ActiveModel",
1526 set(name = "String::from(\"cherry\")"),
1527 set(cake_id = "None")
1528 )]
1529 struct IdOnlyFruit2 {
1530 id: i32,
1531 }
1532 assert_eq!(
1533 IdOnlyFruit2 { id: 1 }.into_active_model(),
1534 fruit::ActiveModel {
1535 id: Set(1),
1536 name: Set("cherry".to_owned()),
1537 cake_id: Set(None),
1538 }
1539 );
1540 }
1541
1542 #[test]
1543 #[cfg(feature = "macros")]
1544 fn test_derive_into_active_model_set_separate_attrs() {
1545 use crate as sea_orm;
1546 use crate::entity::prelude::*;
1547
1548 #[derive(DeriveIntoActiveModel)]
1549 #[sea_orm(
1550 active_model = "fruit::ActiveModel",
1551 set(name = "String::from(\"cherry\")")
1552 )]
1553 #[sea_orm(set(cake_id = "None"))]
1554 struct IdOnlyFruit {
1555 id: i32,
1556 }
1557
1558 assert_eq!(
1559 IdOnlyFruit { id: 1 }.into_active_model(),
1560 fruit::ActiveModel {
1561 id: Set(1),
1562 name: Set("cherry".to_owned()),
1563 cake_id: Set(None),
1564 }
1565 );
1566 }
1567
1568 #[test]
1569 #[cfg(feature = "macros")]
1570 fn test_derive_into_active_model_ignore() {
1571 use crate as sea_orm;
1572 use crate::entity::prelude::*;
1573
1574 #[derive(DeriveIntoActiveModel)]
1575 #[sea_orm(active_model = "fruit::ActiveModel")]
1576 struct NewFruit {
1577 name: String,
1578 cake_id: i32,
1579 #[sea_orm(ignore)]
1580 _extra: String,
1581 }
1582
1583 assert_eq!(
1584 NewFruit {
1585 name: "Apple".to_owned(),
1586 cake_id: 1,
1587 _extra: "ignored".to_owned(),
1588 }
1589 .into_active_model(),
1590 fruit::ActiveModel {
1591 id: NotSet,
1592 name: Set("Apple".to_owned()),
1593 cake_id: Set(Some(1)),
1594 }
1595 );
1596 }
1597
1598 #[test]
1599 #[cfg(feature = "macros")]
1600 fn test_derive_into_active_model_skip() {
1601 use crate as sea_orm;
1602 use crate::entity::prelude::*;
1603
1604 #[derive(DeriveIntoActiveModel)]
1605 #[sea_orm(active_model = "fruit::ActiveModel")]
1606 struct NewFruit {
1607 name: String,
1608 #[sea_orm(skip)]
1609 _extra: String,
1610 }
1611
1612 assert_eq!(
1613 NewFruit {
1614 name: "Apple".to_owned(),
1615 _extra: "skipped".to_owned(),
1616 }
1617 .into_active_model(),
1618 fruit::ActiveModel {
1619 id: NotSet,
1620 name: Set("Apple".to_owned()),
1621 cake_id: NotSet,
1622 }
1623 );
1624 }
1625
1626 #[test]
1627 #[cfg(feature = "macros")]
1628 fn test_derive_into_active_model_set_and_ignore() {
1629 use crate as sea_orm;
1630 use crate::entity::prelude::*;
1631
1632 #[derive(DeriveIntoActiveModel)]
1633 #[sea_orm(active_model = "fruit::ActiveModel", set(cake_id = "Some(42)"))]
1634 struct NewFruit {
1635 name: String,
1636 #[sea_orm(ignore)]
1637 _extra: String,
1638 }
1639
1640 assert_eq!(
1641 NewFruit {
1642 name: "Apple".to_owned(),
1643 _extra: "ignored".to_owned(),
1644 }
1645 .into_active_model(),
1646 fruit::ActiveModel {
1647 id: NotSet,
1648 name: Set("Apple".to_owned()),
1649 cake_id: Set(Some(42)),
1650 }
1651 );
1652 }
1653
1654 #[test]
1655 #[cfg(feature = "macros")]
1656 fn test_derive_into_active_model_foreign_ignore() {
1657 use serde::{Deserialize, Serialize};
1658
1659 use crate as sea_orm;
1660 use crate::entity::prelude::*;
1661
1662 #[derive(DeriveIntoActiveModel, Serialize, Deserialize)]
1663 #[sea_orm(active_model = "fruit::ActiveModel")]
1664 struct NewFruit {
1665 #[sea_orm(ignore)]
1666 id: i32,
1667 name: String,
1668 #[serde(skip)]
1669 cake_id: Option<i32>,
1670 }
1671
1672 assert_eq!(
1673 NewFruit {
1674 id: 1.to_owned(),
1675 name: "Apple".to_owned(),
1676 cake_id: Some(42)
1677 }
1678 .into_active_model(),
1679 fruit::ActiveModel {
1680 id: NotSet,
1681 name: Set("Apple".to_owned()),
1682 cake_id: Set(Some(42)),
1683 }
1684 );
1685 }
1686
1687 #[test]
1688 #[cfg(feature = "macros")]
1689 fn test_derive_into_active_model_exhaustive() {
1690 use crate as sea_orm;
1691 use crate::entity::prelude::*;
1692
1693 #[derive(DeriveIntoActiveModel)]
1694 #[sea_orm(active_model = "fruit::ActiveModel", exhaustive, set(cake_id = "None"))]
1695 struct FullFruit {
1696 id: i32,
1697 name: String,
1698 }
1699
1700 assert_eq!(
1701 FullFruit {
1702 id: 1,
1703 name: "Apple".to_owned(),
1704 }
1705 .into_active_model(),
1706 fruit::ActiveModel {
1707 id: Set(1),
1708 name: Set("Apple".to_owned()),
1709 cake_id: Set(None),
1710 }
1711 );
1712 }
1713
1714 #[test]
1715 #[cfg(feature = "macros")]
1716 fn test_derive_into_active_model_multiple_sets() {
1717 use crate as sea_orm;
1718 use crate::entity::prelude::*;
1719
1720 const DEFULT_CAKE_ID: i32 = 1;
1721 #[derive(DeriveIntoActiveModel)]
1722 #[sea_orm(
1723 active_model = "fruit::ActiveModel",
1724 exhaustive,
1725 set(cake_id = "Some(DEFULT_CAKE_ID)")
1726 )]
1727 struct FullFruit {
1728 id: i32,
1729 name: String,
1730 }
1731
1732 assert_eq!(
1733 FullFruit {
1734 id: 1,
1735 name: "Apple".to_owned(),
1736 }
1737 .into_active_model(),
1738 fruit::ActiveModel {
1739 id: Set(1),
1740 name: Set("Apple".to_owned()),
1741 cake_id: Set(Some(1)),
1742 }
1743 );
1744 }
1745
1746 #[test]
1747 #[cfg(feature = "macros")]
1748 fn test_derive_into_active_model_field_empty_default() {
1749 use crate as sea_orm;
1750 use crate::entity::prelude::*;
1751
1752 #[derive(DeriveIntoActiveModel)]
1753 #[sea_orm(active_model = "fruit::ActiveModel")]
1754 struct NewFruit {
1755 #[sea_orm(default)]
1756 name: Option<String>,
1757 }
1758
1759 assert_eq!(
1761 NewFruit {
1762 name: Some("Apple".to_owned()),
1763 }
1764 .into_active_model(),
1765 fruit::ActiveModel {
1766 id: NotSet,
1767 name: Set("Apple".to_owned()),
1768 cake_id: NotSet,
1769 }
1770 );
1771
1772 assert_eq!(
1774 NewFruit { name: None }.into_active_model(),
1775 fruit::ActiveModel {
1776 id: NotSet,
1777 name: Set("".to_owned()),
1778 cake_id: NotSet,
1779 }
1780 );
1781 }
1782
1783 #[test]
1784 #[cfg(feature = "macros")]
1785 fn test_derive_into_active_model_field_custom_option() {
1786 use crate as sea_orm;
1787 use crate::entity::prelude::*;
1788 mod foreign_crate {
1789 #[derive(Debug, Clone, PartialEq, Eq)]
1790 pub enum CustomOption<T> {
1791 None,
1792 Some(T),
1793 }
1794
1795 impl From<CustomOption<String>> for Option<String> {
1796 fn from(option: CustomOption<String>) -> Self {
1797 match option {
1798 CustomOption::None => Option::None,
1799 CustomOption::Some(value) => value.into(),
1800 }
1801 }
1802 }
1803 }
1804 use foreign_crate::CustomOption;
1805
1806 #[derive(DeriveIntoActiveModel)]
1807 #[sea_orm(active_model = "fruit::ActiveModel")]
1808 struct NewFruit {
1809 #[sea_orm(default)]
1810 name: CustomOption<String>,
1811 }
1812
1813 assert_eq!(
1815 NewFruit {
1816 name: CustomOption::Some("Apple".to_owned()),
1817 }
1818 .into_active_model(),
1819 fruit::ActiveModel {
1820 id: NotSet,
1821 name: Set("Apple".to_owned()),
1822 cake_id: NotSet,
1823 }
1824 );
1825
1826 assert_eq!(
1828 NewFruit {
1829 name: CustomOption::None
1830 }
1831 .into_active_model(),
1832 fruit::ActiveModel {
1833 id: NotSet,
1834 name: Set("".to_owned()),
1835 cake_id: NotSet,
1836 }
1837 );
1838 }
1839
1840 #[test]
1841 #[cfg(feature = "macros")]
1842 fn test_derive_into_active_model_field_default_some() {
1843 use crate as sea_orm;
1844 use crate::entity::prelude::*;
1845
1846 #[derive(DeriveIntoActiveModel)]
1847 #[sea_orm(active_model = "fruit::ActiveModel")]
1848 struct NewFruit {
1849 #[sea_orm(default = "String::from(\"Unnamed\")")]
1850 name: Option<String>,
1851 }
1852
1853 assert_eq!(
1855 NewFruit {
1856 name: Some("Apple".to_owned()),
1857 }
1858 .into_active_model(),
1859 fruit::ActiveModel {
1860 id: NotSet,
1861 name: Set("Apple".to_owned()),
1862 cake_id: NotSet,
1863 }
1864 );
1865
1866 assert_eq!(
1868 NewFruit { name: None }.into_active_model(),
1869 fruit::ActiveModel {
1870 id: NotSet,
1871 name: Set("Unnamed".to_owned()),
1872 cake_id: NotSet,
1873 }
1874 );
1875 }
1876
1877 #[test]
1878 #[cfg(feature = "macros")]
1879 fn test_derive_into_active_model_field_default_with_set() {
1880 use crate as sea_orm;
1881 use crate::entity::prelude::*;
1882
1883 #[derive(DeriveIntoActiveModel)]
1884 #[sea_orm(active_model = "fruit::ActiveModel", set(cake_id = "Some(99)"))]
1885 struct NewFruit {
1886 #[sea_orm(default = "String::from(\"Unnamed\")")]
1887 name: Option<String>,
1888 #[sea_orm(ignore)]
1889 _extra: String,
1890 }
1891
1892 assert_eq!(
1893 NewFruit {
1894 name: Some("Apple".to_owned()),
1895 _extra: "ignored".to_owned(),
1896 }
1897 .into_active_model(),
1898 fruit::ActiveModel {
1899 id: NotSet,
1900 name: Set("Apple".to_owned()),
1901 cake_id: Set(Some(99)),
1902 }
1903 );
1904
1905 assert_eq!(
1906 NewFruit {
1907 name: None,
1908 _extra: "ignored".to_owned(),
1909 }
1910 .into_active_model(),
1911 fruit::ActiveModel {
1912 id: NotSet,
1913 name: Set("Unnamed".to_owned()),
1914 cake_id: Set(Some(99)),
1915 }
1916 );
1917 }
1918
1919 #[test]
1920 #[cfg(feature = "macros")]
1921 fn test_derive_into_active_model_field_default_exhaustive() {
1922 use crate as sea_orm;
1923 use crate::entity::prelude::*;
1924
1925 #[derive(DeriveIntoActiveModel)]
1926 #[sea_orm(active_model = "fruit::ActiveModel", exhaustive, set(cake_id = "None"))]
1927 struct NewFruit {
1928 id: i32,
1929 #[sea_orm(default = "String::from(\"Unnamed\")")]
1930 name: Option<String>,
1931 }
1932
1933 assert_eq!(
1934 NewFruit {
1935 id: 1,
1936 name: Some("Apple".to_owned()),
1937 }
1938 .into_active_model(),
1939 fruit::ActiveModel {
1940 id: Set(1),
1941 name: Set("Apple".to_owned()),
1942 cake_id: Set(None),
1943 }
1944 );
1945
1946 assert_eq!(
1947 NewFruit { id: 2, name: None }.into_active_model(),
1948 fruit::ActiveModel {
1949 id: Set(2),
1950 name: Set("Unnamed".to_owned()),
1951 cake_id: Set(None),
1952 }
1953 );
1954 }
1955
1956 #[test]
1957 #[cfg(feature = "macros")]
1958 fn test_derive_try_into_model_1() {
1959 mod my_fruit {
1960 use crate as sea_orm;
1961 use crate::entity::prelude::*;
1962
1963 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1964 #[sea_orm(table_name = "fruit")]
1965 pub struct Model {
1966 #[sea_orm(primary_key)]
1967 pub id: i32,
1968 pub name: String,
1969 pub cake_id: Option<i32>,
1970 }
1971
1972 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1973 pub enum Relation {}
1974
1975 impl ActiveModelBehavior for ActiveModel {}
1976 }
1977 assert_eq!(
1978 my_fruit::ActiveModel {
1979 id: Set(1),
1980 name: Set("Pineapple".to_owned()),
1981 cake_id: Set(None),
1982 }
1983 .try_into_model()
1984 .unwrap(),
1985 my_fruit::Model {
1986 id: 1,
1987 name: "Pineapple".to_owned(),
1988 cake_id: None,
1989 }
1990 );
1991
1992 assert_eq!(
1993 my_fruit::ActiveModel {
1994 id: Set(2),
1995 name: Set("Apple".to_owned()),
1996 cake_id: Set(Some(1)),
1997 }
1998 .try_into_model()
1999 .unwrap(),
2000 my_fruit::Model {
2001 id: 2,
2002 name: "Apple".to_owned(),
2003 cake_id: Some(1),
2004 }
2005 );
2006
2007 assert_eq!(
2008 my_fruit::ActiveModel {
2009 id: Set(1),
2010 name: NotSet,
2011 cake_id: Set(None),
2012 }
2013 .try_into_model(),
2014 Err(DbErr::AttrNotSet(String::from("name")))
2015 );
2016
2017 assert_eq!(
2018 my_fruit::ActiveModel {
2019 id: Set(1),
2020 name: Set("Pineapple".to_owned()),
2021 cake_id: NotSet,
2022 }
2023 .try_into_model(),
2024 Err(DbErr::AttrNotSet(String::from("cake_id")))
2025 );
2026 }
2027
2028 #[test]
2029 #[cfg(feature = "macros")]
2030 fn test_derive_try_into_model_2() {
2031 mod my_fruit {
2032 use crate as sea_orm;
2033 use crate::entity::prelude::*;
2034
2035 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
2036 #[sea_orm(table_name = "fruit")]
2037 pub struct Model {
2038 #[sea_orm(primary_key)]
2039 pub id: i32,
2040 pub name: String,
2041 #[sea_orm(ignore)]
2042 pub cake_id: Option<i32>,
2043 }
2044
2045 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
2046 pub enum Relation {}
2047
2048 impl ActiveModelBehavior for ActiveModel {}
2049 }
2050 assert_eq!(
2051 my_fruit::ActiveModel {
2052 id: Set(1),
2053 name: Set("Pineapple".to_owned()),
2054 }
2055 .try_into_model()
2056 .unwrap(),
2057 my_fruit::Model {
2058 id: 1,
2059 name: "Pineapple".to_owned(),
2060 cake_id: None,
2061 }
2062 );
2063 }
2064
2065 #[test]
2066 #[cfg(feature = "macros")]
2067 fn test_derive_try_into_model_3() {
2068 mod my_fruit {
2069 use crate as sea_orm;
2070 use crate::entity::prelude::*;
2071
2072 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
2073 #[sea_orm(table_name = "fruit")]
2074 pub struct Model {
2075 #[sea_orm(primary_key)]
2076 pub id: i32,
2077 #[sea_orm(ignore)]
2078 pub name: String,
2079 pub cake_id: Option<i32>,
2080 }
2081
2082 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
2083 pub enum Relation {}
2084
2085 impl ActiveModelBehavior for ActiveModel {}
2086 }
2087 assert_eq!(
2088 my_fruit::ActiveModel {
2089 id: Set(1),
2090 cake_id: Set(Some(1)),
2091 }
2092 .try_into_model()
2093 .unwrap(),
2094 my_fruit::Model {
2095 id: 1,
2096 name: "".to_owned(),
2097 cake_id: Some(1),
2098 }
2099 );
2100 }
2101
2102 #[test]
2103 #[cfg(feature = "with-json")]
2104 fn test_active_model_set_from_json_1() {
2105 assert_eq!(
2106 cake::ActiveModel::from_json(json!({
2107 "id": 1,
2108 "name": "Apple Pie",
2109 }))
2110 .unwrap(),
2111 cake::ActiveModel {
2112 id: Set(1),
2113 name: Set("Apple Pie".to_owned()),
2114 }
2115 );
2116
2117 assert_eq!(
2118 cake::ActiveModel::from_json(json!({
2119 "id": 1,
2120 }))
2121 .unwrap(),
2122 cake::ActiveModel {
2123 id: Set(1),
2124 name: NotSet,
2125 }
2126 );
2127
2128 assert_eq!(
2129 cake::ActiveModel::from_json(json!({
2130 "name": "Apple Pie",
2131 }))
2132 .unwrap(),
2133 cake::ActiveModel {
2134 id: NotSet,
2135 name: Set("Apple Pie".to_owned()),
2136 }
2137 );
2138
2139 let mut cake: cake::ActiveModel = Default::default();
2140 cake.set_from_json(json!({
2141 "name": "Apple Pie",
2142 }))
2143 .unwrap();
2144 assert_eq!(
2145 cake,
2146 cake::ActiveModel {
2147 id: NotSet,
2148 name: Set("Apple Pie".to_owned()),
2149 }
2150 );
2151 }
2152
2153 #[test]
2154 #[cfg(feature = "with-json")]
2155 fn test_active_model_set_from_json_2() -> Result<(), DbErr> {
2156 let mut fruit: fruit::ActiveModel = Default::default();
2157
2158 fruit.set_from_json(json!({
2159 "name": "Apple",
2160 }))?;
2161 assert_eq!(
2162 fruit,
2163 fruit::ActiveModel {
2164 id: ActiveValue::NotSet,
2165 name: ActiveValue::Set("Apple".to_owned()),
2166 cake_id: ActiveValue::NotSet,
2167 }
2168 );
2169
2170 assert_eq!(
2171 fruit::ActiveModel::from_json(json!({
2172 "name": "Apple",
2173 }))?,
2174 fruit::ActiveModel {
2175 id: ActiveValue::NotSet,
2176 name: ActiveValue::Set("Apple".to_owned()),
2177 cake_id: ActiveValue::NotSet,
2178 }
2179 );
2180
2181 fruit.set_from_json(json!({
2182 "name": "Apple",
2183 "cake_id": null,
2184 }))?;
2185 assert_eq!(
2186 fruit,
2187 fruit::ActiveModel {
2188 id: ActiveValue::NotSet,
2189 name: ActiveValue::Set("Apple".to_owned()),
2190 cake_id: ActiveValue::Set(None),
2191 }
2192 );
2193
2194 fruit.set_from_json(json!({
2195 "id": null,
2196 "name": "Apple",
2197 "cake_id": 1,
2198 }))?;
2199 assert_eq!(
2200 fruit,
2201 fruit::ActiveModel {
2202 id: ActiveValue::NotSet,
2203 name: ActiveValue::Set("Apple".to_owned()),
2204 cake_id: ActiveValue::Set(Some(1)),
2205 }
2206 );
2207
2208 fruit.set_from_json(json!({
2209 "id": 2,
2210 "name": "Apple",
2211 "cake_id": 1,
2212 }))?;
2213 assert_eq!(
2214 fruit,
2215 fruit::ActiveModel {
2216 id: ActiveValue::NotSet,
2217 name: ActiveValue::Set("Apple".to_owned()),
2218 cake_id: ActiveValue::Set(Some(1)),
2219 }
2220 );
2221
2222 let mut fruit = fruit::ActiveModel {
2223 id: ActiveValue::Set(1),
2224 name: ActiveValue::NotSet,
2225 cake_id: ActiveValue::NotSet,
2226 };
2227 fruit.set_from_json(json!({
2228 "id": 8,
2229 "name": "Apple",
2230 "cake_id": 1,
2231 }))?;
2232 assert_eq!(
2233 fruit,
2234 fruit::ActiveModel {
2235 id: ActiveValue::Set(1),
2236 name: ActiveValue::Set("Apple".to_owned()),
2237 cake_id: ActiveValue::Set(Some(1)),
2238 }
2239 );
2240
2241 Ok(())
2242 }
2243
2244 #[smol_potat::test]
2245 #[cfg(feature = "with-json")]
2246 async fn test_active_model_set_from_json_3() -> Result<(), DbErr> {
2247 use crate::*;
2248
2249 let db = MockDatabase::new(DbBackend::Postgres)
2250 .append_exec_results([
2251 MockExecResult {
2252 last_insert_id: 1,
2253 rows_affected: 1,
2254 },
2255 MockExecResult {
2256 last_insert_id: 1,
2257 rows_affected: 1,
2258 },
2259 ])
2260 .append_query_results([
2261 [fruit::Model {
2262 id: 1,
2263 name: "Apple".to_owned(),
2264 cake_id: None,
2265 }],
2266 [fruit::Model {
2267 id: 2,
2268 name: "Orange".to_owned(),
2269 cake_id: Some(1),
2270 }],
2271 ])
2272 .into_connection();
2273
2274 let mut fruit: fruit::ActiveModel = Default::default();
2275 fruit.set_from_json(json!({
2276 "name": "Apple",
2277 }))?;
2278 fruit.save(&db).await?;
2279
2280 let mut fruit = fruit::ActiveModel {
2281 id: Set(2),
2282 ..Default::default()
2283 };
2284 fruit.set_from_json(json!({
2285 "id": 9,
2286 "name": "Orange",
2287 "cake_id": 1,
2288 }))?;
2289 fruit.save(&db).await?;
2290
2291 assert_eq!(
2292 db.into_transaction_log(),
2293 [
2294 Transaction::from_sql_and_values(
2295 DbBackend::Postgres,
2296 r#"INSERT INTO "fruit" ("name") VALUES ($1) RETURNING "id", "name", "cake_id""#,
2297 ["Apple".into()],
2298 ),
2299 Transaction::from_sql_and_values(
2300 DbBackend::Postgres,
2301 r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
2302 ["Orange".into(), 1i32.into(), 2i32.into()],
2303 ),
2304 ]
2305 );
2306
2307 Ok(())
2308 }
2309
2310 #[test]
2311 fn test_active_model_is_changed() {
2312 let mut fruit: fruit::ActiveModel = Default::default();
2313 assert!(!fruit.is_changed());
2314
2315 fruit.set(fruit::Column::Name, "apple".into());
2316 assert!(fruit.is_changed());
2317
2318 let mut fruit = fruit::Model {
2319 id: 1,
2320 name: "".into(),
2321 cake_id: None,
2322 };
2323 fruit.set("name".parse().unwrap(), "orange".into());
2324 assert_eq!(fruit.name, "orange");
2325 }
2326
2327 #[test]
2328 fn test_reset_1() {
2329 assert_eq!(
2330 fruit::Model {
2331 id: 1,
2332 name: "Apple".into(),
2333 cake_id: None,
2334 }
2335 .into_active_model(),
2336 fruit::ActiveModel {
2337 id: Unchanged(1),
2338 name: Unchanged("Apple".into()),
2339 cake_id: Unchanged(None)
2340 },
2341 );
2342
2343 assert_eq!(
2344 fruit::Model {
2345 id: 1,
2346 name: "Apple".into(),
2347 cake_id: None,
2348 }
2349 .into_active_model()
2350 .reset_all(),
2351 fruit::ActiveModel {
2352 id: Set(1),
2353 name: Set("Apple".into()),
2354 cake_id: Set(None)
2355 },
2356 );
2357
2358 assert_eq!(
2359 fruit::Model {
2360 id: 1,
2361 name: "Apple".into(),
2362 cake_id: Some(2),
2363 }
2364 .into_active_model(),
2365 fruit::ActiveModel {
2366 id: Unchanged(1),
2367 name: Unchanged("Apple".into()),
2368 cake_id: Unchanged(Some(2)),
2369 },
2370 );
2371
2372 assert_eq!(
2373 fruit::Model {
2374 id: 1,
2375 name: "Apple".into(),
2376 cake_id: Some(2),
2377 }
2378 .into_active_model()
2379 .reset_all(),
2380 fruit::ActiveModel {
2381 id: Set(1),
2382 name: Set("Apple".into()),
2383 cake_id: Set(Some(2)),
2384 },
2385 );
2386 }
2387
2388 #[smol_potat::test]
2389 async fn test_reset_2() -> Result<(), DbErr> {
2390 use crate::*;
2391
2392 let db = MockDatabase::new(DbBackend::Postgres)
2393 .append_exec_results(vec![
2394 MockExecResult {
2395 last_insert_id: 1,
2396 rows_affected: 1,
2397 },
2398 MockExecResult {
2399 last_insert_id: 1,
2400 rows_affected: 1,
2401 },
2402 ])
2403 .append_query_results(vec![
2404 vec![fruit::Model {
2405 id: 1,
2406 name: "Apple".to_owned(),
2407 cake_id: None,
2408 }],
2409 vec![fruit::Model {
2410 id: 1,
2411 name: "Apple".to_owned(),
2412 cake_id: None,
2413 }],
2414 ])
2415 .into_connection();
2416
2417 fruit::Model {
2418 id: 1,
2419 name: "Apple".into(),
2420 cake_id: None,
2421 }
2422 .into_active_model()
2423 .update(&db)
2424 .await?;
2425
2426 fruit::Model {
2427 id: 1,
2428 name: "Apple".into(),
2429 cake_id: None,
2430 }
2431 .into_active_model()
2432 .reset_all()
2433 .update(&db)
2434 .await?;
2435
2436 assert_eq!(
2437 db.into_transaction_log(),
2438 vec![
2439 Transaction::from_sql_and_values(
2440 DbBackend::Postgres,
2441 r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit" WHERE "fruit"."id" = $1 LIMIT $2"#,
2442 vec![1i32.into(), 1u64.into()],
2443 ),
2444 Transaction::from_sql_and_values(
2445 DbBackend::Postgres,
2446 r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
2447 vec!["Apple".into(), Option::<i32>::None.into(), 1i32.into()],
2448 ),
2449 ]
2450 );
2451
2452 Ok(())
2453 }
2454
2455 #[test]
2456 fn test_active_model_default_values() {
2457 assert_eq!(
2458 fruit::ActiveModel::default_values(),
2459 fruit::ActiveModel {
2460 id: Set(0),
2461 name: Set("".into()),
2462 cake_id: Set(None),
2463 },
2464 );
2465
2466 assert_eq!(
2467 lunch_set::ActiveModel::default_values(),
2468 lunch_set::ActiveModel {
2469 id: Set(0),
2470 name: Set("".into()),
2471 tea: NotSet,
2472 },
2473 );
2474 }
2475
2476 #[test]
2477 fn test_active_model_set_parent_key() {
2478 let mut fruit = fruit::Model {
2479 id: 2,
2480 name: "F".into(),
2481 cake_id: None,
2482 }
2483 .into_active_model();
2484
2485 let cake = cake::Model {
2486 id: 4,
2487 name: "C".into(),
2488 }
2489 .into_active_model();
2490
2491 fruit.set_parent_key(&cake).unwrap();
2492
2493 assert_eq!(
2494 fruit,
2495 fruit::ActiveModel {
2496 id: Unchanged(2),
2497 name: Unchanged("F".into()),
2498 cake_id: Set(Some(4)),
2499 }
2500 );
2501
2502 assert!(fruit.clear_parent_key::<cake::Entity>().unwrap());
2503
2504 assert_eq!(
2505 fruit,
2506 fruit::ActiveModel {
2507 id: Unchanged(2),
2508 name: Unchanged("F".into()),
2509 cake_id: Set(None),
2510 }
2511 );
2512
2513 let mut cake_filling = cake_filling::ActiveModel::new();
2514
2515 cake_filling.set_parent_key(&cake).unwrap();
2516
2517 assert_eq!(
2518 cake_filling,
2519 cake_filling::ActiveModel {
2520 cake_id: Set(4),
2521 filling_id: NotSet,
2522 }
2523 );
2524 }
2525}