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 {
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 fn eq<V>(&self, v: V) -> Expr
129 where
130 V: Into<Value>,
131 {
132 let v = v.into();
133 if v == v.as_null() {
134 Expr::col(self.as_column_ref()).is_null()
135 } else {
136 let expr = self.save_as(Expr::val(v));
137 Expr::col(self.as_column_ref()).eq(expr)
138 }
139 }
140
141 fn ne<V>(&self, v: V) -> Expr
161 where
162 V: Into<Value>,
163 {
164 let v = v.into();
165 if v == v.as_null() {
166 Expr::col(self.as_column_ref()).is_not_null()
167 } else {
168 let expr = self.save_as(Expr::val(v));
169 Expr::col(self.as_column_ref()).ne(expr)
170 }
171 }
172
173 bind_oper!(gt, GreaterThan);
174 bind_oper!(gte, GreaterThanOrEqual);
175 bind_oper!(lt, SmallerThan);
176 bind_oper!(lte, SmallerThanOrEqual);
177
178 fn between<V>(&self, a: V, b: V) -> Expr
190 where
191 V: Into<Value>,
192 {
193 Expr::col(self.as_column_ref()).between(a, b)
194 }
195
196 fn not_between<V>(&self, a: V, b: V) -> Expr
208 where
209 V: Into<Value>,
210 {
211 Expr::col(self.as_column_ref()).not_between(a, b)
212 }
213
214 fn like<T>(&self, s: T) -> Expr
226 where
227 T: IntoLikeExpr,
228 {
229 Expr::col(self.as_column_ref()).like(s)
230 }
231
232 fn not_like<T>(&self, s: T) -> Expr
244 where
245 T: IntoLikeExpr,
246 {
247 Expr::col(self.as_column_ref()).not_like(s)
248 }
249
250 fn ilike<T>(&self, s: T) -> Expr
263 where
264 T: IntoLikeExpr,
265 {
266 use sea_query::extension::postgres::PgExpr;
267
268 Expr::col(self.as_column_ref()).ilike(s)
269 }
270
271 fn not_ilike<T>(&self, s: T) -> Expr
284 where
285 T: IntoLikeExpr,
286 {
287 use sea_query::extension::postgres::PgExpr;
288
289 Expr::col(self.as_column_ref()).not_ilike(s)
290 }
291
292 fn starts_with<T>(&self, s: T) -> Expr
309 where
310 T: Into<String>,
311 {
312 let pattern = format!("{}%", s.into());
313 Expr::col(self.as_column_ref()).like(pattern)
314 }
315
316 fn ends_with<T>(&self, s: T) -> Expr
333 where
334 T: Into<String>,
335 {
336 let pattern = format!("%{}", s.into());
337 Expr::col(self.as_column_ref()).like(pattern)
338 }
339
340 fn contains<T>(&self, s: T) -> Expr
357 where
358 T: Into<String>,
359 {
360 let pattern = format!("%{}%", s.into());
361 Expr::col(self.as_column_ref()).like(pattern)
362 }
363
364 bind_func_no_params!(max);
365 bind_func_no_params!(min);
366 bind_func_no_params!(sum);
367 bind_func_no_params!(avg);
368 bind_func_no_params!(count);
369 bind_func_no_params!(is_null);
370 bind_func_no_params!(is_not_null);
371
372 fn if_null<V>(&self, v: V) -> Expr
374 where
375 V: Into<Value>,
376 {
377 Expr::col(self.as_column_ref()).if_null(v)
378 }
379
380 bind_vec_func!(is_in);
381 bind_vec_func!(is_not_in);
382
383 #[cfg(feature = "postgres-array")]
426 fn eq_any<V, I>(&self, v: I) -> Expr
427 where
428 V: Into<Value> + sea_query::postgres_array::NotU8,
429 I: IntoIterator<Item = V>,
430 {
431 use sea_query::extension::postgres::PgFunc;
432
433 let values: Vec<Value> = v.into_iter().map(|v| v.into()).collect();
434
435 if let Some(first) = values.first() {
436 Expr::col(self.as_column_ref()).eq(PgFunc::any(Value::Array(
437 first.array_type(),
438 Some(Box::new(values)),
439 )))
440 } else {
441 Expr::col(self.as_column_ref()).is_in(std::iter::empty::<V>())
442 }
443 }
444
445 #[cfg(feature = "postgres-array")]
465 fn ne_all<V, I>(&self, v: I) -> Expr
466 where
467 V: Into<Value> + sea_query::postgres_array::NotU8,
468 I: IntoIterator<Item = V>,
469 {
470 use sea_query::extension::postgres::PgFunc;
471
472 let values: Vec<Value> = v.into_iter().map(|v| v.into()).collect();
473
474 if let Some(first) = values.first() {
475 Expr::col(self.as_column_ref()).ne(PgFunc::all(Value::Array(
476 first.array_type(),
477 Some(Box::new(values)),
478 )))
479 } else {
480 Expr::col(self.as_column_ref()).is_not_in(std::iter::empty::<V>())
481 }
482 }
483
484 bind_subquery_func!(in_subquery);
485 bind_subquery_func!(not_in_subquery);
486
487 bind_array_oper!(array_contains, Contains);
488 bind_array_oper!(array_contained, Contained);
489 bind_array_oper!(array_overlap, Overlap);
490
491 fn into_expr(self) -> Expr {
493 self.into_simple_expr()
494 }
495
496 #[allow(clippy::match_single_binding)]
498 fn into_returning_expr(self, db_backend: DbBackend) -> Expr {
499 match db_backend {
500 _ => Expr::col(self),
501 }
502 }
503
504 fn select_as(&self, expr: Expr) -> Expr {
507 self.select_enum_as(expr)
508 }
509
510 fn select_enum_as(&self, expr: Expr) -> Expr {
512 cast_enum_as(expr, &self.def(), select_enum_as)
513 }
514
515 fn save_as(&self, val: Expr) -> Expr {
518 self.save_enum_as(val)
519 }
520
521 fn save_enum_as(&self, val: Expr) -> Expr {
523 cast_enum_as(val, &self.def(), save_enum_as)
524 }
525
526 #[cfg(feature = "with-json")]
528 fn json_key(&self) -> &'static str {
529 self.as_str()
530 }
531}
532
533pub trait ColumnTypeTrait {
535 fn def(self) -> ColumnDef;
537
538 fn get_enum_name(&self) -> Option<&DynIden>;
540}
541
542impl ColumnTypeTrait for ColumnType {
543 fn def(self) -> ColumnDef {
544 ColumnDef {
545 col_type: self,
546 null: false,
547 unique: false,
548 indexed: false,
549 default: None,
550 comment: None,
551 unique_key: None,
552 renamed_from: None,
553 extra: None,
554 seaography: Default::default(),
555 }
556 }
557
558 fn get_enum_name(&self) -> Option<&DynIden> {
559 enum_name(self)
560 }
561}
562
563impl ColumnTypeTrait for ColumnDef {
564 fn def(self) -> ColumnDef {
565 self
566 }
567
568 fn get_enum_name(&self) -> Option<&DynIden> {
569 enum_name(&self.col_type)
570 }
571}
572
573fn enum_name(col_type: &ColumnType) -> Option<&DynIden> {
574 match col_type {
575 ColumnType::Enum { name, .. } => Some(name),
576 ColumnType::Array(col_type) => enum_name(col_type),
577 _ => None,
578 }
579}
580
581struct Text;
582struct TextArray;
583
584impl Iden for Text {
585 fn quoted(&self) -> Cow<'static, str> {
586 Cow::Borrowed("text")
587 }
588
589 fn unquoted(&self) -> &str {
590 match self.quoted() {
591 Cow::Borrowed(s) => s,
592 _ => unreachable!(),
593 }
594 }
595}
596
597impl Iden for TextArray {
598 fn quoted(&self) -> Cow<'static, str> {
599 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
611pub(crate) fn select_enum_as(col: Expr, _: DynIden, col_type: &ColumnType) -> Expr {
612 let type_name = match col_type {
613 ColumnType::Array(_) => TextArray.into_iden(),
614 _ => Text.into_iden(),
615 };
616 col.as_enum(type_name)
617}
618
619pub(crate) fn save_enum_as(col: Expr, enum_name: DynIden, col_type: &ColumnType) -> Expr {
620 if matches!(col, Expr::Value(Value::Enum(_))) {
621 return col;
622 }
623 #[cfg(feature = "postgres-array")]
624 if matches!(
625 col,
626 Expr::Value(Value::Array(sea_query::ArrayType::Enum(_), _))
627 ) {
628 return col;
629 }
630
631 let type_name = match col_type {
632 ColumnType::Array(_) => format!("{enum_name}[]").into_iden(),
633 _ => enum_name,
634 };
635 col.as_enum(type_name)
636}
637
638pub(crate) fn cast_enum_as<F>(expr: Expr, col_def: &ColumnDef, f: F) -> Expr
639where
640 F: Fn(Expr, DynIden, &ColumnType) -> Expr,
641{
642 let col_type = col_def.get_column_type();
643
644 match col_type {
645 #[cfg(all(feature = "with-json", feature = "postgres-array"))]
646 ColumnType::Json | ColumnType::JsonBinary => {
647 use sea_query::ArrayType;
648 use serde_json::Value as Json;
649
650 match expr {
651 Expr::Value(Value::Array(ArrayType::Json, Some(json_vec))) => {
652 let json_vec: Vec<Json> = json_vec
654 .into_iter()
655 .filter_map(|val| match val {
656 Value::Json(Some(json)) => Some(*json),
657 _ => None,
658 })
659 .collect();
660 Expr::Value(Value::Json(Some(Box::new(json_vec.into()))))
661 }
662 Expr::Value(Value::Array(ArrayType::Json, None)) => Expr::Value(Value::Json(None)),
663 _ => expr,
664 }
665 }
666 _ => match col_type.get_enum_name() {
667 Some(enum_name) => f(expr, enum_name.clone(), col_type),
668 None => expr,
669 },
670 }
671}
672
673#[cfg(test)]
674mod tests {
675 use crate::{
676 ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait, tests_cfg::*,
677 };
678 use sea_query::Query;
679
680 #[test]
681 fn test_in_subquery_1() {
682 assert_eq!(
683 cake::Entity::find()
684 .filter(
685 Condition::any().add(
686 cake::Column::Id.in_subquery(
687 Query::select()
688 .expr(cake::Column::Id.max())
689 .from(cake::Entity)
690 .to_owned()
691 )
692 )
693 )
694 .build(DbBackend::MySql)
695 .to_string(),
696 [
697 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
698 "WHERE `cake`.`id` IN (SELECT MAX(`cake`.`id`) FROM `cake`)",
699 ]
700 .join(" ")
701 );
702 }
703
704 #[test]
705 fn test_in_subquery_2() {
706 assert_eq!(
707 cake::Entity::find()
708 .filter(
709 Condition::any().add(
710 cake::Column::Id.in_subquery(
711 Query::select()
712 .column(cake_filling::Column::CakeId)
713 .from(cake_filling::Entity)
714 .to_owned()
715 )
716 )
717 )
718 .build(DbBackend::MySql)
719 .to_string(),
720 [
721 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
722 "WHERE `cake`.`id` IN (SELECT `cake_id` FROM `cake_filling`)",
723 ]
724 .join(" ")
725 );
726 }
727
728 #[test]
729 #[cfg(feature = "macros")]
730 fn select_as_1() {
731 use crate::{ActiveModelTrait, ActiveValue, Update};
732
733 mod hello_expanded {
734 use crate as sea_orm;
735 use crate::entity::prelude::*;
736 use crate::sea_query::{Expr, ExprTrait};
737
738 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
739 pub struct Entity;
740
741 impl EntityName for Entity {
742 fn table_name(&self) -> &'static str {
743 "hello"
744 }
745 }
746
747 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
748 pub struct Model {
749 pub id: i32,
750 #[sea_orm(enum_name = "One1")]
751 pub one: i32,
752 pub two: i32,
753 #[sea_orm(enum_name = "Three3")]
754 pub three: i32,
755 }
756
757 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
758 pub enum Column {
759 Id,
760 One1,
761 Two,
762 Three3,
763 }
764
765 impl ColumnTrait for Column {
766 type EntityName = Entity;
767
768 fn def(&self) -> ColumnDef {
769 match self {
770 Column::Id => ColumnType::Integer.def(),
771 Column::One1 => ColumnType::Integer.def(),
772 Column::Two => ColumnType::Integer.def(),
773 Column::Three3 => ColumnType::Integer.def(),
774 }
775 }
776
777 fn select_as(&self, expr: Expr) -> Expr {
778 match self {
779 Self::Two => expr.cast_as("integer"),
780 _ => self.select_enum_as(expr),
781 }
782 }
783 }
784
785 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
786 pub enum PrimaryKey {
787 Id,
788 }
789
790 impl PrimaryKeyTrait for PrimaryKey {
791 type ValueType = i32;
792
793 fn auto_increment() -> bool {
794 true
795 }
796 }
797
798 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
799 pub enum Relation {}
800
801 impl ActiveModelBehavior for ActiveModel {}
802 }
803
804 #[allow(clippy::enum_variant_names)]
805 mod hello_compact {
806 use crate as sea_orm;
807 use crate::entity::prelude::*;
808
809 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
810 #[sea_orm(table_name = "hello")]
811 pub struct Model {
812 #[sea_orm(primary_key)]
813 pub id: i32,
814 #[sea_orm(enum_name = "One1")]
815 pub one: i32,
816 #[sea_orm(select_as = "integer")]
817 pub two: i32,
818 #[sea_orm(enum_name = "Three3")]
819 pub three: i32,
820 }
821
822 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
823 pub enum Relation {}
824
825 impl ActiveModelBehavior for ActiveModel {}
826 }
827
828 fn assert_it<E, A>(active_model: A)
829 where
830 E: EntityTrait,
831 A: ActiveModelTrait<Entity = E>,
832 {
833 assert_eq!(
834 E::find().build(DbBackend::Postgres).to_string(),
835 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
836 );
837 assert_eq!(
838 Update::one(active_model)
839 .validate()
840 .unwrap()
841 .build(DbBackend::Postgres)
842 .to_string(),
843 r#"UPDATE "hello" SET "one1" = 1, "two" = 2, "three3" = 3 WHERE "hello"."id" = 1"#,
844 );
845 }
846
847 assert_it(hello_expanded::ActiveModel {
848 id: ActiveValue::set(1),
849 one: ActiveValue::set(1),
850 two: ActiveValue::set(2),
851 three: ActiveValue::set(3),
852 });
853 assert_it(hello_compact::ActiveModel {
854 id: ActiveValue::set(1),
855 one: ActiveValue::set(1),
856 two: ActiveValue::set(2),
857 three: ActiveValue::set(3),
858 });
859 }
860
861 #[test]
862 #[cfg(feature = "macros")]
863 fn save_as_1() {
864 use crate::{ActiveModelTrait, ActiveValue, Update};
865
866 mod hello_expanded {
867 use crate as sea_orm;
868 use crate::entity::prelude::*;
869 use crate::sea_query::{Expr, ExprTrait};
870
871 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
872 pub struct Entity;
873
874 impl EntityName for Entity {
875 fn table_name(&self) -> &'static str {
876 "hello"
877 }
878 }
879
880 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
881 pub struct Model {
882 pub id: i32,
883 #[sea_orm(enum_name = "One1")]
884 pub one: i32,
885 pub two: i32,
886 #[sea_orm(enum_name = "Three3")]
887 pub three: i32,
888 }
889
890 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
891 pub enum Column {
892 Id,
893 One1,
894 Two,
895 Three3,
896 }
897
898 impl ColumnTrait for Column {
899 type EntityName = Entity;
900
901 fn def(&self) -> ColumnDef {
902 match self {
903 Column::Id => ColumnType::Integer.def(),
904 Column::One1 => ColumnType::Integer.def(),
905 Column::Two => ColumnType::Integer.def(),
906 Column::Three3 => ColumnType::Integer.def(),
907 }
908 }
909
910 fn save_as(&self, val: Expr) -> Expr {
911 match self {
912 Self::Two => val.cast_as("text"),
913 _ => self.save_enum_as(val),
914 }
915 }
916 }
917
918 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
919 pub enum PrimaryKey {
920 Id,
921 }
922
923 impl PrimaryKeyTrait for PrimaryKey {
924 type ValueType = i32;
925
926 fn auto_increment() -> bool {
927 true
928 }
929 }
930
931 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
932 pub enum Relation {}
933
934 impl ActiveModelBehavior for ActiveModel {}
935 }
936
937 #[allow(clippy::enum_variant_names)]
938 mod hello_compact {
939 use crate as sea_orm;
940 use crate::entity::prelude::*;
941
942 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
943 #[sea_orm(table_name = "hello")]
944 pub struct Model {
945 #[sea_orm(primary_key)]
946 pub id: i32,
947 #[sea_orm(enum_name = "One1")]
948 pub one: i32,
949 #[sea_orm(save_as = "text")]
950 pub two: i32,
951 #[sea_orm(enum_name = "Three3")]
952 pub three: i32,
953 }
954
955 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
956 pub enum Relation {}
957
958 impl ActiveModelBehavior for ActiveModel {}
959 }
960
961 fn assert_it<E, A>(active_model: A)
962 where
963 E: EntityTrait,
964 A: ActiveModelTrait<Entity = E>,
965 {
966 assert_eq!(
967 E::find().build(DbBackend::Postgres).to_string(),
968 r#"SELECT "hello"."id", "hello"."one1", "hello"."two", "hello"."three3" FROM "hello""#,
969 );
970 assert_eq!(
971 Update::one(active_model)
972 .validate()
973 .unwrap()
974 .build(DbBackend::Postgres)
975 .to_string(),
976 r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
977 );
978 }
979
980 assert_it(hello_expanded::ActiveModel {
981 id: ActiveValue::set(1),
982 one: ActiveValue::set(1),
983 two: ActiveValue::set(2),
984 three: ActiveValue::set(3),
985 });
986 assert_it(hello_compact::ActiveModel {
987 id: ActiveValue::set(1),
988 one: ActiveValue::set(1),
989 two: ActiveValue::set(2),
990 three: ActiveValue::set(3),
991 });
992 }
993
994 #[test]
995 #[cfg(feature = "macros")]
996 fn select_as_and_value_1() {
997 use crate::{ActiveModelTrait, ActiveValue, Update};
998
999 mod hello_expanded {
1000 use crate as sea_orm;
1001 use crate::entity::prelude::*;
1002 use crate::sea_query::{Expr, ExprTrait};
1003
1004 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
1005 pub struct Entity;
1006
1007 impl EntityName for Entity {
1008 fn table_name(&self) -> &'static str {
1009 "hello"
1010 }
1011 }
1012
1013 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
1014 pub struct Model {
1015 pub id: i32,
1016 #[sea_orm(enum_name = "One1")]
1017 pub one: i32,
1018 pub two: i32,
1019 #[sea_orm(enum_name = "Three3")]
1020 pub three: i32,
1021 }
1022
1023 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
1024 pub enum Column {
1025 Id,
1026 One1,
1027 Two,
1028 Three3,
1029 }
1030
1031 impl ColumnTrait for Column {
1032 type EntityName = Entity;
1033
1034 fn def(&self) -> ColumnDef {
1035 match self {
1036 Column::Id => ColumnType::Integer.def(),
1037 Column::One1 => ColumnType::Integer.def(),
1038 Column::Two => ColumnType::Integer.def(),
1039 Column::Three3 => ColumnType::Integer.def(),
1040 }
1041 }
1042
1043 fn select_as(&self, expr: Expr) -> Expr {
1044 match self {
1045 Self::Two => expr.cast_as("integer"),
1046 _ => self.select_enum_as(expr),
1047 }
1048 }
1049
1050 fn save_as(&self, val: Expr) -> Expr {
1051 match self {
1052 Self::Two => val.cast_as("text"),
1053 _ => self.save_enum_as(val),
1054 }
1055 }
1056 }
1057
1058 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
1059 pub enum PrimaryKey {
1060 Id,
1061 }
1062
1063 impl PrimaryKeyTrait for PrimaryKey {
1064 type ValueType = i32;
1065
1066 fn auto_increment() -> bool {
1067 true
1068 }
1069 }
1070
1071 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1072 pub enum Relation {}
1073
1074 impl ActiveModelBehavior for ActiveModel {}
1075 }
1076
1077 #[allow(clippy::enum_variant_names)]
1078 mod hello_compact {
1079 use crate as sea_orm;
1080 use crate::entity::prelude::*;
1081
1082 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1083 #[sea_orm(table_name = "hello")]
1084 pub struct Model {
1085 #[sea_orm(primary_key)]
1086 pub id: i32,
1087 #[sea_orm(enum_name = "One1")]
1088 pub one: i32,
1089 #[sea_orm(select_as = "integer", save_as = "text")]
1090 pub two: i32,
1091 #[sea_orm(enum_name = "Three3")]
1092 pub three: i32,
1093 }
1094
1095 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1096 pub enum Relation {}
1097
1098 impl ActiveModelBehavior for ActiveModel {}
1099 }
1100
1101 fn assert_it<E, A>(active_model: A)
1102 where
1103 E: EntityTrait,
1104 A: ActiveModelTrait<Entity = E>,
1105 {
1106 assert_eq!(
1107 E::find().build(DbBackend::Postgres).to_string(),
1108 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
1109 );
1110 assert_eq!(
1111 Update::one(active_model)
1112 .validate()
1113 .unwrap()
1114 .build(DbBackend::Postgres)
1115 .to_string(),
1116 r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
1117 );
1118 }
1119
1120 assert_it(hello_expanded::ActiveModel {
1121 id: ActiveValue::set(1),
1122 one: ActiveValue::set(1),
1123 two: ActiveValue::set(2),
1124 three: ActiveValue::set(3),
1125 });
1126 assert_it(hello_compact::ActiveModel {
1127 id: ActiveValue::set(1),
1128 one: ActiveValue::set(1),
1129 two: ActiveValue::set(2),
1130 three: ActiveValue::set(3),
1131 });
1132 }
1133}