1use crate::{
2 ColumnDef, ColumnType, DbBackend, EntityName, Iden, IdenStatic, IntoSimpleExpr, Iterable,
3};
4use sea_query::{
5 BinOper, DynIden, Expr, ExprTrait, IntoIden, IntoLikeExpr, SeaRc, SelectStatement, Value,
6};
7use std::{borrow::Cow, str::FromStr};
8
9mod types;
10pub use types::*;
11
12pub(crate) mod macros {
13 macro_rules! bind_oper {
14 ($vis:vis $op:ident, $bin_op:ident) => {
15 #[allow(missing_docs)]
16 $vis fn $op<V>(&self, v: V) -> Expr
17 where
18 V: Into<Value>,
19 {
20 let expr = self.save_as(Expr::val(v));
21 Expr::col(self.as_column_ref()).binary(BinOper::$bin_op, expr)
22 }
23 };
24 }
25
26 macro_rules! bind_func_no_params {
27 ($vis:vis $func:ident) => {
28 $vis fn $func(&self) -> Expr {
30 Expr::col(self.as_column_ref()).$func()
31 }
32 };
33 }
34
35 macro_rules! bind_vec_func {
36 ($vis:vis $func:ident) => {
37 #[allow(missing_docs)]
38 #[allow(clippy::wrong_self_convention)]
39 $vis fn $func<V, I>(&self, v: I) -> Expr
40 where
41 V: Into<Value>,
42 I: IntoIterator<Item = V>,
43 {
44 let v_with_enum_cast = v.into_iter().map(|v| self.save_as(Expr::val(v)));
45 Expr::col(self.as_column_ref()).$func(v_with_enum_cast)
46 }
47 };
48 }
49
50 macro_rules! bind_subquery_func {
51 ($vis:vis $func:ident) => {
52 #[allow(clippy::wrong_self_convention)]
53 #[allow(missing_docs)]
54 $vis fn $func(&self, s: SelectStatement) -> Expr {
55 Expr::col(self.as_column_ref()).$func(s)
56 }
57 };
58 }
59
60 macro_rules! bind_array_oper {
61 ($vis:vis $op:ident, $oper:ident) => {
62 #[cfg(feature = "postgres-array")]
63 $vis fn $op<V, I>(&self, v: I) -> Expr
65 where
66 V: Into<Value> + sea_query::ValueType + sea_query::with_array::NotU8,
67 I: IntoIterator<Item = V>,
68 {
69 use sea_query::extension::postgres::PgBinOper;
70
71 let vec: Vec<_> = v.into_iter().collect();
72 Expr::col(self.as_column_ref()).binary(PgBinOper::$oper, self.save_as(Expr::val(vec)))
73 }
74 };
75 }
76
77 pub(crate) use bind_array_oper;
78 pub(crate) use bind_func_no_params;
79 pub(crate) use bind_oper;
80 pub(crate) use bind_subquery_func;
81 pub(crate) use bind_vec_func;
82}
83
84use macros::*;
85
86pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
88 #[allow(missing_docs)]
89 type EntityName: EntityName;
90
91 fn def(&self) -> ColumnDef;
93
94 fn enum_type_name(&self) -> Option<&'static str> {
96 None
97 }
98
99 fn entity_name(&self) -> DynIden {
101 SeaRc::new(Self::EntityName::default())
102 }
103
104 fn as_column_ref(&self) -> (DynIden, DynIden) {
106 (self.entity_name(), SeaRc::new(*self))
107 }
108
109 bind_oper!(eq, Equal);
110 bind_oper!(ne, NotEqual);
111 bind_oper!(gt, GreaterThan);
112 bind_oper!(gte, GreaterThanOrEqual);
113 bind_oper!(lt, SmallerThan);
114 bind_oper!(lte, SmallerThanOrEqual);
115
116 fn between<V>(&self, a: V, b: V) -> Expr
128 where
129 V: Into<Value>,
130 {
131 Expr::col(self.as_column_ref()).between(a, b)
132 }
133
134 fn not_between<V>(&self, a: V, b: V) -> Expr
146 where
147 V: Into<Value>,
148 {
149 Expr::col(self.as_column_ref()).not_between(a, b)
150 }
151
152 fn like<T>(&self, s: T) -> Expr
164 where
165 T: IntoLikeExpr,
166 {
167 Expr::col(self.as_column_ref()).like(s)
168 }
169
170 fn not_like<T>(&self, s: T) -> Expr
182 where
183 T: IntoLikeExpr,
184 {
185 Expr::col(self.as_column_ref()).not_like(s)
186 }
187
188 fn ilike<T>(&self, s: T) -> Expr
201 where
202 T: IntoLikeExpr,
203 {
204 use sea_query::extension::postgres::PgExpr;
205
206 Expr::col(self.as_column_ref()).ilike(s)
207 }
208
209 fn not_ilike<T>(&self, s: T) -> Expr
222 where
223 T: IntoLikeExpr,
224 {
225 use sea_query::extension::postgres::PgExpr;
226
227 Expr::col(self.as_column_ref()).not_ilike(s)
228 }
229
230 fn starts_with<T>(&self, s: T) -> Expr
247 where
248 T: Into<String>,
249 {
250 let pattern = format!("{}%", s.into());
251 Expr::col(self.as_column_ref()).like(pattern)
252 }
253
254 fn ends_with<T>(&self, s: T) -> Expr
271 where
272 T: Into<String>,
273 {
274 let pattern = format!("%{}", s.into());
275 Expr::col(self.as_column_ref()).like(pattern)
276 }
277
278 fn contains<T>(&self, s: T) -> Expr
295 where
296 T: Into<String>,
297 {
298 let pattern = format!("%{}%", s.into());
299 Expr::col(self.as_column_ref()).like(pattern)
300 }
301
302 bind_func_no_params!(max);
303 bind_func_no_params!(min);
304 bind_func_no_params!(sum);
305 bind_func_no_params!(avg);
306 bind_func_no_params!(count);
307 bind_func_no_params!(is_null);
308 bind_func_no_params!(is_not_null);
309
310 fn if_null<V>(&self, v: V) -> Expr
312 where
313 V: Into<Value>,
314 {
315 Expr::col(self.as_column_ref()).if_null(v)
316 }
317
318 bind_vec_func!(is_in);
319 bind_vec_func!(is_not_in);
320
321 #[cfg(feature = "postgres-array")]
334 fn eq_any<V, I>(&self, v: I) -> Expr
335 where
336 V: Into<Value> + sea_query::ValueType + sea_query::with_array::NotU8,
337 I: IntoIterator<Item = V>,
338 {
339 use sea_query::extension::postgres::PgFunc;
340
341 let vec: Vec<_> = v.into_iter().collect();
342 Expr::col(self.as_column_ref()).eq(PgFunc::any(vec))
343 }
344
345 bind_subquery_func!(in_subquery);
346 bind_subquery_func!(not_in_subquery);
347
348 bind_array_oper!(array_contains, Contains);
349 bind_array_oper!(array_contained, Contained);
350 bind_array_oper!(array_overlap, Overlap);
351
352 fn into_expr(self) -> Expr {
354 self.into_simple_expr()
355 }
356
357 #[allow(clippy::match_single_binding)]
359 fn into_returning_expr(self, db_backend: DbBackend) -> Expr {
360 match db_backend {
361 _ => Expr::col(self),
362 }
363 }
364
365 fn select_as(&self, expr: Expr) -> Expr {
368 self.select_enum_as(expr)
369 }
370
371 fn select_enum_as(&self, expr: Expr) -> Expr {
373 cast_enum_as(expr, &self.def(), select_enum_as)
374 }
375
376 fn save_as(&self, val: Expr) -> Expr {
379 self.save_enum_as(val)
380 }
381
382 fn save_enum_as(&self, val: Expr) -> Expr {
384 cast_enum_as(val, &self.def(), save_enum_as)
385 }
386}
387
388pub trait ColumnTypeTrait {
390 fn def(self) -> ColumnDef;
392
393 fn get_enum_name(&self) -> Option<&DynIden>;
395}
396
397impl ColumnTypeTrait for ColumnType {
398 fn def(self) -> ColumnDef {
399 ColumnDef {
400 col_type: self,
401 null: false,
402 unique: false,
403 indexed: false,
404 default: None,
405 comment: None,
406 unique_key: None,
407 renamed_from: None,
408 extra: None,
409 seaography: Default::default(),
410 }
411 }
412
413 fn get_enum_name(&self) -> Option<&DynIden> {
414 enum_name(self)
415 }
416}
417
418impl ColumnTypeTrait for ColumnDef {
419 fn def(self) -> ColumnDef {
420 self
421 }
422
423 fn get_enum_name(&self) -> Option<&DynIden> {
424 enum_name(&self.col_type)
425 }
426}
427
428fn enum_name(col_type: &ColumnType) -> Option<&DynIden> {
429 match col_type {
430 ColumnType::Enum { name, .. } => Some(name),
431 ColumnType::Array(col_type) => enum_name(col_type),
432 _ => None,
433 }
434}
435
436struct Text;
437struct TextArray;
438
439impl Iden for Text {
440 fn quoted(&self) -> Cow<'static, str> {
441 Cow::Borrowed("text")
442 }
443
444 fn unquoted(&self) -> &str {
445 match self.quoted() {
446 Cow::Borrowed(s) => s,
447 _ => unreachable!(),
448 }
449 }
450}
451
452impl Iden for TextArray {
453 fn quoted(&self) -> Cow<'static, str> {
454 Cow::Borrowed("text[]")
456 }
457
458 fn unquoted(&self) -> &str {
459 match self.quoted() {
460 Cow::Borrowed(s) => s,
461 _ => unreachable!(),
462 }
463 }
464}
465
466pub(crate) fn select_enum_as(col: Expr, _: DynIden, col_type: &ColumnType) -> Expr {
467 let type_name = match col_type {
468 ColumnType::Array(_) => TextArray.into_iden(),
469 _ => Text.into_iden(),
470 };
471 col.as_enum(type_name)
472}
473
474pub(crate) fn save_enum_as(col: Expr, enum_name: DynIden, col_type: &ColumnType) -> Expr {
475 let type_name = match col_type {
476 ColumnType::Array(_) => format!("{enum_name}[]").into_iden(),
477 _ => enum_name,
478 };
479 col.as_enum(type_name)
480}
481
482pub(crate) fn cast_enum_as<F>(expr: Expr, col_def: &ColumnDef, f: F) -> Expr
483where
484 F: Fn(Expr, DynIden, &ColumnType) -> Expr,
485{
486 let col_type = col_def.get_column_type();
487
488 match col_type {
489 #[cfg(all(feature = "with-json", feature = "postgres-array"))]
490 ColumnType::Json | ColumnType::JsonBinary => {
491 use sea_query::ArrayType;
492 use serde_json::Value as Json;
493
494 match expr {
495 Expr::Value(Value::Array(ArrayType::Json, Some(json_vec))) => {
496 let json_vec: Vec<Json> = json_vec
498 .into_iter()
499 .filter_map(|val| match val {
500 Value::Json(Some(json)) => Some(json),
501 _ => None,
502 })
503 .collect();
504 Expr::Value(Value::Json(Some(json_vec.into())))
505 }
506 Expr::Value(Value::Array(ArrayType::Json, None)) => Expr::Value(Value::Json(None)),
507 _ => expr,
508 }
509 }
510 _ => match col_type.get_enum_name() {
511 Some(enum_name) => f(expr, enum_name.clone(), col_type),
512 None => expr,
513 },
514 }
515}
516
517#[cfg(test)]
518mod tests {
519 use crate::{
520 ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait, tests_cfg::*,
521 };
522 use sea_query::Query;
523
524 #[test]
525 fn test_in_subquery_1() {
526 assert_eq!(
527 cake::Entity::find()
528 .filter(
529 Condition::any().add(
530 cake::Column::Id.in_subquery(
531 Query::select()
532 .expr(cake::Column::Id.max())
533 .from(cake::Entity)
534 .to_owned()
535 )
536 )
537 )
538 .build(DbBackend::MySql)
539 .to_string(),
540 [
541 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
542 "WHERE `cake`.`id` IN (SELECT MAX(`cake`.`id`) FROM `cake`)",
543 ]
544 .join(" ")
545 );
546 }
547
548 #[test]
549 fn test_in_subquery_2() {
550 assert_eq!(
551 cake::Entity::find()
552 .filter(
553 Condition::any().add(
554 cake::Column::Id.in_subquery(
555 Query::select()
556 .column(cake_filling::Column::CakeId)
557 .from(cake_filling::Entity)
558 .to_owned()
559 )
560 )
561 )
562 .build(DbBackend::MySql)
563 .to_string(),
564 [
565 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
566 "WHERE `cake`.`id` IN (SELECT `cake_id` FROM `cake_filling`)",
567 ]
568 .join(" ")
569 );
570 }
571
572 #[test]
573 #[cfg(feature = "macros")]
574 fn select_as_1() {
575 use crate::{ActiveModelTrait, ActiveValue, Update};
576
577 mod hello_expanded {
578 use crate as sea_orm;
579 use crate::entity::prelude::*;
580 use crate::sea_query::{Expr, ExprTrait};
581
582 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
583 pub struct Entity;
584
585 impl EntityName for Entity {
586 fn table_name(&self) -> &'static str {
587 "hello"
588 }
589 }
590
591 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
592 pub struct Model {
593 pub id: i32,
594 #[sea_orm(enum_name = "One1")]
595 pub one: i32,
596 pub two: i32,
597 #[sea_orm(enum_name = "Three3")]
598 pub three: i32,
599 }
600
601 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
602 pub enum Column {
603 Id,
604 One1,
605 Two,
606 Three3,
607 }
608
609 impl ColumnTrait for Column {
610 type EntityName = Entity;
611
612 fn def(&self) -> ColumnDef {
613 match self {
614 Column::Id => ColumnType::Integer.def(),
615 Column::One1 => ColumnType::Integer.def(),
616 Column::Two => ColumnType::Integer.def(),
617 Column::Three3 => ColumnType::Integer.def(),
618 }
619 }
620
621 fn select_as(&self, expr: Expr) -> Expr {
622 match self {
623 Self::Two => expr.cast_as("integer"),
624 _ => self.select_enum_as(expr),
625 }
626 }
627 }
628
629 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
630 pub enum PrimaryKey {
631 Id,
632 }
633
634 impl PrimaryKeyTrait for PrimaryKey {
635 type ValueType = i32;
636
637 fn auto_increment() -> bool {
638 true
639 }
640 }
641
642 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
643 pub enum Relation {}
644
645 impl ActiveModelBehavior for ActiveModel {}
646 }
647
648 #[allow(clippy::enum_variant_names)]
649 mod hello_compact {
650 use crate as sea_orm;
651 use crate::entity::prelude::*;
652
653 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
654 #[sea_orm(table_name = "hello")]
655 pub struct Model {
656 #[sea_orm(primary_key)]
657 pub id: i32,
658 #[sea_orm(enum_name = "One1")]
659 pub one: i32,
660 #[sea_orm(select_as = "integer")]
661 pub two: i32,
662 #[sea_orm(enum_name = "Three3")]
663 pub three: i32,
664 }
665
666 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
667 pub enum Relation {}
668
669 impl ActiveModelBehavior for ActiveModel {}
670 }
671
672 fn assert_it<E, A>(active_model: A)
673 where
674 E: EntityTrait,
675 A: ActiveModelTrait<Entity = E>,
676 {
677 assert_eq!(
678 E::find().build(DbBackend::Postgres).to_string(),
679 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
680 );
681 assert_eq!(
682 Update::one(active_model)
683 .validate()
684 .unwrap()
685 .build(DbBackend::Postgres)
686 .to_string(),
687 r#"UPDATE "hello" SET "one1" = 1, "two" = 2, "three3" = 3 WHERE "hello"."id" = 1"#,
688 );
689 }
690
691 assert_it(hello_expanded::ActiveModel {
692 id: ActiveValue::set(1),
693 one: ActiveValue::set(1),
694 two: ActiveValue::set(2),
695 three: ActiveValue::set(3),
696 });
697 assert_it(hello_compact::ActiveModel {
698 id: ActiveValue::set(1),
699 one: ActiveValue::set(1),
700 two: ActiveValue::set(2),
701 three: ActiveValue::set(3),
702 });
703 }
704
705 #[test]
706 #[cfg(feature = "macros")]
707 fn save_as_1() {
708 use crate::{ActiveModelTrait, ActiveValue, Update};
709
710 mod hello_expanded {
711 use crate as sea_orm;
712 use crate::entity::prelude::*;
713 use crate::sea_query::{Expr, ExprTrait};
714
715 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
716 pub struct Entity;
717
718 impl EntityName for Entity {
719 fn table_name(&self) -> &'static str {
720 "hello"
721 }
722 }
723
724 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
725 pub struct Model {
726 pub id: i32,
727 #[sea_orm(enum_name = "One1")]
728 pub one: i32,
729 pub two: i32,
730 #[sea_orm(enum_name = "Three3")]
731 pub three: i32,
732 }
733
734 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
735 pub enum Column {
736 Id,
737 One1,
738 Two,
739 Three3,
740 }
741
742 impl ColumnTrait for Column {
743 type EntityName = Entity;
744
745 fn def(&self) -> ColumnDef {
746 match self {
747 Column::Id => ColumnType::Integer.def(),
748 Column::One1 => ColumnType::Integer.def(),
749 Column::Two => ColumnType::Integer.def(),
750 Column::Three3 => ColumnType::Integer.def(),
751 }
752 }
753
754 fn save_as(&self, val: Expr) -> Expr {
755 match self {
756 Self::Two => val.cast_as("text"),
757 _ => self.save_enum_as(val),
758 }
759 }
760 }
761
762 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
763 pub enum PrimaryKey {
764 Id,
765 }
766
767 impl PrimaryKeyTrait for PrimaryKey {
768 type ValueType = i32;
769
770 fn auto_increment() -> bool {
771 true
772 }
773 }
774
775 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
776 pub enum Relation {}
777
778 impl ActiveModelBehavior for ActiveModel {}
779 }
780
781 #[allow(clippy::enum_variant_names)]
782 mod hello_compact {
783 use crate as sea_orm;
784 use crate::entity::prelude::*;
785
786 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
787 #[sea_orm(table_name = "hello")]
788 pub struct Model {
789 #[sea_orm(primary_key)]
790 pub id: i32,
791 #[sea_orm(enum_name = "One1")]
792 pub one: i32,
793 #[sea_orm(save_as = "text")]
794 pub two: i32,
795 #[sea_orm(enum_name = "Three3")]
796 pub three: i32,
797 }
798
799 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
800 pub enum Relation {}
801
802 impl ActiveModelBehavior for ActiveModel {}
803 }
804
805 fn assert_it<E, A>(active_model: A)
806 where
807 E: EntityTrait,
808 A: ActiveModelTrait<Entity = E>,
809 {
810 assert_eq!(
811 E::find().build(DbBackend::Postgres).to_string(),
812 r#"SELECT "hello"."id", "hello"."one1", "hello"."two", "hello"."three3" FROM "hello""#,
813 );
814 assert_eq!(
815 Update::one(active_model)
816 .validate()
817 .unwrap()
818 .build(DbBackend::Postgres)
819 .to_string(),
820 r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
821 );
822 }
823
824 assert_it(hello_expanded::ActiveModel {
825 id: ActiveValue::set(1),
826 one: ActiveValue::set(1),
827 two: ActiveValue::set(2),
828 three: ActiveValue::set(3),
829 });
830 assert_it(hello_compact::ActiveModel {
831 id: ActiveValue::set(1),
832 one: ActiveValue::set(1),
833 two: ActiveValue::set(2),
834 three: ActiveValue::set(3),
835 });
836 }
837
838 #[test]
839 #[cfg(feature = "macros")]
840 fn select_as_and_value_1() {
841 use crate::{ActiveModelTrait, ActiveValue, Update};
842
843 mod hello_expanded {
844 use crate as sea_orm;
845 use crate::entity::prelude::*;
846 use crate::sea_query::{Expr, ExprTrait};
847
848 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
849 pub struct Entity;
850
851 impl EntityName for Entity {
852 fn table_name(&self) -> &'static str {
853 "hello"
854 }
855 }
856
857 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
858 pub struct Model {
859 pub id: i32,
860 #[sea_orm(enum_name = "One1")]
861 pub one: i32,
862 pub two: i32,
863 #[sea_orm(enum_name = "Three3")]
864 pub three: i32,
865 }
866
867 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
868 pub enum Column {
869 Id,
870 One1,
871 Two,
872 Three3,
873 }
874
875 impl ColumnTrait for Column {
876 type EntityName = Entity;
877
878 fn def(&self) -> ColumnDef {
879 match self {
880 Column::Id => ColumnType::Integer.def(),
881 Column::One1 => ColumnType::Integer.def(),
882 Column::Two => ColumnType::Integer.def(),
883 Column::Three3 => ColumnType::Integer.def(),
884 }
885 }
886
887 fn select_as(&self, expr: Expr) -> Expr {
888 match self {
889 Self::Two => expr.cast_as("integer"),
890 _ => self.select_enum_as(expr),
891 }
892 }
893
894 fn save_as(&self, val: Expr) -> Expr {
895 match self {
896 Self::Two => val.cast_as("text"),
897 _ => self.save_enum_as(val),
898 }
899 }
900 }
901
902 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
903 pub enum PrimaryKey {
904 Id,
905 }
906
907 impl PrimaryKeyTrait for PrimaryKey {
908 type ValueType = i32;
909
910 fn auto_increment() -> bool {
911 true
912 }
913 }
914
915 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
916 pub enum Relation {}
917
918 impl ActiveModelBehavior for ActiveModel {}
919 }
920
921 #[allow(clippy::enum_variant_names)]
922 mod hello_compact {
923 use crate as sea_orm;
924 use crate::entity::prelude::*;
925
926 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
927 #[sea_orm(table_name = "hello")]
928 pub struct Model {
929 #[sea_orm(primary_key)]
930 pub id: i32,
931 #[sea_orm(enum_name = "One1")]
932 pub one: i32,
933 #[sea_orm(select_as = "integer", save_as = "text")]
934 pub two: i32,
935 #[sea_orm(enum_name = "Three3")]
936 pub three: i32,
937 }
938
939 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
940 pub enum Relation {}
941
942 impl ActiveModelBehavior for ActiveModel {}
943 }
944
945 fn assert_it<E, A>(active_model: A)
946 where
947 E: EntityTrait,
948 A: ActiveModelTrait<Entity = E>,
949 {
950 assert_eq!(
951 E::find().build(DbBackend::Postgres).to_string(),
952 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
953 );
954 assert_eq!(
955 Update::one(active_model)
956 .validate()
957 .unwrap()
958 .build(DbBackend::Postgres)
959 .to_string(),
960 r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
961 );
962 }
963
964 assert_it(hello_expanded::ActiveModel {
965 id: ActiveValue::set(1),
966 one: ActiveValue::set(1),
967 two: ActiveValue::set(2),
968 three: ActiveValue::set(3),
969 });
970 assert_it(hello_compact::ActiveModel {
971 id: ActiveValue::set(1),
972 one: ActiveValue::set(1),
973 two: ActiveValue::set(2),
974 three: ActiveValue::set(3),
975 });
976 }
977}