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 Expr::col(self.as_column_ref()).eq(PgFunc::any(Value::Array(
444 first.array_type(),
445 Some(Box::new(values)),
446 )))
447 } else {
448 Expr::col(self.as_column_ref()).is_in(std::iter::empty::<V>())
449 }
450 }
451
452 #[cfg(feature = "postgres-array")]
472 fn ne_all<V, I>(&self, v: I) -> Expr
473 where
474 V: Into<Value> + sea_query::postgres_array::NotU8,
475 I: IntoIterator<Item = V>,
476 {
477 use sea_query::extension::postgres::PgFunc;
478
479 let values: Vec<Value> = v.into_iter().map(|v| v.into()).collect();
480
481 if let Some(first) = values.first() {
482 Expr::col(self.as_column_ref()).ne(PgFunc::all(Value::Array(
483 first.array_type(),
484 Some(Box::new(values)),
485 )))
486 } else {
487 Expr::col(self.as_column_ref()).is_not_in(std::iter::empty::<V>())
488 }
489 }
490
491 bind_subquery_func!(in_subquery);
492 bind_subquery_func!(not_in_subquery);
493
494 bind_array_oper!(array_contains, Contains);
495 bind_array_oper!(array_contained, Contained);
496 bind_array_oper!(array_overlap, Overlap);
497
498 fn into_expr(self) -> Expr {
501 self.into_simple_expr()
502 }
503
504 #[allow(clippy::match_single_binding)]
507 fn into_returning_expr(self, db_backend: DbBackend) -> Expr {
508 match db_backend {
509 _ => Expr::col(self),
510 }
511 }
512
513 fn select_as(&self, expr: Expr) -> Expr {
516 self.select_enum_as(expr)
517 }
518
519 fn select_enum_as(&self, expr: Expr) -> Expr {
521 cast_enum_as(expr, &self.def(), select_enum_as)
522 }
523
524 fn save_as(&self, val: Expr) -> Expr {
527 self.save_enum_as(val)
528 }
529
530 fn save_enum_as(&self, val: Expr) -> Expr {
532 cast_enum_as(val, &self.def(), save_enum_as)
533 }
534
535 #[cfg(feature = "with-json")]
537 fn json_key(&self) -> &'static str {
538 self.as_str()
539 }
540}
541
542pub trait ColumnTypeTrait {
545 fn def(self) -> ColumnDef;
547
548 fn get_enum_name(&self) -> Option<&DynIden>;
551}
552
553impl ColumnTypeTrait for ColumnType {
554 fn def(self) -> ColumnDef {
555 ColumnDef {
556 col_type: self,
557 null: false,
558 unique: false,
559 indexed: false,
560 default: None,
561 comment: None,
562 unique_key: None,
563 renamed_from: None,
564 extra: None,
565 seaography: Default::default(),
566 }
567 }
568
569 fn get_enum_name(&self) -> Option<&DynIden> {
570 enum_name(self)
571 }
572}
573
574impl ColumnTypeTrait for ColumnDef {
575 fn def(self) -> ColumnDef {
576 self
577 }
578
579 fn get_enum_name(&self) -> Option<&DynIden> {
580 enum_name(&self.col_type)
581 }
582}
583
584fn enum_name(col_type: &ColumnType) -> Option<&DynIden> {
585 match col_type {
586 ColumnType::Enum { name, .. } => Some(name),
587 ColumnType::Array(col_type) => enum_name(col_type),
588 _ => None,
589 }
590}
591
592struct Text;
593struct TextArray;
594
595impl Iden for Text {
596 fn quoted(&self) -> Cow<'static, str> {
597 Cow::Borrowed("text")
598 }
599
600 fn unquoted(&self) -> &str {
601 match self.quoted() {
602 Cow::Borrowed(s) => s,
603 _ => unreachable!(),
604 }
605 }
606}
607
608impl Iden for TextArray {
609 fn quoted(&self) -> Cow<'static, str> {
610 Cow::Borrowed("text[]")
612 }
613
614 fn unquoted(&self) -> &str {
615 match self.quoted() {
616 Cow::Borrowed(s) => s,
617 _ => unreachable!(),
618 }
619 }
620}
621
622pub(crate) fn select_enum_as(col: Expr, _: DynIden, col_type: &ColumnType) -> Expr {
623 let type_name = match col_type {
624 ColumnType::Array(_) => TextArray.into_iden(),
625 _ => Text.into_iden(),
626 };
627 col.as_enum(type_name)
628}
629
630pub(crate) fn save_enum_as(col: Expr, enum_name: DynIden, col_type: &ColumnType) -> Expr {
631 if matches!(col, Expr::Value(Value::Enum(_))) {
632 return col;
633 }
634 #[cfg(feature = "postgres-array")]
635 if matches!(
636 col,
637 Expr::Value(Value::Array(sea_query::ArrayType::Enum(_), _))
638 ) {
639 return col;
640 }
641
642 let type_name = match col_type {
643 ColumnType::Array(_) => format!("{enum_name}[]").into_iden(),
644 _ => enum_name,
645 };
646 col.as_enum(type_name)
647}
648
649pub(crate) fn cast_enum_as<F>(expr: Expr, col_def: &ColumnDef, f: F) -> Expr
650where
651 F: Fn(Expr, DynIden, &ColumnType) -> Expr,
652{
653 let col_type = col_def.get_column_type();
654
655 match col_type {
656 #[cfg(all(feature = "with-json", feature = "postgres-array"))]
657 ColumnType::Json | ColumnType::JsonBinary => {
658 use sea_query::ArrayType;
659 use serde_json::Value as Json;
660
661 match expr {
662 Expr::Value(Value::Array(ArrayType::Json, Some(json_vec))) => {
663 let json_vec: Vec<Json> = json_vec
665 .into_iter()
666 .filter_map(|val| match val {
667 Value::Json(Some(json)) => Some(*json),
668 _ => None,
669 })
670 .collect();
671 Expr::Value(Value::Json(Some(Box::new(json_vec.into()))))
672 }
673 Expr::Value(Value::Array(ArrayType::Json, None)) => Expr::Value(Value::Json(None)),
674 _ => expr,
675 }
676 }
677 _ => match col_type.get_enum_name() {
678 Some(enum_name) => f(expr, enum_name.clone(), col_type),
679 None => expr,
680 },
681 }
682}
683
684#[cfg(test)]
685mod tests {
686 use crate::{
687 ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait, tests_cfg::*,
688 };
689 use sea_query::Query;
690
691 #[test]
692 fn test_in_subquery_1() {
693 assert_eq!(
694 cake::Entity::find()
695 .filter(
696 Condition::any().add(
697 cake::Column::Id.in_subquery(
698 Query::select()
699 .expr(cake::Column::Id.max())
700 .from(cake::Entity)
701 .to_owned()
702 )
703 )
704 )
705 .build(DbBackend::MySql)
706 .to_string(),
707 [
708 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
709 "WHERE `cake`.`id` IN (SELECT MAX(`cake`.`id`) FROM `cake`)",
710 ]
711 .join(" ")
712 );
713 }
714
715 #[test]
716 fn test_in_subquery_2() {
717 assert_eq!(
718 cake::Entity::find()
719 .filter(
720 Condition::any().add(
721 cake::Column::Id.in_subquery(
722 Query::select()
723 .column(cake_filling::Column::CakeId)
724 .from(cake_filling::Entity)
725 .to_owned()
726 )
727 )
728 )
729 .build(DbBackend::MySql)
730 .to_string(),
731 [
732 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
733 "WHERE `cake`.`id` IN (SELECT `cake_id` FROM `cake_filling`)",
734 ]
735 .join(" ")
736 );
737 }
738
739 #[test]
740 #[cfg(feature = "macros")]
741 fn select_as_1() {
742 use crate::{ActiveModelTrait, ActiveValue, Update};
743
744 mod hello_expanded {
745 use crate as sea_orm;
746 use crate::entity::prelude::*;
747 use crate::sea_query::{Expr, ExprTrait};
748
749 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
750 pub struct Entity;
751
752 impl EntityName for Entity {
753 fn table_name(&self) -> &'static str {
754 "hello"
755 }
756 }
757
758 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
759 pub struct Model {
760 pub id: i32,
761 #[sea_orm(enum_name = "One1")]
762 pub one: i32,
763 pub two: i32,
764 #[sea_orm(enum_name = "Three3")]
765 pub three: i32,
766 }
767
768 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
769 pub enum Column {
770 Id,
771 One1,
772 Two,
773 Three3,
774 }
775
776 impl ColumnTrait for Column {
777 type EntityName = Entity;
778
779 fn def(&self) -> ColumnDef {
780 match self {
781 Column::Id => ColumnType::Integer.def(),
782 Column::One1 => ColumnType::Integer.def(),
783 Column::Two => ColumnType::Integer.def(),
784 Column::Three3 => ColumnType::Integer.def(),
785 }
786 }
787
788 fn select_as(&self, expr: Expr) -> Expr {
789 match self {
790 Self::Two => expr.cast_as("integer"),
791 _ => self.select_enum_as(expr),
792 }
793 }
794 }
795
796 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
797 pub enum PrimaryKey {
798 Id,
799 }
800
801 impl PrimaryKeyTrait for PrimaryKey {
802 type ValueType = i32;
803
804 fn auto_increment() -> bool {
805 true
806 }
807 }
808
809 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
810 pub enum Relation {}
811
812 impl ActiveModelBehavior for ActiveModel {}
813 }
814
815 #[allow(clippy::enum_variant_names)]
816 mod hello_compact {
817 use crate as sea_orm;
818 use crate::entity::prelude::*;
819
820 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
821 #[sea_orm(table_name = "hello")]
822 pub struct Model {
823 #[sea_orm(primary_key)]
824 pub id: i32,
825 #[sea_orm(enum_name = "One1")]
826 pub one: i32,
827 #[sea_orm(select_as = "integer")]
828 pub two: i32,
829 #[sea_orm(enum_name = "Three3")]
830 pub three: i32,
831 }
832
833 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
834 pub enum Relation {}
835
836 impl ActiveModelBehavior for ActiveModel {}
837 }
838
839 fn assert_it<E, A>(active_model: A)
840 where
841 E: EntityTrait,
842 A: ActiveModelTrait<Entity = E>,
843 {
844 assert_eq!(
845 E::find().build(DbBackend::Postgres).to_string(),
846 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
847 );
848 assert_eq!(
849 Update::one(active_model)
850 .validate()
851 .unwrap()
852 .build(DbBackend::Postgres)
853 .to_string(),
854 r#"UPDATE "hello" SET "one1" = 1, "two" = 2, "three3" = 3 WHERE "hello"."id" = 1"#,
855 );
856 }
857
858 assert_it(hello_expanded::ActiveModel {
859 id: ActiveValue::set(1),
860 one: ActiveValue::set(1),
861 two: ActiveValue::set(2),
862 three: ActiveValue::set(3),
863 });
864 assert_it(hello_compact::ActiveModel {
865 id: ActiveValue::set(1),
866 one: ActiveValue::set(1),
867 two: ActiveValue::set(2),
868 three: ActiveValue::set(3),
869 });
870 }
871
872 #[test]
873 #[cfg(feature = "macros")]
874 fn save_as_1() {
875 use crate::{ActiveModelTrait, ActiveValue, Update};
876
877 mod hello_expanded {
878 use crate as sea_orm;
879 use crate::entity::prelude::*;
880 use crate::sea_query::{Expr, ExprTrait};
881
882 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
883 pub struct Entity;
884
885 impl EntityName for Entity {
886 fn table_name(&self) -> &'static str {
887 "hello"
888 }
889 }
890
891 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
892 pub struct Model {
893 pub id: i32,
894 #[sea_orm(enum_name = "One1")]
895 pub one: i32,
896 pub two: i32,
897 #[sea_orm(enum_name = "Three3")]
898 pub three: i32,
899 }
900
901 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
902 pub enum Column {
903 Id,
904 One1,
905 Two,
906 Three3,
907 }
908
909 impl ColumnTrait for Column {
910 type EntityName = Entity;
911
912 fn def(&self) -> ColumnDef {
913 match self {
914 Column::Id => ColumnType::Integer.def(),
915 Column::One1 => ColumnType::Integer.def(),
916 Column::Two => ColumnType::Integer.def(),
917 Column::Three3 => ColumnType::Integer.def(),
918 }
919 }
920
921 fn save_as(&self, val: Expr) -> Expr {
922 match self {
923 Self::Two => val.cast_as("text"),
924 _ => self.save_enum_as(val),
925 }
926 }
927 }
928
929 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
930 pub enum PrimaryKey {
931 Id,
932 }
933
934 impl PrimaryKeyTrait for PrimaryKey {
935 type ValueType = i32;
936
937 fn auto_increment() -> bool {
938 true
939 }
940 }
941
942 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
943 pub enum Relation {}
944
945 impl ActiveModelBehavior for ActiveModel {}
946 }
947
948 #[allow(clippy::enum_variant_names)]
949 mod hello_compact {
950 use crate as sea_orm;
951 use crate::entity::prelude::*;
952
953 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
954 #[sea_orm(table_name = "hello")]
955 pub struct Model {
956 #[sea_orm(primary_key)]
957 pub id: i32,
958 #[sea_orm(enum_name = "One1")]
959 pub one: i32,
960 #[sea_orm(save_as = "text")]
961 pub two: i32,
962 #[sea_orm(enum_name = "Three3")]
963 pub three: i32,
964 }
965
966 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
967 pub enum Relation {}
968
969 impl ActiveModelBehavior for ActiveModel {}
970 }
971
972 fn assert_it<E, A>(active_model: A)
973 where
974 E: EntityTrait,
975 A: ActiveModelTrait<Entity = E>,
976 {
977 assert_eq!(
978 E::find().build(DbBackend::Postgres).to_string(),
979 r#"SELECT "hello"."id", "hello"."one1", "hello"."two", "hello"."three3" FROM "hello""#,
980 );
981 assert_eq!(
982 Update::one(active_model)
983 .validate()
984 .unwrap()
985 .build(DbBackend::Postgres)
986 .to_string(),
987 r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
988 );
989 }
990
991 assert_it(hello_expanded::ActiveModel {
992 id: ActiveValue::set(1),
993 one: ActiveValue::set(1),
994 two: ActiveValue::set(2),
995 three: ActiveValue::set(3),
996 });
997 assert_it(hello_compact::ActiveModel {
998 id: ActiveValue::set(1),
999 one: ActiveValue::set(1),
1000 two: ActiveValue::set(2),
1001 three: ActiveValue::set(3),
1002 });
1003 }
1004
1005 #[test]
1006 #[cfg(feature = "macros")]
1007 fn select_as_and_value_1() {
1008 use crate::{ActiveModelTrait, ActiveValue, Update};
1009
1010 mod hello_expanded {
1011 use crate as sea_orm;
1012 use crate::entity::prelude::*;
1013 use crate::sea_query::{Expr, ExprTrait};
1014
1015 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
1016 pub struct Entity;
1017
1018 impl EntityName for Entity {
1019 fn table_name(&self) -> &'static str {
1020 "hello"
1021 }
1022 }
1023
1024 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
1025 pub struct Model {
1026 pub id: i32,
1027 #[sea_orm(enum_name = "One1")]
1028 pub one: i32,
1029 pub two: i32,
1030 #[sea_orm(enum_name = "Three3")]
1031 pub three: i32,
1032 }
1033
1034 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
1035 pub enum Column {
1036 Id,
1037 One1,
1038 Two,
1039 Three3,
1040 }
1041
1042 impl ColumnTrait for Column {
1043 type EntityName = Entity;
1044
1045 fn def(&self) -> ColumnDef {
1046 match self {
1047 Column::Id => ColumnType::Integer.def(),
1048 Column::One1 => ColumnType::Integer.def(),
1049 Column::Two => ColumnType::Integer.def(),
1050 Column::Three3 => ColumnType::Integer.def(),
1051 }
1052 }
1053
1054 fn select_as(&self, expr: Expr) -> Expr {
1055 match self {
1056 Self::Two => expr.cast_as("integer"),
1057 _ => self.select_enum_as(expr),
1058 }
1059 }
1060
1061 fn save_as(&self, val: Expr) -> Expr {
1062 match self {
1063 Self::Two => val.cast_as("text"),
1064 _ => self.save_enum_as(val),
1065 }
1066 }
1067 }
1068
1069 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
1070 pub enum PrimaryKey {
1071 Id,
1072 }
1073
1074 impl PrimaryKeyTrait for PrimaryKey {
1075 type ValueType = i32;
1076
1077 fn auto_increment() -> bool {
1078 true
1079 }
1080 }
1081
1082 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1083 pub enum Relation {}
1084
1085 impl ActiveModelBehavior for ActiveModel {}
1086 }
1087
1088 #[allow(clippy::enum_variant_names)]
1089 mod hello_compact {
1090 use crate as sea_orm;
1091 use crate::entity::prelude::*;
1092
1093 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1094 #[sea_orm(table_name = "hello")]
1095 pub struct Model {
1096 #[sea_orm(primary_key)]
1097 pub id: i32,
1098 #[sea_orm(enum_name = "One1")]
1099 pub one: i32,
1100 #[sea_orm(select_as = "integer", save_as = "text")]
1101 pub two: i32,
1102 #[sea_orm(enum_name = "Three3")]
1103 pub three: i32,
1104 }
1105
1106 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1107 pub enum Relation {}
1108
1109 impl ActiveModelBehavior for ActiveModel {}
1110 }
1111
1112 fn assert_it<E, A>(active_model: A)
1113 where
1114 E: EntityTrait,
1115 A: ActiveModelTrait<Entity = E>,
1116 {
1117 assert_eq!(
1118 E::find().build(DbBackend::Postgres).to_string(),
1119 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
1120 );
1121 assert_eq!(
1122 Update::one(active_model)
1123 .validate()
1124 .unwrap()
1125 .build(DbBackend::Postgres)
1126 .to_string(),
1127 r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
1128 );
1129 }
1130
1131 assert_it(hello_expanded::ActiveModel {
1132 id: ActiveValue::set(1),
1133 one: ActiveValue::set(1),
1134 two: ActiveValue::set(2),
1135 three: ActiveValue::set(3),
1136 });
1137 assert_it(hello_compact::ActiveModel {
1138 id: ActiveValue::set(1),
1139 one: ActiveValue::set(1),
1140 two: ActiveValue::set(2),
1141 three: ActiveValue::set(3),
1142 });
1143 }
1144}