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::postgres_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 {
93 type EntityName: EntityName;
95
96 fn def(&self) -> ColumnDef;
98
99 fn enum_type_name(&self) -> Option<&'static str> {
102 None
103 }
104
105 fn entity_name(&self) -> DynIden {
107 SeaRc::new(Self::EntityName::default())
108 }
109
110 fn as_column_ref(&self) -> (DynIden, DynIden) {
113 (self.entity_name(), SeaRc::new(*self))
114 }
115
116 fn eq<V>(&self, v: V) -> Expr
136 where
137 V: Into<Value>,
138 {
139 let v = v.into();
140 if v == v.as_null() {
141 Expr::col(self.as_column_ref()).is_null()
142 } else {
143 let expr = self.save_as(Expr::val(v));
144 Expr::col(self.as_column_ref()).eq(expr)
145 }
146 }
147
148 fn ne<V>(&self, v: V) -> Expr
168 where
169 V: Into<Value>,
170 {
171 let v = v.into();
172 if v == v.as_null() {
173 Expr::col(self.as_column_ref()).is_not_null()
174 } else {
175 let expr = self.save_as(Expr::val(v));
176 Expr::col(self.as_column_ref()).ne(expr)
177 }
178 }
179
180 bind_oper!(gt, GreaterThan);
181 bind_oper!(gte, GreaterThanOrEqual);
182 bind_oper!(lt, SmallerThan);
183 bind_oper!(lte, SmallerThanOrEqual);
184
185 fn between<V>(&self, a: V, b: V) -> Expr
197 where
198 V: Into<Value>,
199 {
200 Expr::col(self.as_column_ref()).between(a, b)
201 }
202
203 fn not_between<V>(&self, a: V, b: V) -> Expr
215 where
216 V: Into<Value>,
217 {
218 Expr::col(self.as_column_ref()).not_between(a, b)
219 }
220
221 fn like<T>(&self, s: T) -> Expr
233 where
234 T: IntoLikeExpr,
235 {
236 Expr::col(self.as_column_ref()).like(s)
237 }
238
239 fn not_like<T>(&self, s: T) -> Expr
251 where
252 T: IntoLikeExpr,
253 {
254 Expr::col(self.as_column_ref()).not_like(s)
255 }
256
257 fn ilike<T>(&self, s: T) -> Expr
270 where
271 T: IntoLikeExpr,
272 {
273 use sea_query::extension::postgres::PgExpr;
274
275 Expr::col(self.as_column_ref()).ilike(s)
276 }
277
278 fn not_ilike<T>(&self, s: T) -> Expr
291 where
292 T: IntoLikeExpr,
293 {
294 use sea_query::extension::postgres::PgExpr;
295
296 Expr::col(self.as_column_ref()).not_ilike(s)
297 }
298
299 fn starts_with<T>(&self, s: T) -> Expr
316 where
317 T: Into<String>,
318 {
319 let pattern = format!("{}%", s.into());
320 Expr::col(self.as_column_ref()).like(pattern)
321 }
322
323 fn ends_with<T>(&self, s: T) -> Expr
340 where
341 T: Into<String>,
342 {
343 let pattern = format!("%{}", s.into());
344 Expr::col(self.as_column_ref()).like(pattern)
345 }
346
347 fn contains<T>(&self, s: T) -> Expr
364 where
365 T: Into<String>,
366 {
367 let pattern = format!("%{}%", s.into());
368 Expr::col(self.as_column_ref()).like(pattern)
369 }
370
371 bind_func_no_params!(max);
372 bind_func_no_params!(min);
373 bind_func_no_params!(sum);
374 bind_func_no_params!(avg);
375 bind_func_no_params!(count);
376 bind_func_no_params!(is_null);
377 bind_func_no_params!(is_not_null);
378
379 fn if_null<V>(&self, v: V) -> Expr
381 where
382 V: Into<Value>,
383 {
384 Expr::col(self.as_column_ref()).if_null(v)
385 }
386
387 bind_vec_func!(is_in);
388 bind_vec_func!(is_not_in);
389
390 #[cfg(feature = "postgres-array")]
433 fn eq_any<V, I>(&self, v: I) -> Expr
434 where
435 V: Into<Value> + sea_query::postgres_array::NotU8,
436 I: IntoIterator<Item = V>,
437 {
438 use sea_query::extension::postgres::PgFunc;
439
440 let values: Vec<Value> = v.into_iter().map(|v| v.into()).collect();
441
442 if let Some(first) = values.first() {
443 let array = Value::Array(first.array_type(), Some(Box::new(values)));
444 Expr::col(self.as_column_ref()).eq(PgFunc::any(self.save_array_as(Expr::val(array))))
445 } else {
446 Expr::col(self.as_column_ref()).is_in(std::iter::empty::<V>())
447 }
448 }
449
450 #[cfg(feature = "postgres-array")]
470 fn ne_all<V, I>(&self, v: I) -> Expr
471 where
472 V: Into<Value> + sea_query::postgres_array::NotU8,
473 I: IntoIterator<Item = V>,
474 {
475 use sea_query::extension::postgres::PgFunc;
476
477 let values: Vec<Value> = v.into_iter().map(|v| v.into()).collect();
478
479 if let Some(first) = values.first() {
480 let array = Value::Array(first.array_type(), Some(Box::new(values)));
481 Expr::col(self.as_column_ref()).ne(PgFunc::all(self.save_array_as(Expr::val(array))))
482 } else {
483 Expr::col(self.as_column_ref()).is_not_in(std::iter::empty::<V>())
484 }
485 }
486
487 bind_subquery_func!(in_subquery);
488 bind_subquery_func!(not_in_subquery);
489
490 bind_array_oper!(array_contains, Contains);
491 bind_array_oper!(array_contained, Contained);
492 bind_array_oper!(array_overlap, Overlap);
493
494 fn into_expr(self) -> Expr {
497 self.into_simple_expr()
498 }
499
500 #[allow(clippy::match_single_binding)]
503 fn into_returning_expr(self, db_backend: DbBackend) -> Expr {
504 match db_backend {
505 _ => Expr::col(self),
506 }
507 }
508
509 fn select_as(&self, expr: Expr) -> Expr {
512 self.select_enum_as(expr)
513 }
514
515 fn select_enum_as(&self, expr: Expr) -> Expr {
517 cast_enum_as(expr, &self.def(), select_enum_as)
518 }
519
520 fn save_as(&self, val: Expr) -> Expr {
523 self.save_enum_as(val)
524 }
525
526 fn save_enum_as(&self, val: Expr) -> Expr {
528 cast_enum_as(val, &self.def(), save_enum_as)
529 }
530
531 fn save_array_as(&self, val: Expr) -> Expr {
535 val
536 }
537
538 #[cfg(feature = "with-json")]
540 fn json_key(&self) -> &'static str {
541 self.as_str()
542 }
543}
544
545pub trait ColumnTypeTrait {
548 fn def(self) -> ColumnDef;
550
551 fn get_enum_name(&self) -> Option<&DynIden>;
554}
555
556impl ColumnTypeTrait for ColumnType {
557 fn def(self) -> ColumnDef {
558 ColumnDef {
559 col_type: self,
560 null: false,
561 unique: false,
562 indexed: false,
563 default: None,
564 comment: None,
565 unique_key: None,
566 renamed_from: None,
567 extra: None,
568 seaography: Default::default(),
569 }
570 }
571
572 fn get_enum_name(&self) -> Option<&DynIden> {
573 enum_name(self)
574 }
575}
576
577impl ColumnTypeTrait for ColumnDef {
578 fn def(self) -> ColumnDef {
579 self
580 }
581
582 fn get_enum_name(&self) -> Option<&DynIden> {
583 enum_name(&self.col_type)
584 }
585}
586
587fn enum_name(col_type: &ColumnType) -> Option<&DynIden> {
588 match col_type {
589 ColumnType::Enum { name, .. } => Some(name),
590 ColumnType::Array(col_type) => enum_name(col_type),
591 _ => None,
592 }
593}
594
595struct Text;
596struct TextArray;
597
598impl Iden for Text {
599 fn quoted(&self) -> Cow<'static, str> {
600 Cow::Borrowed("text")
601 }
602
603 fn unquoted(&self) -> &str {
604 match self.quoted() {
605 Cow::Borrowed(s) => s,
606 _ => unreachable!(),
607 }
608 }
609}
610
611impl Iden for TextArray {
612 fn quoted(&self) -> Cow<'static, str> {
613 Cow::Borrowed("text[]")
615 }
616
617 fn unquoted(&self) -> &str {
618 match self.quoted() {
619 Cow::Borrowed(s) => s,
620 _ => unreachable!(),
621 }
622 }
623}
624
625pub(crate) fn select_enum_as(col: Expr, _: DynIden, col_type: &ColumnType) -> Expr {
626 let type_name = match col_type {
627 ColumnType::Array(_) => TextArray.into_iden(),
628 _ => Text.into_iden(),
629 };
630 col.as_enum(type_name)
631}
632
633pub(crate) fn save_enum_as(col: Expr, enum_name: DynIden, col_type: &ColumnType) -> Expr {
634 if matches!(col, Expr::Value(Value::Enum(_))) {
635 return col;
636 }
637 #[cfg(feature = "postgres-array")]
638 if matches!(
639 col,
640 Expr::Value(Value::Array(sea_query::ArrayType::Enum(_), _))
641 ) {
642 return col;
643 }
644
645 let type_name = match col_type {
646 ColumnType::Array(_) => format!("{enum_name}[]").into_iden(),
647 _ => enum_name,
648 };
649 col.as_enum(type_name)
650}
651
652pub(crate) fn cast_enum_as<F>(expr: Expr, col_def: &ColumnDef, f: F) -> Expr
653where
654 F: Fn(Expr, DynIden, &ColumnType) -> Expr,
655{
656 let col_type = col_def.get_column_type();
657
658 match col_type {
659 #[cfg(all(feature = "with-json", feature = "postgres-array"))]
660 ColumnType::Json | ColumnType::JsonBinary => {
661 use sea_query::ArrayType;
662 use serde_json::Value as Json;
663
664 match expr {
665 Expr::Value(Value::Array(ArrayType::Json, Some(json_vec))) => {
666 let json_vec: Vec<Json> = json_vec
668 .into_iter()
669 .filter_map(|val| match val {
670 Value::Json(Some(json)) => Some(*json),
671 _ => None,
672 })
673 .collect();
674 Expr::Value(Value::Json(Some(Box::new(json_vec.into()))))
675 }
676 Expr::Value(Value::Array(ArrayType::Json, None)) => Expr::Value(Value::Json(None)),
677 _ => expr,
678 }
679 }
680 _ => match col_type.get_enum_name() {
681 Some(enum_name) => f(expr, enum_name.clone(), col_type),
682 None => expr,
683 },
684 }
685}
686
687#[cfg(test)]
688mod tests {
689 use crate::{
690 ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait, tests_cfg::*,
691 };
692 use sea_query::Query;
693
694 #[test]
695 fn test_in_subquery_1() {
696 assert_eq!(
697 cake::Entity::find()
698 .filter(
699 Condition::any().add(
700 cake::Column::Id.in_subquery(
701 Query::select()
702 .expr(cake::Column::Id.max())
703 .from(cake::Entity)
704 .to_owned()
705 )
706 )
707 )
708 .build(DbBackend::MySql)
709 .to_string(),
710 [
711 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
712 "WHERE `cake`.`id` IN (SELECT MAX(`cake`.`id`) FROM `cake`)",
713 ]
714 .join(" ")
715 );
716 }
717
718 #[test]
719 fn test_in_subquery_2() {
720 assert_eq!(
721 cake::Entity::find()
722 .filter(
723 Condition::any().add(
724 cake::Column::Id.in_subquery(
725 Query::select()
726 .column(cake_filling::Column::CakeId)
727 .from(cake_filling::Entity)
728 .to_owned()
729 )
730 )
731 )
732 .build(DbBackend::MySql)
733 .to_string(),
734 [
735 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
736 "WHERE `cake`.`id` IN (SELECT `cake_id` FROM `cake_filling`)",
737 ]
738 .join(" ")
739 );
740 }
741
742 #[cfg(feature = "macros")]
743 mod select_as {
744 use super::*;
745
746 mod hello_expanded {
747 use crate as sea_orm;
748 use crate::entity::prelude::*;
749 use crate::sea_query::{Expr, ExprTrait};
750
751 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
752 pub struct Entity;
753
754 impl EntityName for Entity {
755 fn table_name(&self) -> &'static str {
756 "hello"
757 }
758 }
759
760 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
761 pub struct Model {
762 pub id: i32,
763 #[sea_orm(enum_name = "One1")]
764 pub one: i32,
765 pub two: i32,
766 #[sea_orm(enum_name = "Three3")]
767 pub three: i32,
768 }
769
770 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
771 pub enum Column {
772 Id,
773 One1,
774 Two,
775 Three3,
776 }
777
778 impl ColumnTrait for Column {
779 type EntityName = Entity;
780
781 fn def(&self) -> ColumnDef {
782 match self {
783 Column::Id => ColumnType::Integer.def(),
784 Column::One1 => ColumnType::Integer.def(),
785 Column::Two => ColumnType::Integer.def(),
786 Column::Three3 => ColumnType::Integer.def(),
787 }
788 }
789
790 fn select_as(&self, expr: Expr) -> Expr {
791 match self {
792 Self::Two => expr.cast_as("integer"),
793 _ => self.select_enum_as(expr),
794 }
795 }
796 }
797
798 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
799 pub enum PrimaryKey {
800 Id,
801 }
802
803 impl PrimaryKeyTrait for PrimaryKey {
804 type ValueType = i32;
805
806 fn auto_increment() -> bool {
807 true
808 }
809 }
810
811 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
812 pub enum Relation {}
813
814 impl ActiveModelBehavior for ActiveModel {}
815 }
816
817 #[allow(clippy::enum_variant_names)]
818 mod hello_compact {
819 use crate as sea_orm;
820 use crate::entity::prelude::*;
821
822 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
823 #[sea_orm(table_name = "hello")]
824 pub struct Model {
825 #[sea_orm(primary_key)]
826 pub id: i32,
827 #[sea_orm(enum_name = "One1")]
828 pub one: i32,
829 #[sea_orm(select_as = "integer")]
830 pub two: i32,
831 #[sea_orm(enum_name = "Three3")]
832 pub three: i32,
833 }
834
835 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
836 pub enum Relation {}
837
838 impl ActiveModelBehavior for ActiveModel {}
839 }
840
841 #[test]
842 fn select_as_1() {
843 use crate::{ActiveModelTrait, ActiveValue, Update};
844
845 fn assert_it<E, A>(active_model: A)
846 where
847 E: EntityTrait,
848 A: ActiveModelTrait<Entity = E>,
849 {
850 assert_eq!(
851 E::find().build(DbBackend::Postgres).to_string(),
852 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer) AS "two", "hello"."three3" FROM "hello""#,
853 );
854 assert_eq!(
855 Update::one(active_model)
856 .validate()
857 .unwrap()
858 .build(DbBackend::Postgres)
859 .to_string(),
860 r#"UPDATE "hello" SET "one1" = 1, "two" = 2, "three3" = 3 WHERE "hello"."id" = 1"#,
861 );
862 }
863
864 assert_it(hello_expanded::ActiveModel {
865 id: ActiveValue::set(1),
866 one: ActiveValue::set(1),
867 two: ActiveValue::set(2),
868 three: ActiveValue::set(3),
869 });
870 assert_it(hello_compact::ActiveModel {
871 id: ActiveValue::set(1),
872 one: ActiveValue::set(1),
873 two: ActiveValue::set(2),
874 three: ActiveValue::set(3),
875 });
876 }
877
878 #[test]
879 fn select_except_keeps_select_as_aliases() {
880 use crate::QuerySelect;
881
882 fn assert_it<E: EntityTrait>(except: E::Column) {
883 assert_eq!(
884 E::find()
885 .select_except([except])
886 .build(DbBackend::Postgres)
887 .to_string(),
888 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer) AS "two" FROM "hello""#,
889 );
890 assert_eq!(
891 E::find()
892 .select_except([except])
893 .select_also(E::default())
894 .build(DbBackend::Postgres)
895 .to_string(),
896 r#"SELECT "hello"."id" AS "A_id", "hello"."one1" AS "A_one1", CAST("hello"."two" AS integer) AS "A_two", "hello"."id" AS "B_id", "hello"."one1" AS "B_one1", CAST("hello"."two" AS integer) AS "B_two", "hello"."three3" AS "B_three3" FROM "hello""#,
897 );
898 }
899
900 assert_it::<hello_expanded::Entity>(hello_expanded::Column::Three3);
901 assert_it::<hello_compact::Entity>(hello_compact::Column::Three3);
902 }
903
904 #[test]
905 fn select_as_columns_keep_aliases_in_multi_selects() {
906 use crate::{Iterable, QuerySelect};
907
908 fn assert_it<E: EntityTrait>() {
909 for select in [
910 E::find(),
911 E::find().select_only().columns(E::Column::iter()),
912 ] {
913 assert_eq!(
914 select
915 .select_also(E::default())
916 .build(DbBackend::Postgres)
917 .to_string(),
918 r#"SELECT "hello"."id" AS "A_id", "hello"."one1" AS "A_one1", CAST("hello"."two" AS integer) AS "A_two", "hello"."three3" AS "A_three3", "hello"."id" AS "B_id", "hello"."one1" AS "B_one1", CAST("hello"."two" AS integer) AS "B_two", "hello"."three3" AS "B_three3" FROM "hello""#,
919 );
920 }
921 }
922
923 assert_it::<hello_expanded::Entity>();
924 assert_it::<hello_compact::Entity>();
925 }
926 }
927
928 #[test]
929 #[cfg(feature = "macros")]
930 fn save_as_1() {
931 use crate::{ActiveModelTrait, ActiveValue, Update};
932
933 mod hello_expanded {
934 use crate as sea_orm;
935 use crate::entity::prelude::*;
936 use crate::sea_query::{Expr, ExprTrait};
937
938 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
939 pub struct Entity;
940
941 impl EntityName for Entity {
942 fn table_name(&self) -> &'static str {
943 "hello"
944 }
945 }
946
947 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
948 pub struct Model {
949 pub id: i32,
950 #[sea_orm(enum_name = "One1")]
951 pub one: i32,
952 pub two: i32,
953 #[sea_orm(enum_name = "Three3")]
954 pub three: i32,
955 }
956
957 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
958 pub enum Column {
959 Id,
960 One1,
961 Two,
962 Three3,
963 }
964
965 impl ColumnTrait for Column {
966 type EntityName = Entity;
967
968 fn def(&self) -> ColumnDef {
969 match self {
970 Column::Id => ColumnType::Integer.def(),
971 Column::One1 => ColumnType::Integer.def(),
972 Column::Two => ColumnType::Integer.def(),
973 Column::Three3 => ColumnType::Integer.def(),
974 }
975 }
976
977 fn save_as(&self, val: Expr) -> Expr {
978 match self {
979 Self::Two => val.cast_as("text"),
980 _ => self.save_enum_as(val),
981 }
982 }
983 }
984
985 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
986 pub enum PrimaryKey {
987 Id,
988 }
989
990 impl PrimaryKeyTrait for PrimaryKey {
991 type ValueType = i32;
992
993 fn auto_increment() -> bool {
994 true
995 }
996 }
997
998 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
999 pub enum Relation {}
1000
1001 impl ActiveModelBehavior for ActiveModel {}
1002 }
1003
1004 #[allow(clippy::enum_variant_names)]
1005 mod hello_compact {
1006 use crate as sea_orm;
1007 use crate::entity::prelude::*;
1008
1009 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1010 #[sea_orm(table_name = "hello")]
1011 pub struct Model {
1012 #[sea_orm(primary_key)]
1013 pub id: i32,
1014 #[sea_orm(enum_name = "One1")]
1015 pub one: i32,
1016 #[sea_orm(save_as = "text")]
1017 pub two: i32,
1018 #[sea_orm(enum_name = "Three3")]
1019 pub three: i32,
1020 }
1021
1022 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1023 pub enum Relation {}
1024
1025 impl ActiveModelBehavior for ActiveModel {}
1026 }
1027
1028 fn assert_it<E, A>(active_model: A)
1029 where
1030 E: EntityTrait,
1031 A: ActiveModelTrait<Entity = E>,
1032 {
1033 assert_eq!(
1034 E::find().build(DbBackend::Postgres).to_string(),
1035 r#"SELECT "hello"."id", "hello"."one1", "hello"."two", "hello"."three3" FROM "hello""#,
1036 );
1037 assert_eq!(
1038 Update::one(active_model)
1039 .validate()
1040 .unwrap()
1041 .build(DbBackend::Postgres)
1042 .to_string(),
1043 r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
1044 );
1045 }
1046
1047 assert_it(hello_expanded::ActiveModel {
1048 id: ActiveValue::set(1),
1049 one: ActiveValue::set(1),
1050 two: ActiveValue::set(2),
1051 three: ActiveValue::set(3),
1052 });
1053 assert_it(hello_compact::ActiveModel {
1054 id: ActiveValue::set(1),
1055 one: ActiveValue::set(1),
1056 two: ActiveValue::set(2),
1057 three: ActiveValue::set(3),
1058 });
1059 }
1060
1061 #[test]
1062 #[cfg(feature = "macros")]
1063 fn select_as_and_value_1() {
1064 use crate::{ActiveModelTrait, ActiveValue, Update};
1065
1066 mod hello_expanded {
1067 use crate as sea_orm;
1068 use crate::entity::prelude::*;
1069 use crate::sea_query::{Expr, ExprTrait};
1070
1071 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
1072 pub struct Entity;
1073
1074 impl EntityName for Entity {
1075 fn table_name(&self) -> &'static str {
1076 "hello"
1077 }
1078 }
1079
1080 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
1081 pub struct Model {
1082 pub id: i32,
1083 #[sea_orm(enum_name = "One1")]
1084 pub one: i32,
1085 pub two: i32,
1086 #[sea_orm(enum_name = "Three3")]
1087 pub three: i32,
1088 }
1089
1090 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
1091 pub enum Column {
1092 Id,
1093 One1,
1094 Two,
1095 Three3,
1096 }
1097
1098 impl ColumnTrait for Column {
1099 type EntityName = Entity;
1100
1101 fn def(&self) -> ColumnDef {
1102 match self {
1103 Column::Id => ColumnType::Integer.def(),
1104 Column::One1 => ColumnType::Integer.def(),
1105 Column::Two => ColumnType::Integer.def(),
1106 Column::Three3 => ColumnType::Integer.def(),
1107 }
1108 }
1109
1110 fn select_as(&self, expr: Expr) -> Expr {
1111 match self {
1112 Self::Two => expr.cast_as("integer"),
1113 _ => self.select_enum_as(expr),
1114 }
1115 }
1116
1117 fn save_as(&self, val: Expr) -> Expr {
1118 match self {
1119 Self::Two => val.cast_as("text"),
1120 _ => self.save_enum_as(val),
1121 }
1122 }
1123 }
1124
1125 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
1126 pub enum PrimaryKey {
1127 Id,
1128 }
1129
1130 impl PrimaryKeyTrait for PrimaryKey {
1131 type ValueType = i32;
1132
1133 fn auto_increment() -> bool {
1134 true
1135 }
1136 }
1137
1138 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1139 pub enum Relation {}
1140
1141 impl ActiveModelBehavior for ActiveModel {}
1142 }
1143
1144 #[allow(clippy::enum_variant_names)]
1145 mod hello_compact {
1146 use crate as sea_orm;
1147 use crate::entity::prelude::*;
1148
1149 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1150 #[sea_orm(table_name = "hello")]
1151 pub struct Model {
1152 #[sea_orm(primary_key)]
1153 pub id: i32,
1154 #[sea_orm(enum_name = "One1")]
1155 pub one: i32,
1156 #[sea_orm(select_as = "integer", save_as = "text")]
1157 pub two: i32,
1158 #[sea_orm(enum_name = "Three3")]
1159 pub three: i32,
1160 }
1161
1162 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1163 pub enum Relation {}
1164
1165 impl ActiveModelBehavior for ActiveModel {}
1166 }
1167
1168 fn assert_it<E, A>(active_model: A)
1169 where
1170 E: EntityTrait,
1171 A: ActiveModelTrait<Entity = E>,
1172 {
1173 assert_eq!(
1174 E::find().build(DbBackend::Postgres).to_string(),
1175 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer) AS "two", "hello"."three3" FROM "hello""#,
1176 );
1177 assert_eq!(
1178 Update::one(active_model)
1179 .validate()
1180 .unwrap()
1181 .build(DbBackend::Postgres)
1182 .to_string(),
1183 r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
1184 );
1185 }
1186
1187 assert_it(hello_expanded::ActiveModel {
1188 id: ActiveValue::set(1),
1189 one: ActiveValue::set(1),
1190 two: ActiveValue::set(2),
1191 three: ActiveValue::set(3),
1192 });
1193 assert_it(hello_compact::ActiveModel {
1194 id: ActiveValue::set(1),
1195 one: ActiveValue::set(1),
1196 two: ActiveValue::set(2),
1197 three: ActiveValue::set(3),
1198 });
1199 }
1200}