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
15pub trait ActiveModelTrait: Clone + Debug {
27 type Entity: EntityTrait;
29
30 fn take(&mut self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
32
33 fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
35
36 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 fn set_if_not_equals(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
44
45 fn try_set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) -> Result<(), DbErr>;
47
48 fn not_set(&mut self, c: <Self::Entity as EntityTrait>::Column);
50
51 fn is_not_set(&self, c: <Self::Entity as EntityTrait>::Column) -> bool;
53
54 fn default() -> Self;
56
57 fn default_values() -> Self;
59
60 fn reset(&mut self, c: <Self::Entity as EntityTrait>::Column);
63
64 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 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 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 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 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 #[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 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 #[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 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 *self = Self::from_json(json)?;
446
447 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 #[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 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 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 for (key, value) in obj {
497 merged.insert(key, value);
498 }
499 json = dummy_json;
500 }
501 }
502
503 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 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 #[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 #[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 #[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 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 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 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 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 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 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 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 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 #[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 #[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 #[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 #[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 #[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 #[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#[allow(unused_variables)]
1042pub trait ActiveModelBehavior: ActiveModelTrait {
1043 fn new() -> Self {
1056 <Self as ActiveModelTrait>::default()
1057 }
1058
1059 fn before_save<C>(self, db: &C, insert: bool) -> Result<Self, DbErr>
1061 where
1062 C: ConnectionTrait,
1063 {
1064 Ok(self)
1065 }
1066
1067 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 fn before_delete<C>(self, db: &C) -> Result<Self, DbErr>
1081 where
1082 C: ConnectionTrait,
1083 {
1084 Ok(self)
1085 }
1086
1087 fn after_delete<C>(self, db: &C) -> Result<Self, DbErr>
1089 where
1090 C: ConnectionTrait,
1091 {
1092 Ok(self)
1093 }
1094}
1095
1096pub trait IntoActiveModel<A>
1098where
1099 A: ActiveModelTrait,
1100{
1101 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 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 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; 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 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 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 pub name: String,
1228 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}