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