1use crate::{
2 ConnectionTrait, DeleteResult, EntityTrait, IdenStatic, Iterable, PrimaryKeyArity,
3 PrimaryKeyToColumn, PrimaryKeyTrait, Value, error::*,
4};
5use async_trait::async_trait;
6use sea_query::{Nullable, ValueTuple};
7use std::fmt::Debug;
8
9pub use ActiveValue::{NotSet, Set, Unchanged};
10
11#[derive(Clone, Debug)]
57pub enum ActiveValue<V>
58where
59 V: Into<Value>,
60{
61 Set(V),
69 Unchanged(V),
78 NotSet,
88}
89
90#[deprecated(
92 since = "0.5.0",
93 note = "Please use [`ActiveValue::NotSet`] or [`NotSet`]"
94)]
95#[allow(non_snake_case)]
96pub fn Unset<V>(_: Option<bool>) -> ActiveValue<V>
97where
98 V: Into<Value>,
99{
100 ActiveValue::not_set()
101}
102
103#[async_trait]
115pub trait ActiveModelTrait: Clone + Debug {
116 type Entity: EntityTrait;
118
119 fn take(&mut self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
121
122 fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
124
125 fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) {
127 self.try_set(c, v).unwrap_or_else(|e| {
128 panic!(
129 "Failed to set value for {}.{}: {e:?}",
130 Self::Entity::default().as_str(),
131 c.as_str()
132 )
133 })
134 }
135
136 fn try_set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) -> Result<(), DbErr>;
138
139 fn not_set(&mut self, c: <Self::Entity as EntityTrait>::Column);
141
142 fn is_not_set(&self, c: <Self::Entity as EntityTrait>::Column) -> bool;
144
145 fn default() -> Self;
147
148 fn default_values() -> Self;
150
151 fn reset(&mut self, c: <Self::Entity as EntityTrait>::Column);
154
155 fn reset_all(mut self) -> Self {
158 for col in <Self::Entity as EntityTrait>::Column::iter() {
159 self.reset(col);
160 }
161 self
162 }
163
164 #[allow(clippy::question_mark)]
170 fn get_primary_key_value(&self) -> Option<ValueTuple> {
171 let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
172 macro_rules! next {
173 () => {
174 if let Some(col) = cols.next() {
175 if let Some(val) = self.get(col.into_column()).into_value() {
176 val
177 } else {
178 return None;
179 }
180 } else {
181 return None;
182 }
183 };
184 }
185 match <<<Self::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType as PrimaryKeyArity>::ARITY {
186 1 => {
187 let s1 = next!();
188 Some(ValueTuple::One(s1))
189 }
190 2 => {
191 let s1 = next!();
192 let s2 = next!();
193 Some(ValueTuple::Two(s1, s2))
194 }
195 3 => {
196 let s1 = next!();
197 let s2 = next!();
198 let s3 = next!();
199 Some(ValueTuple::Three(s1, s2, s3))
200 }
201 len => {
202 let mut vec = Vec::with_capacity(len);
203 for _ in 0..len {
204 let s = next!();
205 vec.push(s);
206 }
207 Some(ValueTuple::Many(vec))
208 }
209 }
210 }
211
212 async fn insert<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
319 where
320 <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
321 Self: ActiveModelBehavior + 'a,
322 C: ConnectionTrait,
323 {
324 let am = ActiveModelBehavior::before_save(self, db, true).await?;
325 let model = <Self::Entity as EntityTrait>::insert(am)
326 .exec_with_returning(db)
327 .await?;
328 Self::after_save(model, db, true).await
329 }
330
331 async fn update<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
441 where
442 <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
443 Self: ActiveModelBehavior + 'a,
444 C: ConnectionTrait,
445 {
446 let am = ActiveModelBehavior::before_save(self, db, false).await?;
447 let model: <Self::Entity as EntityTrait>::Model = Self::Entity::update(am).exec(db).await?;
448 Self::after_save(model, db, false).await
449 }
450
451 async fn save<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
454 where
455 <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
456 Self: ActiveModelBehavior + 'a,
457 C: ConnectionTrait,
458 {
459 let mut is_update = true;
460 for key in <Self::Entity as EntityTrait>::PrimaryKey::iter() {
461 let col = key.into_column();
462 if self.is_not_set(col) {
463 is_update = false;
464 break;
465 }
466 }
467 let res = if !is_update {
468 self.insert(db).await
469 } else {
470 self.update(db).await
471 }?;
472 Ok(res.into_active_model())
473 }
474
475 async fn delete<'a, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
519 where
520 Self: ActiveModelBehavior + 'a,
521 C: ConnectionTrait,
522 {
523 let am = ActiveModelBehavior::before_delete(self, db).await?;
524 let am_clone = am.clone();
525 let delete_res = Self::Entity::delete(am).exec(db).await?;
526 ActiveModelBehavior::after_delete(am_clone, db).await?;
527 Ok(delete_res)
528 }
529
530 #[cfg(feature = "with-json")]
534 fn set_from_json(&mut self, json: serde_json::Value) -> Result<(), DbErr>
535 where
536 Self: crate::TryIntoModel<<Self::Entity as EntityTrait>::Model>,
537 <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
538 for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
539 serde::de::Deserialize<'de> + serde::Serialize,
540 {
541 use crate::Iterable;
542
543 let primary_key_values: Vec<(<Self::Entity as EntityTrait>::Column, ActiveValue<Value>)> =
545 <<Self::Entity as EntityTrait>::PrimaryKey>::iter()
546 .map(|pk| (pk.into_column(), self.take(pk.into_column())))
547 .collect();
548
549 *self = Self::from_json(json)?;
551
552 for (col, active_value) in primary_key_values {
554 match active_value {
555 ActiveValue::Unchanged(v) | ActiveValue::Set(v) => self.set(col, v),
556 NotSet => self.not_set(col),
557 }
558 }
559
560 Ok(())
561 }
562
563 #[cfg(feature = "with-json")]
565 fn from_json(mut json: serde_json::Value) -> Result<Self, DbErr>
566 where
567 Self: crate::TryIntoModel<<Self::Entity as EntityTrait>::Model>,
568 <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
569 for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
570 serde::de::Deserialize<'de> + serde::Serialize,
571 {
572 use crate::{IdenStatic, Iterable};
573
574 let serde_json::Value::Object(obj) = &json else {
575 return Err(DbErr::Json(format!(
576 "invalid type: expected JSON object for {}",
577 <<Self as ActiveModelTrait>::Entity as IdenStatic>::as_str(&Default::default())
578 )));
579 };
580
581 let mut json_keys: Vec<(<Self::Entity as EntityTrait>::Column, bool)> = Vec::new();
583
584 for col in <<Self::Entity as EntityTrait>::Column>::iter() {
585 let key = col.as_str();
586 let has_key = obj.contains_key(key);
587 json_keys.push((col, has_key));
588 }
589
590 let dummy_model = Self::default_values();
592 if let Ok(dummy_model) = dummy_model.try_into_model() {
593 if let Ok(mut dummy_json) = serde_json::to_value(&dummy_model) {
594 let serde_json::Value::Object(merged) = &mut dummy_json else {
595 unreachable!();
596 };
597 let serde_json::Value::Object(obj) = json else {
598 unreachable!();
599 };
600 for (key, value) in obj {
602 merged.insert(key, value);
603 }
604 json = dummy_json;
605 }
606 }
607
608 let model: <Self::Entity as EntityTrait>::Model =
610 serde_json::from_value(json).map_err(json_err)?;
611 let mut am = model.into_active_model();
612
613 for (col, json_key_exists) in json_keys {
615 match (json_key_exists, am.get(col)) {
616 (true, ActiveValue::Set(value) | ActiveValue::Unchanged(value)) => {
617 am.set(col, value);
618 }
619 _ => {
620 am.not_set(col);
621 }
622 }
623 }
624
625 Ok(am)
626 }
627
628 fn is_changed(&self) -> bool {
630 <Self::Entity as EntityTrait>::Column::iter()
631 .any(|col| self.get(col).is_set() && !self.get(col).is_unchanged())
632 }
633}
634
635#[allow(unused_variables)]
663#[async_trait]
664pub trait ActiveModelBehavior: ActiveModelTrait {
665 fn new() -> Self {
667 <Self as ActiveModelTrait>::default()
668 }
669
670 async fn before_save<C>(self, db: &C, insert: bool) -> Result<Self, DbErr>
672 where
673 C: ConnectionTrait,
674 {
675 Ok(self)
676 }
677
678 async fn after_save<C>(
680 model: <Self::Entity as EntityTrait>::Model,
681 db: &C,
682 insert: bool,
683 ) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
684 where
685 C: ConnectionTrait,
686 {
687 Ok(model)
688 }
689
690 async fn before_delete<C>(self, db: &C) -> Result<Self, DbErr>
692 where
693 C: ConnectionTrait,
694 {
695 Ok(self)
696 }
697
698 async fn after_delete<C>(self, db: &C) -> Result<Self, DbErr>
700 where
701 C: ConnectionTrait,
702 {
703 Ok(self)
704 }
705}
706
707pub trait IntoActiveModel<A>
709where
710 A: ActiveModelTrait,
711{
712 fn into_active_model(self) -> A;
714}
715
716impl<A> IntoActiveModel<A> for A
717where
718 A: ActiveModelTrait,
719{
720 fn into_active_model(self) -> A {
721 self
722 }
723}
724
725pub trait IntoActiveValue<V>
727where
728 V: Into<Value>,
729{
730 fn into_active_value(self) -> ActiveValue<V>;
732}
733
734impl<V> IntoActiveValue<Option<V>> for Option<V>
735where
736 V: IntoActiveValue<V> + Into<Value> + Nullable,
737{
738 fn into_active_value(self) -> ActiveValue<Option<V>> {
739 match self {
740 Some(value) => Set(Some(value)),
741 None => NotSet,
742 }
743 }
744}
745
746impl<V> IntoActiveValue<Option<V>> for Option<Option<V>>
747where
748 V: IntoActiveValue<V> + Into<Value> + Nullable,
749{
750 fn into_active_value(self) -> ActiveValue<Option<V>> {
751 match self {
752 Some(value) => Set(value),
753 None => NotSet,
754 }
755 }
756}
757
758macro_rules! impl_into_active_value {
759 ($ty: ty) => {
760 impl IntoActiveValue<$ty> for $ty {
761 fn into_active_value(self) -> ActiveValue<$ty> {
762 Set(self)
763 }
764 }
765 };
766}
767
768impl_into_active_value!(bool);
769impl_into_active_value!(i8);
770impl_into_active_value!(i16);
771impl_into_active_value!(i32);
772impl_into_active_value!(i64);
773impl_into_active_value!(u8);
774impl_into_active_value!(u16);
775impl_into_active_value!(u32);
776impl_into_active_value!(u64);
777impl_into_active_value!(f32);
778impl_into_active_value!(f64);
779impl_into_active_value!(&'static str);
780impl_into_active_value!(String);
781impl_into_active_value!(Vec<u8>);
782
783#[cfg(feature = "with-json")]
784#[cfg_attr(docsrs, doc(cfg(feature = "with-json")))]
785impl_into_active_value!(crate::prelude::Json);
786
787#[cfg(feature = "with-chrono")]
788#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
789impl_into_active_value!(crate::prelude::Date);
790
791#[cfg(feature = "with-chrono")]
792#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
793impl_into_active_value!(crate::prelude::Time);
794
795#[cfg(feature = "with-chrono")]
796#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
797impl_into_active_value!(crate::prelude::DateTime);
798
799#[cfg(feature = "with-chrono")]
800#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
801impl_into_active_value!(crate::prelude::DateTimeWithTimeZone);
802
803#[cfg(feature = "with-chrono")]
804#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
805impl_into_active_value!(crate::prelude::DateTimeUtc);
806
807#[cfg(feature = "with-chrono")]
808#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
809impl_into_active_value!(crate::prelude::DateTimeLocal);
810
811#[cfg(feature = "with-rust_decimal")]
812#[cfg_attr(docsrs, doc(cfg(feature = "with-rust_decimal")))]
813impl_into_active_value!(crate::prelude::Decimal);
814
815#[cfg(feature = "with-uuid")]
816#[cfg_attr(docsrs, doc(cfg(feature = "with-uuid")))]
817impl_into_active_value!(crate::prelude::Uuid);
818
819#[cfg(feature = "with-time")]
820#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
821impl_into_active_value!(crate::prelude::TimeDate);
822
823#[cfg(feature = "with-time")]
824#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
825impl_into_active_value!(crate::prelude::TimeTime);
826
827#[cfg(feature = "with-time")]
828#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
829impl_into_active_value!(crate::prelude::TimeDateTime);
830
831#[cfg(feature = "with-time")]
832#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
833impl_into_active_value!(crate::prelude::TimeDateTimeWithTimeZone);
834
835#[cfg(feature = "with-ipnetwork")]
836#[cfg_attr(docsrs, doc(cfg(feature = "with-ipnetwork")))]
837impl_into_active_value!(crate::prelude::IpNetwork);
838
839impl<V> Default for ActiveValue<V>
840where
841 V: Into<Value>,
842{
843 fn default() -> Self {
845 Self::NotSet
846 }
847}
848
849impl<V> ActiveValue<V>
850where
851 V: Into<Value>,
852{
853 pub fn set(value: V) -> Self {
855 Self::Set(value)
856 }
857
858 pub fn is_set(&self) -> bool {
860 matches!(self, Self::Set(_))
861 }
862
863 pub fn unchanged(value: V) -> Self {
865 Self::Unchanged(value)
866 }
867
868 pub fn is_unchanged(&self) -> bool {
870 matches!(self, Self::Unchanged(_))
871 }
872
873 pub fn not_set() -> Self {
875 Self::default()
876 }
877
878 pub fn is_not_set(&self) -> bool {
880 matches!(self, Self::NotSet)
881 }
882
883 pub fn take(&mut self) -> Option<V> {
886 match std::mem::take(self) {
887 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value),
888 ActiveValue::NotSet => None,
889 }
890 }
891
892 pub fn unwrap(self) -> V {
898 match self {
899 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
900 ActiveValue::NotSet => panic!("Cannot unwrap ActiveValue::NotSet"),
901 }
902 }
903
904 pub fn into_value(self) -> Option<Value> {
906 match self {
907 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value.into()),
908 ActiveValue::NotSet => None,
909 }
910 }
911
912 pub fn into_wrapped_value(self) -> ActiveValue<Value> {
914 match self {
915 Self::Set(value) => ActiveValue::set(value.into()),
916 Self::Unchanged(value) => ActiveValue::unchanged(value.into()),
917 Self::NotSet => ActiveValue::not_set(),
918 }
919 }
920
921 pub fn reset(&mut self) {
924 *self = match self.take() {
925 Some(value) => ActiveValue::Set(value),
926 None => ActiveValue::NotSet,
927 };
928 }
929
930 pub fn set_if_not_equals(&mut self, value: V)
958 where
959 V: PartialEq,
960 {
961 match self {
962 ActiveValue::Unchanged(current) if &value == current => {}
963 _ => *self = ActiveValue::Set(value),
964 }
965 }
966
967 pub fn try_as_ref(&self) -> Option<&V> {
981 match self {
982 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value),
983 ActiveValue::NotSet => None,
984 }
985 }
986}
987
988impl<V> std::convert::AsRef<V> for ActiveValue<V>
989where
990 V: Into<Value>,
991{
992 fn as_ref(&self) -> &V {
998 match self {
999 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
1000 ActiveValue::NotSet => panic!("Cannot borrow ActiveValue::NotSet"),
1001 }
1002 }
1003}
1004
1005impl<V> PartialEq for ActiveValue<V>
1006where
1007 V: Into<Value> + std::cmp::PartialEq,
1008{
1009 fn eq(&self, other: &Self) -> bool {
1010 match (self, other) {
1011 (ActiveValue::Set(l), ActiveValue::Set(r)) => l == r,
1012 (ActiveValue::Unchanged(l), ActiveValue::Unchanged(r)) => l == r,
1013 (ActiveValue::NotSet, ActiveValue::NotSet) => true,
1014 _ => false,
1015 }
1016 }
1017}
1018
1019impl<V> From<ActiveValue<V>> for ActiveValue<Option<V>>
1020where
1021 V: Into<Value> + Nullable,
1022{
1023 fn from(value: ActiveValue<V>) -> Self {
1024 match value {
1025 ActiveValue::Set(value) => ActiveValue::set(Some(value)),
1026 ActiveValue::Unchanged(value) => ActiveValue::unchanged(Some(value)),
1027 ActiveValue::NotSet => ActiveValue::not_set(),
1028 }
1029 }
1030}
1031
1032#[cfg(test)]
1033mod tests {
1034 use crate::{DbErr, entity::*, tests_cfg::*};
1035 use pretty_assertions::assert_eq;
1036
1037 #[cfg(feature = "with-json")]
1038 use serde_json::json;
1039
1040 #[test]
1041 #[cfg(feature = "macros")]
1042 fn test_derive_into_active_model_1() {
1043 mod my_fruit {
1044 pub use super::fruit::*;
1045 use crate as sea_orm;
1046 use crate::entity::prelude::*;
1047
1048 #[derive(DeriveIntoActiveModel)]
1049 pub struct NewFruit {
1050 pub name: String,
1052 pub cake_id: i32,
1054 }
1055 }
1056
1057 assert_eq!(
1058 my_fruit::NewFruit {
1059 name: "Apple".to_owned(),
1060 cake_id: 1,
1061 }
1062 .into_active_model(),
1063 fruit::ActiveModel {
1064 id: NotSet,
1065 name: Set("Apple".to_owned()),
1066 cake_id: Set(Some(1)),
1067 }
1068 );
1069 }
1070
1071 #[test]
1072 #[cfg(feature = "macros")]
1073 fn test_derive_into_active_model_2() {
1074 use crate as sea_orm;
1075 use crate::entity::prelude::*;
1076
1077 #[derive(DeriveIntoActiveModel)]
1078 #[sea_orm(active_model = "fruit::ActiveModel")]
1079 struct FruitName {
1080 name: String,
1081 }
1082
1083 assert_eq!(
1084 FruitName {
1085 name: "Apple Pie".to_owned(),
1086 }
1087 .into_active_model(),
1088 fruit::ActiveModel {
1089 id: NotSet,
1090 name: Set("Apple Pie".to_owned()),
1091 cake_id: NotSet,
1092 }
1093 );
1094
1095 #[derive(DeriveIntoActiveModel)]
1096 #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
1097 struct FruitCake {
1098 cake_id: Option<Option<i32>>,
1099 }
1100
1101 assert_eq!(
1102 FruitCake {
1103 cake_id: Some(Some(1)),
1104 }
1105 .into_active_model(),
1106 fruit::ActiveModel {
1107 id: NotSet,
1108 name: NotSet,
1109 cake_id: Set(Some(1)),
1110 }
1111 );
1112
1113 assert_eq!(
1114 FruitCake {
1115 cake_id: Some(None),
1116 }
1117 .into_active_model(),
1118 fruit::ActiveModel {
1119 id: NotSet,
1120 name: NotSet,
1121 cake_id: Set(None),
1122 }
1123 );
1124
1125 assert_eq!(
1126 FruitCake { cake_id: None }.into_active_model(),
1127 fruit::ActiveModel {
1128 id: NotSet,
1129 name: NotSet,
1130 cake_id: NotSet,
1131 }
1132 );
1133 }
1134
1135 #[test]
1136 #[cfg(feature = "macros")]
1137 fn test_derive_try_into_model_1() {
1138 mod my_fruit {
1139 use crate as sea_orm;
1140 use crate::entity::prelude::*;
1141
1142 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1143 #[sea_orm(table_name = "fruit")]
1144 pub struct Model {
1145 #[sea_orm(primary_key)]
1146 pub id: i32,
1147 pub name: String,
1148 pub cake_id: Option<i32>,
1149 }
1150
1151 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1152 pub enum Relation {}
1153
1154 impl ActiveModelBehavior for ActiveModel {}
1155 }
1156 assert_eq!(
1157 my_fruit::ActiveModel {
1158 id: Set(1),
1159 name: Set("Pineapple".to_owned()),
1160 cake_id: Set(None),
1161 }
1162 .try_into_model()
1163 .unwrap(),
1164 my_fruit::Model {
1165 id: 1,
1166 name: "Pineapple".to_owned(),
1167 cake_id: None,
1168 }
1169 );
1170
1171 assert_eq!(
1172 my_fruit::ActiveModel {
1173 id: Set(2),
1174 name: Set("Apple".to_owned()),
1175 cake_id: Set(Some(1)),
1176 }
1177 .try_into_model()
1178 .unwrap(),
1179 my_fruit::Model {
1180 id: 2,
1181 name: "Apple".to_owned(),
1182 cake_id: Some(1),
1183 }
1184 );
1185
1186 assert_eq!(
1187 my_fruit::ActiveModel {
1188 id: Set(1),
1189 name: NotSet,
1190 cake_id: Set(None),
1191 }
1192 .try_into_model(),
1193 Err(DbErr::AttrNotSet(String::from("name")))
1194 );
1195
1196 assert_eq!(
1197 my_fruit::ActiveModel {
1198 id: Set(1),
1199 name: Set("Pineapple".to_owned()),
1200 cake_id: NotSet,
1201 }
1202 .try_into_model(),
1203 Err(DbErr::AttrNotSet(String::from("cake_id")))
1204 );
1205 }
1206
1207 #[test]
1208 #[cfg(feature = "macros")]
1209 fn test_derive_try_into_model_2() {
1210 mod my_fruit {
1211 use crate as sea_orm;
1212 use crate::entity::prelude::*;
1213
1214 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1215 #[sea_orm(table_name = "fruit")]
1216 pub struct Model {
1217 #[sea_orm(primary_key)]
1218 pub id: i32,
1219 pub name: String,
1220 #[sea_orm(ignore)]
1221 pub cake_id: Option<i32>,
1222 }
1223
1224 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1225 pub enum Relation {}
1226
1227 impl ActiveModelBehavior for ActiveModel {}
1228 }
1229 assert_eq!(
1230 my_fruit::ActiveModel {
1231 id: Set(1),
1232 name: Set("Pineapple".to_owned()),
1233 }
1234 .try_into_model()
1235 .unwrap(),
1236 my_fruit::Model {
1237 id: 1,
1238 name: "Pineapple".to_owned(),
1239 cake_id: None,
1240 }
1241 );
1242 }
1243
1244 #[test]
1245 #[cfg(feature = "macros")]
1246 fn test_derive_try_into_model_3() {
1247 mod my_fruit {
1248 use crate as sea_orm;
1249 use crate::entity::prelude::*;
1250
1251 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1252 #[sea_orm(table_name = "fruit")]
1253 pub struct Model {
1254 #[sea_orm(primary_key)]
1255 pub id: i32,
1256 #[sea_orm(ignore)]
1257 pub name: String,
1258 pub cake_id: Option<i32>,
1259 }
1260
1261 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1262 pub enum Relation {}
1263
1264 impl ActiveModelBehavior for ActiveModel {}
1265 }
1266 assert_eq!(
1267 my_fruit::ActiveModel {
1268 id: Set(1),
1269 cake_id: Set(Some(1)),
1270 }
1271 .try_into_model()
1272 .unwrap(),
1273 my_fruit::Model {
1274 id: 1,
1275 name: "".to_owned(),
1276 cake_id: Some(1),
1277 }
1278 );
1279 }
1280
1281 #[test]
1282 #[cfg(feature = "with-json")]
1283 fn test_active_model_set_from_json_1() {
1284 assert_eq!(
1285 cake::ActiveModel::from_json(json!({
1286 "id": 1,
1287 "name": "Apple Pie",
1288 }))
1289 .unwrap(),
1290 cake::ActiveModel {
1291 id: Set(1),
1292 name: Set("Apple Pie".to_owned()),
1293 }
1294 );
1295
1296 assert_eq!(
1297 cake::ActiveModel::from_json(json!({
1298 "id": 1,
1299 }))
1300 .unwrap(),
1301 cake::ActiveModel {
1302 id: Set(1),
1303 name: NotSet,
1304 }
1305 );
1306
1307 assert_eq!(
1308 cake::ActiveModel::from_json(json!({
1309 "name": "Apple Pie",
1310 }))
1311 .unwrap(),
1312 cake::ActiveModel {
1313 id: NotSet,
1314 name: Set("Apple Pie".to_owned()),
1315 }
1316 );
1317
1318 let mut cake: cake::ActiveModel = Default::default();
1319 cake.set_from_json(json!({
1320 "name": "Apple Pie",
1321 }))
1322 .unwrap();
1323 assert_eq!(
1324 cake,
1325 cake::ActiveModel {
1326 id: NotSet,
1327 name: Set("Apple Pie".to_owned()),
1328 }
1329 );
1330 }
1331
1332 #[test]
1333 #[cfg(feature = "with-json")]
1334 fn test_active_model_set_from_json_2() -> Result<(), DbErr> {
1335 let mut fruit: fruit::ActiveModel = Default::default();
1336
1337 fruit.set_from_json(json!({
1338 "name": "Apple",
1339 }))?;
1340 assert_eq!(
1341 fruit,
1342 fruit::ActiveModel {
1343 id: ActiveValue::NotSet,
1344 name: ActiveValue::Set("Apple".to_owned()),
1345 cake_id: ActiveValue::NotSet,
1346 }
1347 );
1348
1349 assert_eq!(
1350 fruit::ActiveModel::from_json(json!({
1351 "name": "Apple",
1352 }))?,
1353 fruit::ActiveModel {
1354 id: ActiveValue::NotSet,
1355 name: ActiveValue::Set("Apple".to_owned()),
1356 cake_id: ActiveValue::NotSet,
1357 }
1358 );
1359
1360 fruit.set_from_json(json!({
1361 "name": "Apple",
1362 "cake_id": null,
1363 }))?;
1364 assert_eq!(
1365 fruit,
1366 fruit::ActiveModel {
1367 id: ActiveValue::NotSet,
1368 name: ActiveValue::Set("Apple".to_owned()),
1369 cake_id: ActiveValue::Set(None),
1370 }
1371 );
1372
1373 fruit.set_from_json(json!({
1374 "id": null,
1375 "name": "Apple",
1376 "cake_id": 1,
1377 }))?;
1378 assert_eq!(
1379 fruit,
1380 fruit::ActiveModel {
1381 id: ActiveValue::NotSet,
1382 name: ActiveValue::Set("Apple".to_owned()),
1383 cake_id: ActiveValue::Set(Some(1)),
1384 }
1385 );
1386
1387 fruit.set_from_json(json!({
1388 "id": 2,
1389 "name": "Apple",
1390 "cake_id": 1,
1391 }))?;
1392 assert_eq!(
1393 fruit,
1394 fruit::ActiveModel {
1395 id: ActiveValue::NotSet,
1396 name: ActiveValue::Set("Apple".to_owned()),
1397 cake_id: ActiveValue::Set(Some(1)),
1398 }
1399 );
1400
1401 let mut fruit = fruit::ActiveModel {
1402 id: ActiveValue::Set(1),
1403 name: ActiveValue::NotSet,
1404 cake_id: ActiveValue::NotSet,
1405 };
1406 fruit.set_from_json(json!({
1407 "id": 8,
1408 "name": "Apple",
1409 "cake_id": 1,
1410 }))?;
1411 assert_eq!(
1412 fruit,
1413 fruit::ActiveModel {
1414 id: ActiveValue::Set(1),
1415 name: ActiveValue::Set("Apple".to_owned()),
1416 cake_id: ActiveValue::Set(Some(1)),
1417 }
1418 );
1419
1420 Ok(())
1421 }
1422
1423 #[smol_potat::test]
1424 #[cfg(feature = "with-json")]
1425 async fn test_active_model_set_from_json_3() -> Result<(), DbErr> {
1426 use crate::*;
1427
1428 let db = MockDatabase::new(DbBackend::Postgres)
1429 .append_exec_results([
1430 MockExecResult {
1431 last_insert_id: 1,
1432 rows_affected: 1,
1433 },
1434 MockExecResult {
1435 last_insert_id: 1,
1436 rows_affected: 1,
1437 },
1438 ])
1439 .append_query_results([
1440 [fruit::Model {
1441 id: 1,
1442 name: "Apple".to_owned(),
1443 cake_id: None,
1444 }],
1445 [fruit::Model {
1446 id: 2,
1447 name: "Orange".to_owned(),
1448 cake_id: Some(1),
1449 }],
1450 ])
1451 .into_connection();
1452
1453 let mut fruit: fruit::ActiveModel = Default::default();
1454 fruit.set_from_json(json!({
1455 "name": "Apple",
1456 }))?;
1457 fruit.save(&db).await?;
1458
1459 let mut fruit = fruit::ActiveModel {
1460 id: Set(2),
1461 ..Default::default()
1462 };
1463 fruit.set_from_json(json!({
1464 "id": 9,
1465 "name": "Orange",
1466 "cake_id": 1,
1467 }))?;
1468 fruit.save(&db).await?;
1469
1470 assert_eq!(
1471 db.into_transaction_log(),
1472 [
1473 Transaction::from_sql_and_values(
1474 DbBackend::Postgres,
1475 r#"INSERT INTO "fruit" ("name") VALUES ($1) RETURNING "id", "name", "cake_id""#,
1476 ["Apple".into()],
1477 ),
1478 Transaction::from_sql_and_values(
1479 DbBackend::Postgres,
1480 r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
1481 ["Orange".into(), 1i32.into(), 2i32.into()],
1482 ),
1483 ]
1484 );
1485
1486 Ok(())
1487 }
1488
1489 #[test]
1490 fn test_active_model_is_changed() {
1491 let mut fruit: fruit::ActiveModel = Default::default();
1492 assert!(!fruit.is_changed());
1493
1494 fruit.set(fruit::Column::Name, "apple".into());
1495 assert!(fruit.is_changed());
1496 }
1497
1498 #[test]
1499 fn test_reset_1() {
1500 assert_eq!(
1501 fruit::Model {
1502 id: 1,
1503 name: "Apple".into(),
1504 cake_id: None,
1505 }
1506 .into_active_model(),
1507 fruit::ActiveModel {
1508 id: Unchanged(1),
1509 name: Unchanged("Apple".into()),
1510 cake_id: Unchanged(None)
1511 },
1512 );
1513
1514 assert_eq!(
1515 fruit::Model {
1516 id: 1,
1517 name: "Apple".into(),
1518 cake_id: None,
1519 }
1520 .into_active_model()
1521 .reset_all(),
1522 fruit::ActiveModel {
1523 id: Set(1),
1524 name: Set("Apple".into()),
1525 cake_id: Set(None)
1526 },
1527 );
1528
1529 assert_eq!(
1530 fruit::Model {
1531 id: 1,
1532 name: "Apple".into(),
1533 cake_id: Some(2),
1534 }
1535 .into_active_model(),
1536 fruit::ActiveModel {
1537 id: Unchanged(1),
1538 name: Unchanged("Apple".into()),
1539 cake_id: Unchanged(Some(2)),
1540 },
1541 );
1542
1543 assert_eq!(
1544 fruit::Model {
1545 id: 1,
1546 name: "Apple".into(),
1547 cake_id: Some(2),
1548 }
1549 .into_active_model()
1550 .reset_all(),
1551 fruit::ActiveModel {
1552 id: Set(1),
1553 name: Set("Apple".into()),
1554 cake_id: Set(Some(2)),
1555 },
1556 );
1557 }
1558
1559 #[smol_potat::test]
1560 async fn test_reset_2() -> Result<(), DbErr> {
1561 use crate::*;
1562
1563 let db = MockDatabase::new(DbBackend::Postgres)
1564 .append_exec_results(vec![
1565 MockExecResult {
1566 last_insert_id: 1,
1567 rows_affected: 1,
1568 },
1569 MockExecResult {
1570 last_insert_id: 1,
1571 rows_affected: 1,
1572 },
1573 ])
1574 .append_query_results(vec![
1575 vec![fruit::Model {
1576 id: 1,
1577 name: "Apple".to_owned(),
1578 cake_id: None,
1579 }],
1580 vec![fruit::Model {
1581 id: 1,
1582 name: "Apple".to_owned(),
1583 cake_id: None,
1584 }],
1585 ])
1586 .into_connection();
1587
1588 fruit::Model {
1589 id: 1,
1590 name: "Apple".into(),
1591 cake_id: None,
1592 }
1593 .into_active_model()
1594 .update(&db)
1595 .await?;
1596
1597 fruit::Model {
1598 id: 1,
1599 name: "Apple".into(),
1600 cake_id: None,
1601 }
1602 .into_active_model()
1603 .reset_all()
1604 .update(&db)
1605 .await?;
1606
1607 assert_eq!(
1608 db.into_transaction_log(),
1609 vec![
1610 Transaction::from_sql_and_values(
1611 DbBackend::Postgres,
1612 r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit" WHERE "fruit"."id" = $1 LIMIT $2"#,
1613 vec![1i32.into(), 1u64.into()],
1614 ),
1615 Transaction::from_sql_and_values(
1616 DbBackend::Postgres,
1617 r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
1618 vec!["Apple".into(), Option::<i32>::None.into(), 1i32.into()],
1619 ),
1620 ]
1621 );
1622
1623 Ok(())
1624 }
1625
1626 #[test]
1627 fn test_active_model_default_values() {
1628 assert_eq!(
1629 fruit::ActiveModel::default_values(),
1630 fruit::ActiveModel {
1631 id: Set(0),
1632 name: Set("".into()),
1633 cake_id: Set(None),
1634 },
1635 );
1636
1637 assert_eq!(
1638 lunch_set::ActiveModel::default_values(),
1639 lunch_set::ActiveModel {
1640 id: Set(0),
1641 name: Set("".into()),
1642 tea: NotSet,
1643 },
1644 );
1645 }
1646}