1use crate::{
2 error::*, ConnectionTrait, DeleteResult, EntityTrait, Iterable, PrimaryKeyArity,
3 PrimaryKeyToColumn, PrimaryKeyTrait, Value,
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)]
40pub enum ActiveValue<V>
41where
42 V: Into<Value>,
43{
44 Set(V),
46 Unchanged(V),
48 NotSet,
50}
51
52#[deprecated(
54 since = "0.5.0",
55 note = "Please use [`ActiveValue::NotSet`] or [`NotSet`]"
56)]
57#[allow(non_snake_case)]
58pub fn Unset<V>(_: Option<bool>) -> ActiveValue<V>
59where
60 V: Into<Value>,
61{
62 ActiveValue::not_set()
63}
64
65#[async_trait]
69pub trait ActiveModelTrait: Clone + Debug {
70 type Entity: EntityTrait;
72
73 fn take(&mut self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
75
76 fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
78
79 fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) {
81 self.try_set(c, v).unwrap()
82 }
83
84 fn try_set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) -> Result<(), DbErr> {
91 self.set(c, v);
92 Ok(())
93 }
94
95 fn not_set(&mut self, c: <Self::Entity as EntityTrait>::Column);
97
98 fn is_not_set(&self, c: <Self::Entity as EntityTrait>::Column) -> bool;
100
101 fn default() -> Self;
103
104 fn default_values() -> Self;
106
107 fn reset(&mut self, c: <Self::Entity as EntityTrait>::Column);
110
111 fn reset_all(mut self) -> Self {
114 for col in <Self::Entity as EntityTrait>::Column::iter() {
115 self.reset(col);
116 }
117 self
118 }
119
120 #[allow(clippy::question_mark)]
126 fn get_primary_key_value(&self) -> Option<ValueTuple> {
127 let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
128 macro_rules! next {
129 () => {
130 if let Some(col) = cols.next() {
131 if let Some(val) = self.get(col.into_column()).into_value() {
132 val
133 } else {
134 return None;
135 }
136 } else {
137 return None;
138 }
139 };
140 }
141 match <<<Self::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType as PrimaryKeyArity>::ARITY {
142 1 => {
143 let s1 = next!();
144 Some(ValueTuple::One(s1))
145 }
146 2 => {
147 let s1 = next!();
148 let s2 = next!();
149 Some(ValueTuple::Two(s1, s2))
150 }
151 3 => {
152 let s1 = next!();
153 let s2 = next!();
154 let s3 = next!();
155 Some(ValueTuple::Three(s1, s2, s3))
156 }
157 len => {
158 let mut vec = Vec::with_capacity(len);
159 for _ in 0..len {
160 let s = next!();
161 vec.push(s);
162 }
163 Some(ValueTuple::Many(vec))
164 }
165 }
166 }
167
168 async fn insert<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
275 where
276 <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
277 Self: ActiveModelBehavior + 'a,
278 C: ConnectionTrait,
279 {
280 let am = ActiveModelBehavior::before_save(self, db, true).await?;
281 let model = <Self::Entity as EntityTrait>::insert(am)
282 .exec_with_returning(db)
283 .await?;
284 Self::after_save(model, db, true).await
285 }
286
287 async fn update<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
397 where
398 <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
399 Self: ActiveModelBehavior + 'a,
400 C: ConnectionTrait,
401 {
402 let am = ActiveModelBehavior::before_save(self, db, false).await?;
403 let model: <Self::Entity as EntityTrait>::Model = Self::Entity::update(am).exec(db).await?;
404 Self::after_save(model, db, false).await
405 }
406
407 async fn save<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
410 where
411 <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
412 Self: ActiveModelBehavior + 'a,
413 C: ConnectionTrait,
414 {
415 let mut is_update = true;
416 for key in <Self::Entity as EntityTrait>::PrimaryKey::iter() {
417 let col = key.into_column();
418 if self.is_not_set(col) {
419 is_update = false;
420 break;
421 }
422 }
423 let res = if !is_update {
424 self.insert(db).await
425 } else {
426 self.update(db).await
427 }?;
428 Ok(res.into_active_model())
429 }
430
431 async fn delete<'a, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
475 where
476 Self: ActiveModelBehavior + 'a,
477 C: ConnectionTrait,
478 {
479 let am = ActiveModelBehavior::before_delete(self, db).await?;
480 let am_clone = am.clone();
481 let delete_res = Self::Entity::delete(am).exec(db).await?;
482 ActiveModelBehavior::after_delete(am_clone, db).await?;
483 Ok(delete_res)
484 }
485
486 #[cfg(feature = "with-json")]
490 fn set_from_json(&mut self, json: serde_json::Value) -> Result<(), DbErr>
491 where
492 <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
493 for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
494 serde::de::Deserialize<'de>,
495 {
496 use crate::Iterable;
497
498 let primary_key_values: Vec<(<Self::Entity as EntityTrait>::Column, ActiveValue<Value>)> =
500 <<Self::Entity as EntityTrait>::PrimaryKey>::iter()
501 .map(|pk| (pk.into_column(), self.take(pk.into_column())))
502 .collect();
503
504 *self = Self::from_json(json)?;
506
507 for (col, active_value) in primary_key_values {
509 match active_value {
510 ActiveValue::Unchanged(v) | ActiveValue::Set(v) => self.set(col, v),
511 NotSet => self.not_set(col),
512 }
513 }
514
515 Ok(())
516 }
517
518 #[cfg(feature = "with-json")]
520 fn from_json(json: serde_json::Value) -> Result<Self, DbErr>
521 where
522 <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
523 for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
524 serde::de::Deserialize<'de>,
525 {
526 use crate::{IdenStatic, Iterable};
527
528 let serde_json::Value::Object(obj) = &json else {
529 return Err(DbErr::Json(format!(
530 "invalid type: expected JSON object for {}",
531 <<Self as ActiveModelTrait>::Entity as IdenStatic>::as_str(&Default::default())
532 )));
533 };
534
535 let mut json_keys: Vec<(<Self::Entity as EntityTrait>::Column, bool)> = Vec::new();
537
538 for col in <<Self::Entity as EntityTrait>::Column>::iter() {
539 let key = col.as_str();
540 let has_key = obj.contains_key(key);
541 json_keys.push((col, has_key));
542 }
543
544 let model: <Self::Entity as EntityTrait>::Model =
546 serde_json::from_value(json).map_err(json_err)?;
547 let mut am = model.into_active_model();
548
549 for (col, json_key_exists) in json_keys {
551 match (json_key_exists, am.get(col)) {
552 (true, ActiveValue::Set(value) | ActiveValue::Unchanged(value)) => {
553 am.set(col, value);
554 }
555 _ => {
556 am.not_set(col);
557 }
558 }
559 }
560
561 Ok(am)
562 }
563
564 fn is_changed(&self) -> bool {
566 <Self::Entity as EntityTrait>::Column::iter()
567 .any(|col| self.get(col).is_set() && !self.get(col).is_unchanged())
568 }
569}
570
571#[allow(unused_variables)]
599#[async_trait]
600pub trait ActiveModelBehavior: ActiveModelTrait {
601 fn new() -> Self {
603 <Self as ActiveModelTrait>::default()
604 }
605
606 async fn before_save<C>(self, db: &C, insert: bool) -> Result<Self, DbErr>
608 where
609 C: ConnectionTrait,
610 {
611 Ok(self)
612 }
613
614 async fn after_save<C>(
616 model: <Self::Entity as EntityTrait>::Model,
617 db: &C,
618 insert: bool,
619 ) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
620 where
621 C: ConnectionTrait,
622 {
623 Ok(model)
624 }
625
626 async fn before_delete<C>(self, db: &C) -> Result<Self, DbErr>
628 where
629 C: ConnectionTrait,
630 {
631 Ok(self)
632 }
633
634 async fn after_delete<C>(self, db: &C) -> Result<Self, DbErr>
636 where
637 C: ConnectionTrait,
638 {
639 Ok(self)
640 }
641}
642
643pub trait IntoActiveModel<A>
645where
646 A: ActiveModelTrait,
647{
648 fn into_active_model(self) -> A;
650}
651
652impl<A> IntoActiveModel<A> for A
653where
654 A: ActiveModelTrait,
655{
656 fn into_active_model(self) -> A {
657 self
658 }
659}
660
661pub trait IntoActiveValue<V>
663where
664 V: Into<Value>,
665{
666 fn into_active_value(self) -> ActiveValue<V>;
668}
669
670impl<V> IntoActiveValue<Option<V>> for Option<V>
671where
672 V: IntoActiveValue<V> + Into<Value> + Nullable,
673{
674 fn into_active_value(self) -> ActiveValue<Option<V>> {
675 match self {
676 Some(value) => Set(Some(value)),
677 None => NotSet,
678 }
679 }
680}
681
682impl<V> IntoActiveValue<Option<V>> for Option<Option<V>>
683where
684 V: IntoActiveValue<V> + Into<Value> + Nullable,
685{
686 fn into_active_value(self) -> ActiveValue<Option<V>> {
687 match self {
688 Some(value) => Set(value),
689 None => NotSet,
690 }
691 }
692}
693
694macro_rules! impl_into_active_value {
695 ($ty: ty) => {
696 impl IntoActiveValue<$ty> for $ty {
697 fn into_active_value(self) -> ActiveValue<$ty> {
698 Set(self)
699 }
700 }
701 };
702}
703
704impl_into_active_value!(bool);
705impl_into_active_value!(i8);
706impl_into_active_value!(i16);
707impl_into_active_value!(i32);
708impl_into_active_value!(i64);
709impl_into_active_value!(u8);
710impl_into_active_value!(u16);
711impl_into_active_value!(u32);
712impl_into_active_value!(u64);
713impl_into_active_value!(f32);
714impl_into_active_value!(f64);
715impl_into_active_value!(&'static str);
716impl_into_active_value!(String);
717impl_into_active_value!(Vec<u8>);
718
719#[cfg(feature = "with-json")]
720#[cfg_attr(docsrs, doc(cfg(feature = "with-json")))]
721impl_into_active_value!(crate::prelude::Json);
722
723#[cfg(feature = "with-chrono")]
724#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
725impl_into_active_value!(crate::prelude::Date);
726
727#[cfg(feature = "with-chrono")]
728#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
729impl_into_active_value!(crate::prelude::Time);
730
731#[cfg(feature = "with-chrono")]
732#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
733impl_into_active_value!(crate::prelude::DateTime);
734
735#[cfg(feature = "with-chrono")]
736#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
737impl_into_active_value!(crate::prelude::DateTimeWithTimeZone);
738
739#[cfg(feature = "with-chrono")]
740#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
741impl_into_active_value!(crate::prelude::DateTimeUtc);
742
743#[cfg(feature = "with-chrono")]
744#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
745impl_into_active_value!(crate::prelude::DateTimeLocal);
746
747#[cfg(feature = "with-rust_decimal")]
748#[cfg_attr(docsrs, doc(cfg(feature = "with-rust_decimal")))]
749impl_into_active_value!(crate::prelude::Decimal);
750
751#[cfg(feature = "with-uuid")]
752#[cfg_attr(docsrs, doc(cfg(feature = "with-uuid")))]
753impl_into_active_value!(crate::prelude::Uuid);
754
755#[cfg(feature = "with-time")]
756#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
757impl_into_active_value!(crate::prelude::TimeDate);
758
759#[cfg(feature = "with-time")]
760#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
761impl_into_active_value!(crate::prelude::TimeTime);
762
763#[cfg(feature = "with-time")]
764#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
765impl_into_active_value!(crate::prelude::TimeDateTime);
766
767#[cfg(feature = "with-time")]
768#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
769impl_into_active_value!(crate::prelude::TimeDateTimeWithTimeZone);
770
771#[cfg(feature = "with-ipnetwork")]
772#[cfg_attr(docsrs, doc(cfg(feature = "with-ipnetwork")))]
773impl_into_active_value!(crate::prelude::IpNetwork);
774
775impl<V> Default for ActiveValue<V>
776where
777 V: Into<Value>,
778{
779 fn default() -> Self {
781 Self::NotSet
782 }
783}
784
785impl<V> ActiveValue<V>
786where
787 V: Into<Value>,
788{
789 pub fn set(value: V) -> Self {
791 Self::Set(value)
792 }
793
794 pub fn is_set(&self) -> bool {
796 matches!(self, Self::Set(_))
797 }
798
799 pub fn unchanged(value: V) -> Self {
801 Self::Unchanged(value)
802 }
803
804 pub fn is_unchanged(&self) -> bool {
806 matches!(self, Self::Unchanged(_))
807 }
808
809 pub fn not_set() -> Self {
811 Self::default()
812 }
813
814 pub fn is_not_set(&self) -> bool {
816 matches!(self, Self::NotSet)
817 }
818
819 pub fn take(&mut self) -> Option<V> {
822 match std::mem::take(self) {
823 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value),
824 ActiveValue::NotSet => None,
825 }
826 }
827
828 pub fn unwrap(self) -> V {
834 match self {
835 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
836 ActiveValue::NotSet => panic!("Cannot unwrap ActiveValue::NotSet"),
837 }
838 }
839
840 pub fn into_value(self) -> Option<Value> {
842 match self {
843 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value.into()),
844 ActiveValue::NotSet => None,
845 }
846 }
847
848 pub fn into_wrapped_value(self) -> ActiveValue<Value> {
850 match self {
851 Self::Set(value) => ActiveValue::set(value.into()),
852 Self::Unchanged(value) => ActiveValue::unchanged(value.into()),
853 Self::NotSet => ActiveValue::not_set(),
854 }
855 }
856
857 pub fn reset(&mut self) {
860 *self = match self.take() {
861 Some(value) => ActiveValue::Set(value),
862 None => ActiveValue::NotSet,
863 };
864 }
865
866 pub fn set_if_not_equals(&mut self, value: V)
894 where
895 V: PartialEq,
896 {
897 match self {
898 ActiveValue::Unchanged(current) if &value == current => {}
899 _ => *self = ActiveValue::Set(value),
900 }
901 }
902
903 pub fn try_as_ref(&self) -> Option<&V> {
917 match self {
918 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value),
919 ActiveValue::NotSet => None,
920 }
921 }
922}
923
924impl<V> std::convert::AsRef<V> for ActiveValue<V>
925where
926 V: Into<Value>,
927{
928 fn as_ref(&self) -> &V {
934 match self {
935 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
936 ActiveValue::NotSet => panic!("Cannot borrow ActiveValue::NotSet"),
937 }
938 }
939}
940
941impl<V> PartialEq for ActiveValue<V>
942where
943 V: Into<Value> + std::cmp::PartialEq,
944{
945 fn eq(&self, other: &Self) -> bool {
946 match (self, other) {
947 (ActiveValue::Set(l), ActiveValue::Set(r)) => l == r,
948 (ActiveValue::Unchanged(l), ActiveValue::Unchanged(r)) => l == r,
949 (ActiveValue::NotSet, ActiveValue::NotSet) => true,
950 _ => false,
951 }
952 }
953}
954
955impl<V> From<ActiveValue<V>> for ActiveValue<Option<V>>
956where
957 V: Into<Value> + Nullable,
958{
959 fn from(value: ActiveValue<V>) -> Self {
960 match value {
961 ActiveValue::Set(value) => ActiveValue::set(Some(value)),
962 ActiveValue::Unchanged(value) => ActiveValue::unchanged(Some(value)),
963 ActiveValue::NotSet => ActiveValue::not_set(),
964 }
965 }
966}
967
968#[cfg(test)]
969mod tests {
970 use crate::{entity::*, tests_cfg::*, DbErr};
971 use pretty_assertions::assert_eq;
972
973 #[cfg(feature = "with-json")]
974 use serde_json::json;
975
976 #[test]
977 #[cfg(feature = "macros")]
978 fn test_derive_into_active_model_1() {
979 mod my_fruit {
980 pub use super::fruit::*;
981 use crate as sea_orm;
982 use crate::entity::prelude::*;
983
984 #[derive(DeriveIntoActiveModel)]
985 pub struct NewFruit {
986 pub name: String,
988 pub cake_id: i32,
990 }
991 }
992
993 assert_eq!(
994 my_fruit::NewFruit {
995 name: "Apple".to_owned(),
996 cake_id: 1,
997 }
998 .into_active_model(),
999 fruit::ActiveModel {
1000 id: NotSet,
1001 name: Set("Apple".to_owned()),
1002 cake_id: Set(Some(1)),
1003 }
1004 );
1005 }
1006
1007 #[test]
1008 #[cfg(feature = "macros")]
1009 fn test_derive_into_active_model_2() {
1010 use crate as sea_orm;
1011 use crate::entity::prelude::*;
1012
1013 #[derive(DeriveIntoActiveModel)]
1014 #[sea_orm(active_model = "fruit::ActiveModel")]
1015 struct FruitName {
1016 name: String,
1017 }
1018
1019 assert_eq!(
1020 FruitName {
1021 name: "Apple Pie".to_owned(),
1022 }
1023 .into_active_model(),
1024 fruit::ActiveModel {
1025 id: NotSet,
1026 name: Set("Apple Pie".to_owned()),
1027 cake_id: NotSet,
1028 }
1029 );
1030
1031 #[derive(DeriveIntoActiveModel)]
1032 #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
1033 struct FruitCake {
1034 cake_id: Option<Option<i32>>,
1035 }
1036
1037 assert_eq!(
1038 FruitCake {
1039 cake_id: Some(Some(1)),
1040 }
1041 .into_active_model(),
1042 fruit::ActiveModel {
1043 id: NotSet,
1044 name: NotSet,
1045 cake_id: Set(Some(1)),
1046 }
1047 );
1048
1049 assert_eq!(
1050 FruitCake {
1051 cake_id: Some(None),
1052 }
1053 .into_active_model(),
1054 fruit::ActiveModel {
1055 id: NotSet,
1056 name: NotSet,
1057 cake_id: Set(None),
1058 }
1059 );
1060
1061 assert_eq!(
1062 FruitCake { cake_id: None }.into_active_model(),
1063 fruit::ActiveModel {
1064 id: NotSet,
1065 name: NotSet,
1066 cake_id: NotSet,
1067 }
1068 );
1069 }
1070
1071 #[test]
1072 #[cfg(feature = "macros")]
1073 fn test_derive_try_into_model_1() {
1074 mod my_fruit {
1075 use crate as sea_orm;
1076 use crate::entity::prelude::*;
1077
1078 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1079 #[sea_orm(table_name = "fruit")]
1080 pub struct Model {
1081 #[sea_orm(primary_key)]
1082 pub id: i32,
1083 pub name: String,
1084 pub cake_id: Option<i32>,
1085 }
1086
1087 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1088 pub enum Relation {}
1089
1090 impl ActiveModelBehavior for ActiveModel {}
1091 }
1092 assert_eq!(
1093 my_fruit::ActiveModel {
1094 id: Set(1),
1095 name: Set("Pineapple".to_owned()),
1096 cake_id: Set(None),
1097 }
1098 .try_into_model()
1099 .unwrap(),
1100 my_fruit::Model {
1101 id: 1,
1102 name: "Pineapple".to_owned(),
1103 cake_id: None,
1104 }
1105 );
1106
1107 assert_eq!(
1108 my_fruit::ActiveModel {
1109 id: Set(2),
1110 name: Set("Apple".to_owned()),
1111 cake_id: Set(Some(1)),
1112 }
1113 .try_into_model()
1114 .unwrap(),
1115 my_fruit::Model {
1116 id: 2,
1117 name: "Apple".to_owned(),
1118 cake_id: Some(1),
1119 }
1120 );
1121
1122 assert_eq!(
1123 my_fruit::ActiveModel {
1124 id: Set(1),
1125 name: NotSet,
1126 cake_id: Set(None),
1127 }
1128 .try_into_model(),
1129 Err(DbErr::AttrNotSet(String::from("name")))
1130 );
1131
1132 assert_eq!(
1133 my_fruit::ActiveModel {
1134 id: Set(1),
1135 name: Set("Pineapple".to_owned()),
1136 cake_id: NotSet,
1137 }
1138 .try_into_model(),
1139 Err(DbErr::AttrNotSet(String::from("cake_id")))
1140 );
1141 }
1142
1143 #[test]
1144 #[cfg(feature = "macros")]
1145 fn test_derive_try_into_model_2() {
1146 mod my_fruit {
1147 use crate as sea_orm;
1148 use crate::entity::prelude::*;
1149
1150 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1151 #[sea_orm(table_name = "fruit")]
1152 pub struct Model {
1153 #[sea_orm(primary_key)]
1154 pub id: i32,
1155 pub name: String,
1156 #[sea_orm(ignore)]
1157 pub cake_id: Option<i32>,
1158 }
1159
1160 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1161 pub enum Relation {}
1162
1163 impl ActiveModelBehavior for ActiveModel {}
1164 }
1165 assert_eq!(
1166 my_fruit::ActiveModel {
1167 id: Set(1),
1168 name: Set("Pineapple".to_owned()),
1169 }
1170 .try_into_model()
1171 .unwrap(),
1172 my_fruit::Model {
1173 id: 1,
1174 name: "Pineapple".to_owned(),
1175 cake_id: None,
1176 }
1177 );
1178 }
1179
1180 #[test]
1181 #[cfg(feature = "macros")]
1182 fn test_derive_try_into_model_3() {
1183 mod my_fruit {
1184 use crate as sea_orm;
1185 use crate::entity::prelude::*;
1186
1187 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1188 #[sea_orm(table_name = "fruit")]
1189 pub struct Model {
1190 #[sea_orm(primary_key)]
1191 pub id: i32,
1192 #[sea_orm(ignore)]
1193 pub name: String,
1194 pub cake_id: Option<i32>,
1195 }
1196
1197 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1198 pub enum Relation {}
1199
1200 impl ActiveModelBehavior for ActiveModel {}
1201 }
1202 assert_eq!(
1203 my_fruit::ActiveModel {
1204 id: Set(1),
1205 cake_id: Set(Some(1)),
1206 }
1207 .try_into_model()
1208 .unwrap(),
1209 my_fruit::Model {
1210 id: 1,
1211 name: "".to_owned(),
1212 cake_id: Some(1),
1213 }
1214 );
1215 }
1216
1217 #[test]
1218 #[cfg(feature = "with-json")]
1219 #[should_panic(
1220 expected = r#"called `Result::unwrap()` on an `Err` value: Json("missing field `id`")"#
1221 )]
1222 fn test_active_model_set_from_json_1() {
1223 let mut cake: cake::ActiveModel = Default::default();
1224
1225 cake.set_from_json(json!({
1226 "name": "Apple Pie",
1227 }))
1228 .unwrap();
1229 }
1230
1231 #[test]
1232 #[cfg(feature = "with-json")]
1233 fn test_active_model_set_from_json_2() -> Result<(), DbErr> {
1234 let mut fruit: fruit::ActiveModel = Default::default();
1235
1236 fruit.set_from_json(json!({
1237 "name": "Apple",
1238 }))?;
1239 assert_eq!(
1240 fruit,
1241 fruit::ActiveModel {
1242 id: ActiveValue::NotSet,
1243 name: ActiveValue::Set("Apple".to_owned()),
1244 cake_id: ActiveValue::NotSet,
1245 }
1246 );
1247
1248 assert_eq!(
1249 fruit::ActiveModel::from_json(json!({
1250 "name": "Apple",
1251 }))?,
1252 fruit::ActiveModel {
1253 id: ActiveValue::NotSet,
1254 name: ActiveValue::Set("Apple".to_owned()),
1255 cake_id: ActiveValue::NotSet,
1256 }
1257 );
1258
1259 fruit.set_from_json(json!({
1260 "name": "Apple",
1261 "cake_id": null,
1262 }))?;
1263 assert_eq!(
1264 fruit,
1265 fruit::ActiveModel {
1266 id: ActiveValue::NotSet,
1267 name: ActiveValue::Set("Apple".to_owned()),
1268 cake_id: ActiveValue::Set(None),
1269 }
1270 );
1271
1272 fruit.set_from_json(json!({
1273 "id": null,
1274 "name": "Apple",
1275 "cake_id": 1,
1276 }))?;
1277 assert_eq!(
1278 fruit,
1279 fruit::ActiveModel {
1280 id: ActiveValue::NotSet,
1281 name: ActiveValue::Set("Apple".to_owned()),
1282 cake_id: ActiveValue::Set(Some(1)),
1283 }
1284 );
1285
1286 fruit.set_from_json(json!({
1287 "id": 2,
1288 "name": "Apple",
1289 "cake_id": 1,
1290 }))?;
1291 assert_eq!(
1292 fruit,
1293 fruit::ActiveModel {
1294 id: ActiveValue::NotSet,
1295 name: ActiveValue::Set("Apple".to_owned()),
1296 cake_id: ActiveValue::Set(Some(1)),
1297 }
1298 );
1299
1300 let mut fruit = fruit::ActiveModel {
1301 id: ActiveValue::Set(1),
1302 name: ActiveValue::NotSet,
1303 cake_id: ActiveValue::NotSet,
1304 };
1305 fruit.set_from_json(json!({
1306 "id": 8,
1307 "name": "Apple",
1308 "cake_id": 1,
1309 }))?;
1310 assert_eq!(
1311 fruit,
1312 fruit::ActiveModel {
1313 id: ActiveValue::Set(1),
1314 name: ActiveValue::Set("Apple".to_owned()),
1315 cake_id: ActiveValue::Set(Some(1)),
1316 }
1317 );
1318
1319 Ok(())
1320 }
1321
1322 #[smol_potat::test]
1323 #[cfg(feature = "with-json")]
1324 async fn test_active_model_set_from_json_3() -> Result<(), DbErr> {
1325 use crate::*;
1326
1327 let db = MockDatabase::new(DbBackend::Postgres)
1328 .append_exec_results([
1329 MockExecResult {
1330 last_insert_id: 1,
1331 rows_affected: 1,
1332 },
1333 MockExecResult {
1334 last_insert_id: 1,
1335 rows_affected: 1,
1336 },
1337 ])
1338 .append_query_results([
1339 [fruit::Model {
1340 id: 1,
1341 name: "Apple".to_owned(),
1342 cake_id: None,
1343 }],
1344 [fruit::Model {
1345 id: 2,
1346 name: "Orange".to_owned(),
1347 cake_id: Some(1),
1348 }],
1349 ])
1350 .into_connection();
1351
1352 let mut fruit: fruit::ActiveModel = Default::default();
1353 fruit.set_from_json(json!({
1354 "name": "Apple",
1355 }))?;
1356 fruit.save(&db).await?;
1357
1358 let mut fruit = fruit::ActiveModel {
1359 id: Set(2),
1360 ..Default::default()
1361 };
1362 fruit.set_from_json(json!({
1363 "id": 9,
1364 "name": "Orange",
1365 "cake_id": 1,
1366 }))?;
1367 fruit.save(&db).await?;
1368
1369 assert_eq!(
1370 db.into_transaction_log(),
1371 [
1372 Transaction::from_sql_and_values(
1373 DbBackend::Postgres,
1374 r#"INSERT INTO "fruit" ("name") VALUES ($1) RETURNING "id", "name", "cake_id""#,
1375 ["Apple".into()],
1376 ),
1377 Transaction::from_sql_and_values(
1378 DbBackend::Postgres,
1379 r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
1380 ["Orange".into(), 1i32.into(), 2i32.into()],
1381 ),
1382 ]
1383 );
1384
1385 Ok(())
1386 }
1387
1388 #[test]
1389 fn test_active_model_is_changed() {
1390 let mut fruit: fruit::ActiveModel = Default::default();
1391 assert!(!fruit.is_changed());
1392
1393 fruit.set(fruit::Column::Name, "apple".into());
1394 assert!(fruit.is_changed());
1395 }
1396
1397 #[test]
1398 fn test_reset_1() {
1399 assert_eq!(
1400 fruit::Model {
1401 id: 1,
1402 name: "Apple".into(),
1403 cake_id: None,
1404 }
1405 .into_active_model(),
1406 fruit::ActiveModel {
1407 id: Unchanged(1),
1408 name: Unchanged("Apple".into()),
1409 cake_id: Unchanged(None)
1410 },
1411 );
1412
1413 assert_eq!(
1414 fruit::Model {
1415 id: 1,
1416 name: "Apple".into(),
1417 cake_id: None,
1418 }
1419 .into_active_model()
1420 .reset_all(),
1421 fruit::ActiveModel {
1422 id: Set(1),
1423 name: Set("Apple".into()),
1424 cake_id: Set(None)
1425 },
1426 );
1427
1428 assert_eq!(
1429 fruit::Model {
1430 id: 1,
1431 name: "Apple".into(),
1432 cake_id: Some(2),
1433 }
1434 .into_active_model(),
1435 fruit::ActiveModel {
1436 id: Unchanged(1),
1437 name: Unchanged("Apple".into()),
1438 cake_id: Unchanged(Some(2)),
1439 },
1440 );
1441
1442 assert_eq!(
1443 fruit::Model {
1444 id: 1,
1445 name: "Apple".into(),
1446 cake_id: Some(2),
1447 }
1448 .into_active_model()
1449 .reset_all(),
1450 fruit::ActiveModel {
1451 id: Set(1),
1452 name: Set("Apple".into()),
1453 cake_id: Set(Some(2)),
1454 },
1455 );
1456 }
1457
1458 #[smol_potat::test]
1459 async fn test_reset_2() -> Result<(), DbErr> {
1460 use crate::*;
1461
1462 let db = MockDatabase::new(DbBackend::Postgres)
1463 .append_exec_results(vec![
1464 MockExecResult {
1465 last_insert_id: 1,
1466 rows_affected: 1,
1467 },
1468 MockExecResult {
1469 last_insert_id: 1,
1470 rows_affected: 1,
1471 },
1472 ])
1473 .append_query_results(vec![
1474 vec![fruit::Model {
1475 id: 1,
1476 name: "Apple".to_owned(),
1477 cake_id: None,
1478 }],
1479 vec![fruit::Model {
1480 id: 1,
1481 name: "Apple".to_owned(),
1482 cake_id: None,
1483 }],
1484 ])
1485 .into_connection();
1486
1487 fruit::Model {
1488 id: 1,
1489 name: "Apple".into(),
1490 cake_id: None,
1491 }
1492 .into_active_model()
1493 .update(&db)
1494 .await?;
1495
1496 fruit::Model {
1497 id: 1,
1498 name: "Apple".into(),
1499 cake_id: None,
1500 }
1501 .into_active_model()
1502 .reset_all()
1503 .update(&db)
1504 .await?;
1505
1506 assert_eq!(
1507 db.into_transaction_log(),
1508 vec![
1509 Transaction::from_sql_and_values(
1510 DbBackend::Postgres,
1511 r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit" WHERE "fruit"."id" = $1 LIMIT $2"#,
1512 vec![1i32.into(), 1u64.into()],
1513 ),
1514 Transaction::from_sql_and_values(
1515 DbBackend::Postgres,
1516 r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
1517 vec!["Apple".into(), Option::<i32>::None.into(), 1i32.into()],
1518 ),
1519 ]
1520 );
1521
1522 Ok(())
1523 }
1524
1525 #[test]
1526 fn test_active_model_default_values() {
1527 assert_eq!(
1528 fruit::ActiveModel::default_values(),
1529 fruit::ActiveModel {
1530 id: Set(0),
1531 name: Set("".into()),
1532 cake_id: Set(None),
1533 },
1534 );
1535
1536 assert_eq!(
1537 lunch_set::ActiveModel::default_values(),
1538 lunch_set::ActiveModel {
1539 id: Set(0),
1540 name: Set("".into()),
1541 tea: NotSet,
1542 },
1543 );
1544 }
1545}