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-uuid")]
800#[cfg_attr(docsrs, doc(cfg(feature = "with-uuid")))]
801impl_into_active_value!(crate::prelude::Uuid);
802
803#[cfg(feature = "with-time")]
804#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
805impl_into_active_value!(crate::prelude::TimeDate);
806
807#[cfg(feature = "with-time")]
808#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
809impl_into_active_value!(crate::prelude::TimeTime);
810
811#[cfg(feature = "with-time")]
812#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
813impl_into_active_value!(crate::prelude::TimeDateTime);
814
815#[cfg(feature = "with-time")]
816#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
817impl_into_active_value!(crate::prelude::TimeDateTimeWithTimeZone);
818
819#[cfg(feature = "with-ipnetwork")]
820#[cfg_attr(docsrs, doc(cfg(feature = "with-ipnetwork")))]
821impl_into_active_value!(crate::prelude::IpNetwork);
822
823impl<V> Default for ActiveValue<V>
824where
825 V: Into<Value>,
826{
827 fn default() -> Self {
829 Self::NotSet
830 }
831}
832
833impl<V> ActiveValue<V>
834where
835 V: Into<Value>,
836{
837 pub fn set(value: V) -> Self {
839 Self::Set(value)
840 }
841
842 pub fn is_set(&self) -> bool {
844 matches!(self, Self::Set(_))
845 }
846
847 pub fn unchanged(value: V) -> Self {
849 Self::Unchanged(value)
850 }
851
852 pub fn is_unchanged(&self) -> bool {
854 matches!(self, Self::Unchanged(_))
855 }
856
857 pub fn not_set() -> Self {
859 Self::default()
860 }
861
862 pub fn is_not_set(&self) -> bool {
864 matches!(self, Self::NotSet)
865 }
866
867 pub fn take(&mut self) -> Option<V> {
870 match std::mem::take(self) {
871 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value),
872 ActiveValue::NotSet => None,
873 }
874 }
875
876 pub fn unwrap(self) -> V {
882 match self {
883 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
884 ActiveValue::NotSet => panic!("Cannot unwrap ActiveValue::NotSet"),
885 }
886 }
887
888 pub fn into_value(self) -> Option<Value> {
890 match self {
891 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value.into()),
892 ActiveValue::NotSet => None,
893 }
894 }
895
896 pub fn into_wrapped_value(self) -> ActiveValue<Value> {
898 match self {
899 Self::Set(value) => ActiveValue::set(value.into()),
900 Self::Unchanged(value) => ActiveValue::unchanged(value.into()),
901 Self::NotSet => ActiveValue::not_set(),
902 }
903 }
904
905 pub fn reset(&mut self) {
908 *self = match self.take() {
909 Some(value) => ActiveValue::Set(value),
910 None => ActiveValue::NotSet,
911 };
912 }
913
914 pub fn set_if_not_equals(&mut self, value: V)
942 where
943 V: PartialEq,
944 {
945 match self {
946 ActiveValue::Unchanged(current) if &value == current => {}
947 _ => *self = ActiveValue::Set(value),
948 }
949 }
950
951 pub fn try_as_ref(&self) -> Option<&V> {
965 match self {
966 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value),
967 ActiveValue::NotSet => None,
968 }
969 }
970}
971
972impl<V> std::convert::AsRef<V> for ActiveValue<V>
973where
974 V: Into<Value>,
975{
976 fn as_ref(&self) -> &V {
982 match self {
983 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
984 ActiveValue::NotSet => panic!("Cannot borrow ActiveValue::NotSet"),
985 }
986 }
987}
988
989impl<V> PartialEq for ActiveValue<V>
990where
991 V: Into<Value> + std::cmp::PartialEq,
992{
993 fn eq(&self, other: &Self) -> bool {
994 match (self, other) {
995 (ActiveValue::Set(l), ActiveValue::Set(r)) => l == r,
996 (ActiveValue::Unchanged(l), ActiveValue::Unchanged(r)) => l == r,
997 (ActiveValue::NotSet, ActiveValue::NotSet) => true,
998 _ => false,
999 }
1000 }
1001}
1002
1003impl<V> From<ActiveValue<V>> for ActiveValue<Option<V>>
1004where
1005 V: Into<Value> + Nullable,
1006{
1007 fn from(value: ActiveValue<V>) -> Self {
1008 match value {
1009 ActiveValue::Set(value) => ActiveValue::set(Some(value)),
1010 ActiveValue::Unchanged(value) => ActiveValue::unchanged(Some(value)),
1011 ActiveValue::NotSet => ActiveValue::not_set(),
1012 }
1013 }
1014}
1015
1016#[cfg(test)]
1017mod tests {
1018 use crate::{DbErr, entity::*, tests_cfg::*};
1019 use pretty_assertions::assert_eq;
1020
1021 #[cfg(feature = "with-json")]
1022 use serde_json::json;
1023
1024 #[test]
1025 #[cfg(feature = "macros")]
1026 fn test_derive_into_active_model_1() {
1027 mod my_fruit {
1028 pub use super::fruit::*;
1029 use crate as sea_orm;
1030 use crate::entity::prelude::*;
1031
1032 #[derive(DeriveIntoActiveModel)]
1033 pub struct NewFruit {
1034 pub name: String,
1036 pub cake_id: i32,
1038 }
1039 }
1040
1041 assert_eq!(
1042 my_fruit::NewFruit {
1043 name: "Apple".to_owned(),
1044 cake_id: 1,
1045 }
1046 .into_active_model(),
1047 fruit::ActiveModel {
1048 id: NotSet,
1049 name: Set("Apple".to_owned()),
1050 cake_id: Set(Some(1)),
1051 }
1052 );
1053 }
1054
1055 #[test]
1056 #[cfg(feature = "macros")]
1057 fn test_derive_into_active_model_2() {
1058 use crate as sea_orm;
1059 use crate::entity::prelude::*;
1060
1061 #[derive(DeriveIntoActiveModel)]
1062 #[sea_orm(active_model = "fruit::ActiveModel")]
1063 struct FruitName {
1064 name: String,
1065 }
1066
1067 assert_eq!(
1068 FruitName {
1069 name: "Apple Pie".to_owned(),
1070 }
1071 .into_active_model(),
1072 fruit::ActiveModel {
1073 id: NotSet,
1074 name: Set("Apple Pie".to_owned()),
1075 cake_id: NotSet,
1076 }
1077 );
1078
1079 #[derive(DeriveIntoActiveModel)]
1080 #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
1081 struct FruitCake {
1082 cake_id: Option<Option<i32>>,
1083 }
1084
1085 assert_eq!(
1086 FruitCake {
1087 cake_id: Some(Some(1)),
1088 }
1089 .into_active_model(),
1090 fruit::ActiveModel {
1091 id: NotSet,
1092 name: NotSet,
1093 cake_id: Set(Some(1)),
1094 }
1095 );
1096
1097 assert_eq!(
1098 FruitCake {
1099 cake_id: Some(None),
1100 }
1101 .into_active_model(),
1102 fruit::ActiveModel {
1103 id: NotSet,
1104 name: NotSet,
1105 cake_id: Set(None),
1106 }
1107 );
1108
1109 assert_eq!(
1110 FruitCake { cake_id: None }.into_active_model(),
1111 fruit::ActiveModel {
1112 id: NotSet,
1113 name: NotSet,
1114 cake_id: NotSet,
1115 }
1116 );
1117 }
1118
1119 #[test]
1120 #[cfg(feature = "macros")]
1121 fn test_derive_try_into_model_1() {
1122 mod my_fruit {
1123 use crate as sea_orm;
1124 use crate::entity::prelude::*;
1125
1126 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1127 #[sea_orm(table_name = "fruit")]
1128 pub struct Model {
1129 #[sea_orm(primary_key)]
1130 pub id: i32,
1131 pub name: String,
1132 pub cake_id: Option<i32>,
1133 }
1134
1135 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1136 pub enum Relation {}
1137
1138 impl ActiveModelBehavior for ActiveModel {}
1139 }
1140 assert_eq!(
1141 my_fruit::ActiveModel {
1142 id: Set(1),
1143 name: Set("Pineapple".to_owned()),
1144 cake_id: Set(None),
1145 }
1146 .try_into_model()
1147 .unwrap(),
1148 my_fruit::Model {
1149 id: 1,
1150 name: "Pineapple".to_owned(),
1151 cake_id: None,
1152 }
1153 );
1154
1155 assert_eq!(
1156 my_fruit::ActiveModel {
1157 id: Set(2),
1158 name: Set("Apple".to_owned()),
1159 cake_id: Set(Some(1)),
1160 }
1161 .try_into_model()
1162 .unwrap(),
1163 my_fruit::Model {
1164 id: 2,
1165 name: "Apple".to_owned(),
1166 cake_id: Some(1),
1167 }
1168 );
1169
1170 assert_eq!(
1171 my_fruit::ActiveModel {
1172 id: Set(1),
1173 name: NotSet,
1174 cake_id: Set(None),
1175 }
1176 .try_into_model(),
1177 Err(DbErr::AttrNotSet(String::from("name")))
1178 );
1179
1180 assert_eq!(
1181 my_fruit::ActiveModel {
1182 id: Set(1),
1183 name: Set("Pineapple".to_owned()),
1184 cake_id: NotSet,
1185 }
1186 .try_into_model(),
1187 Err(DbErr::AttrNotSet(String::from("cake_id")))
1188 );
1189 }
1190
1191 #[test]
1192 #[cfg(feature = "macros")]
1193 fn test_derive_try_into_model_2() {
1194 mod my_fruit {
1195 use crate as sea_orm;
1196 use crate::entity::prelude::*;
1197
1198 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1199 #[sea_orm(table_name = "fruit")]
1200 pub struct Model {
1201 #[sea_orm(primary_key)]
1202 pub id: i32,
1203 pub name: String,
1204 #[sea_orm(ignore)]
1205 pub cake_id: Option<i32>,
1206 }
1207
1208 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1209 pub enum Relation {}
1210
1211 impl ActiveModelBehavior for ActiveModel {}
1212 }
1213 assert_eq!(
1214 my_fruit::ActiveModel {
1215 id: Set(1),
1216 name: Set("Pineapple".to_owned()),
1217 }
1218 .try_into_model()
1219 .unwrap(),
1220 my_fruit::Model {
1221 id: 1,
1222 name: "Pineapple".to_owned(),
1223 cake_id: None,
1224 }
1225 );
1226 }
1227
1228 #[test]
1229 #[cfg(feature = "macros")]
1230 fn test_derive_try_into_model_3() {
1231 mod my_fruit {
1232 use crate as sea_orm;
1233 use crate::entity::prelude::*;
1234
1235 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1236 #[sea_orm(table_name = "fruit")]
1237 pub struct Model {
1238 #[sea_orm(primary_key)]
1239 pub id: i32,
1240 #[sea_orm(ignore)]
1241 pub name: String,
1242 pub cake_id: Option<i32>,
1243 }
1244
1245 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1246 pub enum Relation {}
1247
1248 impl ActiveModelBehavior for ActiveModel {}
1249 }
1250 assert_eq!(
1251 my_fruit::ActiveModel {
1252 id: Set(1),
1253 cake_id: Set(Some(1)),
1254 }
1255 .try_into_model()
1256 .unwrap(),
1257 my_fruit::Model {
1258 id: 1,
1259 name: "".to_owned(),
1260 cake_id: Some(1),
1261 }
1262 );
1263 }
1264
1265 #[test]
1266 #[cfg(feature = "with-json")]
1267 fn test_active_model_set_from_json_1() {
1268 assert_eq!(
1269 cake::ActiveModel::from_json(json!({
1270 "id": 1,
1271 "name": "Apple Pie",
1272 }))
1273 .unwrap(),
1274 cake::ActiveModel {
1275 id: Set(1),
1276 name: Set("Apple Pie".to_owned()),
1277 }
1278 );
1279
1280 assert_eq!(
1281 cake::ActiveModel::from_json(json!({
1282 "id": 1,
1283 }))
1284 .unwrap(),
1285 cake::ActiveModel {
1286 id: Set(1),
1287 name: NotSet,
1288 }
1289 );
1290
1291 assert_eq!(
1292 cake::ActiveModel::from_json(json!({
1293 "name": "Apple Pie",
1294 }))
1295 .unwrap(),
1296 cake::ActiveModel {
1297 id: NotSet,
1298 name: Set("Apple Pie".to_owned()),
1299 }
1300 );
1301
1302 let mut cake: cake::ActiveModel = Default::default();
1303 cake.set_from_json(json!({
1304 "name": "Apple Pie",
1305 }))
1306 .unwrap();
1307 assert_eq!(
1308 cake,
1309 cake::ActiveModel {
1310 id: NotSet,
1311 name: Set("Apple Pie".to_owned()),
1312 }
1313 );
1314 }
1315
1316 #[test]
1317 #[cfg(feature = "with-json")]
1318 fn test_active_model_set_from_json_2() -> Result<(), DbErr> {
1319 let mut fruit: fruit::ActiveModel = Default::default();
1320
1321 fruit.set_from_json(json!({
1322 "name": "Apple",
1323 }))?;
1324 assert_eq!(
1325 fruit,
1326 fruit::ActiveModel {
1327 id: ActiveValue::NotSet,
1328 name: ActiveValue::Set("Apple".to_owned()),
1329 cake_id: ActiveValue::NotSet,
1330 }
1331 );
1332
1333 assert_eq!(
1334 fruit::ActiveModel::from_json(json!({
1335 "name": "Apple",
1336 }))?,
1337 fruit::ActiveModel {
1338 id: ActiveValue::NotSet,
1339 name: ActiveValue::Set("Apple".to_owned()),
1340 cake_id: ActiveValue::NotSet,
1341 }
1342 );
1343
1344 fruit.set_from_json(json!({
1345 "name": "Apple",
1346 "cake_id": null,
1347 }))?;
1348 assert_eq!(
1349 fruit,
1350 fruit::ActiveModel {
1351 id: ActiveValue::NotSet,
1352 name: ActiveValue::Set("Apple".to_owned()),
1353 cake_id: ActiveValue::Set(None),
1354 }
1355 );
1356
1357 fruit.set_from_json(json!({
1358 "id": null,
1359 "name": "Apple",
1360 "cake_id": 1,
1361 }))?;
1362 assert_eq!(
1363 fruit,
1364 fruit::ActiveModel {
1365 id: ActiveValue::NotSet,
1366 name: ActiveValue::Set("Apple".to_owned()),
1367 cake_id: ActiveValue::Set(Some(1)),
1368 }
1369 );
1370
1371 fruit.set_from_json(json!({
1372 "id": 2,
1373 "name": "Apple",
1374 "cake_id": 1,
1375 }))?;
1376 assert_eq!(
1377 fruit,
1378 fruit::ActiveModel {
1379 id: ActiveValue::NotSet,
1380 name: ActiveValue::Set("Apple".to_owned()),
1381 cake_id: ActiveValue::Set(Some(1)),
1382 }
1383 );
1384
1385 let mut fruit = fruit::ActiveModel {
1386 id: ActiveValue::Set(1),
1387 name: ActiveValue::NotSet,
1388 cake_id: ActiveValue::NotSet,
1389 };
1390 fruit.set_from_json(json!({
1391 "id": 8,
1392 "name": "Apple",
1393 "cake_id": 1,
1394 }))?;
1395 assert_eq!(
1396 fruit,
1397 fruit::ActiveModel {
1398 id: ActiveValue::Set(1),
1399 name: ActiveValue::Set("Apple".to_owned()),
1400 cake_id: ActiveValue::Set(Some(1)),
1401 }
1402 );
1403
1404 Ok(())
1405 }
1406
1407 #[smol_potat::test]
1408 #[cfg(feature = "with-json")]
1409 async fn test_active_model_set_from_json_3() -> Result<(), DbErr> {
1410 use crate::*;
1411
1412 let db = MockDatabase::new(DbBackend::Postgres)
1413 .append_exec_results([
1414 MockExecResult {
1415 last_insert_id: 1,
1416 rows_affected: 1,
1417 },
1418 MockExecResult {
1419 last_insert_id: 1,
1420 rows_affected: 1,
1421 },
1422 ])
1423 .append_query_results([
1424 [fruit::Model {
1425 id: 1,
1426 name: "Apple".to_owned(),
1427 cake_id: None,
1428 }],
1429 [fruit::Model {
1430 id: 2,
1431 name: "Orange".to_owned(),
1432 cake_id: Some(1),
1433 }],
1434 ])
1435 .into_connection();
1436
1437 let mut fruit: fruit::ActiveModel = Default::default();
1438 fruit.set_from_json(json!({
1439 "name": "Apple",
1440 }))?;
1441 fruit.save(&db).await?;
1442
1443 let mut fruit = fruit::ActiveModel {
1444 id: Set(2),
1445 ..Default::default()
1446 };
1447 fruit.set_from_json(json!({
1448 "id": 9,
1449 "name": "Orange",
1450 "cake_id": 1,
1451 }))?;
1452 fruit.save(&db).await?;
1453
1454 assert_eq!(
1455 db.into_transaction_log(),
1456 [
1457 Transaction::from_sql_and_values(
1458 DbBackend::Postgres,
1459 r#"INSERT INTO "fruit" ("name") VALUES ($1) RETURNING "id", "name", "cake_id""#,
1460 ["Apple".into()],
1461 ),
1462 Transaction::from_sql_and_values(
1463 DbBackend::Postgres,
1464 r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
1465 ["Orange".into(), 1i32.into(), 2i32.into()],
1466 ),
1467 ]
1468 );
1469
1470 Ok(())
1471 }
1472
1473 #[test]
1474 fn test_active_model_is_changed() {
1475 let mut fruit: fruit::ActiveModel = Default::default();
1476 assert!(!fruit.is_changed());
1477
1478 fruit.set(fruit::Column::Name, "apple".into());
1479 assert!(fruit.is_changed());
1480
1481 let mut fruit = fruit::Model {
1482 id: 1,
1483 name: "".into(),
1484 cake_id: None,
1485 };
1486 fruit.set("name".parse().unwrap(), "orange".into());
1487 assert_eq!(fruit.name, "orange");
1488 }
1489
1490 #[test]
1491 fn test_reset_1() {
1492 assert_eq!(
1493 fruit::Model {
1494 id: 1,
1495 name: "Apple".into(),
1496 cake_id: None,
1497 }
1498 .into_active_model(),
1499 fruit::ActiveModel {
1500 id: Unchanged(1),
1501 name: Unchanged("Apple".into()),
1502 cake_id: Unchanged(None)
1503 },
1504 );
1505
1506 assert_eq!(
1507 fruit::Model {
1508 id: 1,
1509 name: "Apple".into(),
1510 cake_id: None,
1511 }
1512 .into_active_model()
1513 .reset_all(),
1514 fruit::ActiveModel {
1515 id: Set(1),
1516 name: Set("Apple".into()),
1517 cake_id: Set(None)
1518 },
1519 );
1520
1521 assert_eq!(
1522 fruit::Model {
1523 id: 1,
1524 name: "Apple".into(),
1525 cake_id: Some(2),
1526 }
1527 .into_active_model(),
1528 fruit::ActiveModel {
1529 id: Unchanged(1),
1530 name: Unchanged("Apple".into()),
1531 cake_id: Unchanged(Some(2)),
1532 },
1533 );
1534
1535 assert_eq!(
1536 fruit::Model {
1537 id: 1,
1538 name: "Apple".into(),
1539 cake_id: Some(2),
1540 }
1541 .into_active_model()
1542 .reset_all(),
1543 fruit::ActiveModel {
1544 id: Set(1),
1545 name: Set("Apple".into()),
1546 cake_id: Set(Some(2)),
1547 },
1548 );
1549 }
1550
1551 #[smol_potat::test]
1552 async fn test_reset_2() -> Result<(), DbErr> {
1553 use crate::*;
1554
1555 let db = MockDatabase::new(DbBackend::Postgres)
1556 .append_exec_results(vec![
1557 MockExecResult {
1558 last_insert_id: 1,
1559 rows_affected: 1,
1560 },
1561 MockExecResult {
1562 last_insert_id: 1,
1563 rows_affected: 1,
1564 },
1565 ])
1566 .append_query_results(vec![
1567 vec![fruit::Model {
1568 id: 1,
1569 name: "Apple".to_owned(),
1570 cake_id: None,
1571 }],
1572 vec![fruit::Model {
1573 id: 1,
1574 name: "Apple".to_owned(),
1575 cake_id: None,
1576 }],
1577 ])
1578 .into_connection();
1579
1580 fruit::Model {
1581 id: 1,
1582 name: "Apple".into(),
1583 cake_id: None,
1584 }
1585 .into_active_model()
1586 .update(&db)
1587 .await?;
1588
1589 fruit::Model {
1590 id: 1,
1591 name: "Apple".into(),
1592 cake_id: None,
1593 }
1594 .into_active_model()
1595 .reset_all()
1596 .update(&db)
1597 .await?;
1598
1599 assert_eq!(
1600 db.into_transaction_log(),
1601 vec![
1602 Transaction::from_sql_and_values(
1603 DbBackend::Postgres,
1604 r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit" WHERE "fruit"."id" = $1 LIMIT $2"#,
1605 vec![1i32.into(), 1u64.into()],
1606 ),
1607 Transaction::from_sql_and_values(
1608 DbBackend::Postgres,
1609 r#"UPDATE "fruit" SET "name" = $1, "cake_id" = $2 WHERE "fruit"."id" = $3 RETURNING "id", "name", "cake_id""#,
1610 vec!["Apple".into(), Option::<i32>::None.into(), 1i32.into()],
1611 ),
1612 ]
1613 );
1614
1615 Ok(())
1616 }
1617
1618 #[test]
1619 fn test_active_model_default_values() {
1620 assert_eq!(
1621 fruit::ActiveModel::default_values(),
1622 fruit::ActiveModel {
1623 id: Set(0),
1624 name: Set("".into()),
1625 cake_id: Set(None),
1626 },
1627 );
1628
1629 assert_eq!(
1630 lunch_set::ActiveModel::default_values(),
1631 lunch_set::ActiveModel {
1632 id: Set(0),
1633 name: Set("".into()),
1634 tea: NotSet,
1635 },
1636 );
1637 }
1638}