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