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