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 #[cfg(feature = "macros")]
740 mod select_as {
741 use super::*;
742
743 mod hello_expanded {
744 use crate as sea_orm;
745 use crate::entity::prelude::*;
746 use crate::sea_query::{Expr, ExprTrait};
747
748 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
749 pub struct Entity;
750
751 impl EntityName for Entity {
752 fn table_name(&self) -> &'static str {
753 "hello"
754 }
755 }
756
757 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
758 pub struct Model {
759 pub id: i32,
760 #[sea_orm(enum_name = "One1")]
761 pub one: i32,
762 pub two: i32,
763 #[sea_orm(enum_name = "Three3")]
764 pub three: i32,
765 }
766
767 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
768 pub enum Column {
769 Id,
770 One1,
771 Two,
772 Three3,
773 }
774
775 impl ColumnTrait for Column {
776 type EntityName = Entity;
777
778 fn def(&self) -> ColumnDef {
779 match self {
780 Column::Id => ColumnType::Integer.def(),
781 Column::One1 => ColumnType::Integer.def(),
782 Column::Two => ColumnType::Integer.def(),
783 Column::Three3 => ColumnType::Integer.def(),
784 }
785 }
786
787 fn select_as(&self, expr: Expr) -> Expr {
788 match self {
789 Self::Two => expr.cast_as("integer"),
790 _ => self.select_enum_as(expr),
791 }
792 }
793 }
794
795 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
796 pub enum PrimaryKey {
797 Id,
798 }
799
800 impl PrimaryKeyTrait for PrimaryKey {
801 type ValueType = i32;
802
803 fn auto_increment() -> bool {
804 true
805 }
806 }
807
808 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
809 pub enum Relation {}
810
811 impl ActiveModelBehavior for ActiveModel {}
812 }
813
814 #[allow(clippy::enum_variant_names)]
815 mod hello_compact {
816 use crate as sea_orm;
817 use crate::entity::prelude::*;
818
819 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
820 #[sea_orm(table_name = "hello")]
821 pub struct Model {
822 #[sea_orm(primary_key)]
823 pub id: i32,
824 #[sea_orm(enum_name = "One1")]
825 pub one: i32,
826 #[sea_orm(select_as = "integer")]
827 pub two: i32,
828 #[sea_orm(enum_name = "Three3")]
829 pub three: i32,
830 }
831
832 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
833 pub enum Relation {}
834
835 impl ActiveModelBehavior for ActiveModel {}
836 }
837
838 #[test]
839 fn select_as_1() {
840 use crate::{ActiveModelTrait, ActiveValue, Update};
841
842 fn assert_it<E, A>(active_model: A)
843 where
844 E: EntityTrait,
845 A: ActiveModelTrait<Entity = E>,
846 {
847 assert_eq!(
848 E::find().build(DbBackend::Postgres).to_string(),
849 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer) AS "two", "hello"."three3" FROM "hello""#,
850 );
851 assert_eq!(
852 Update::one(active_model)
853 .validate()
854 .unwrap()
855 .build(DbBackend::Postgres)
856 .to_string(),
857 r#"UPDATE "hello" SET "one1" = 1, "two" = 2, "three3" = 3 WHERE "hello"."id" = 1"#,
858 );
859 }
860
861 assert_it(hello_expanded::ActiveModel {
862 id: ActiveValue::set(1),
863 one: ActiveValue::set(1),
864 two: ActiveValue::set(2),
865 three: ActiveValue::set(3),
866 });
867 assert_it(hello_compact::ActiveModel {
868 id: ActiveValue::set(1),
869 one: ActiveValue::set(1),
870 two: ActiveValue::set(2),
871 three: ActiveValue::set(3),
872 });
873 }
874
875 #[test]
876 fn select_as_columns_keep_aliases_in_multi_selects() {
877 use crate::{Iterable, QuerySelect};
878
879 fn assert_it<E: EntityTrait>() {
880 for select in [
881 E::find(),
882 E::find().select_only().columns(E::Column::iter()),
883 ] {
884 assert_eq!(
885 select
886 .select_also(E::default())
887 .build(DbBackend::Postgres)
888 .to_string(),
889 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""#,
890 );
891 }
892 }
893
894 assert_it::<hello_expanded::Entity>();
895 assert_it::<hello_compact::Entity>();
896 }
897 }
898
899 #[test]
900 #[cfg(feature = "macros")]
901 fn save_as_1() {
902 use crate::{ActiveModelTrait, ActiveValue, Update};
903
904 mod hello_expanded {
905 use crate as sea_orm;
906 use crate::entity::prelude::*;
907 use crate::sea_query::{Expr, ExprTrait};
908
909 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
910 pub struct Entity;
911
912 impl EntityName for Entity {
913 fn table_name(&self) -> &'static str {
914 "hello"
915 }
916 }
917
918 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
919 pub struct Model {
920 pub id: i32,
921 #[sea_orm(enum_name = "One1")]
922 pub one: i32,
923 pub two: i32,
924 #[sea_orm(enum_name = "Three3")]
925 pub three: i32,
926 }
927
928 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
929 pub enum Column {
930 Id,
931 One1,
932 Two,
933 Three3,
934 }
935
936 impl ColumnTrait for Column {
937 type EntityName = Entity;
938
939 fn def(&self) -> ColumnDef {
940 match self {
941 Column::Id => ColumnType::Integer.def(),
942 Column::One1 => ColumnType::Integer.def(),
943 Column::Two => ColumnType::Integer.def(),
944 Column::Three3 => ColumnType::Integer.def(),
945 }
946 }
947
948 fn save_as(&self, val: Expr) -> Expr {
949 match self {
950 Self::Two => val.cast_as("text"),
951 _ => self.save_enum_as(val),
952 }
953 }
954 }
955
956 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
957 pub enum PrimaryKey {
958 Id,
959 }
960
961 impl PrimaryKeyTrait for PrimaryKey {
962 type ValueType = i32;
963
964 fn auto_increment() -> bool {
965 true
966 }
967 }
968
969 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
970 pub enum Relation {}
971
972 impl ActiveModelBehavior for ActiveModel {}
973 }
974
975 #[allow(clippy::enum_variant_names)]
976 mod hello_compact {
977 use crate as sea_orm;
978 use crate::entity::prelude::*;
979
980 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
981 #[sea_orm(table_name = "hello")]
982 pub struct Model {
983 #[sea_orm(primary_key)]
984 pub id: i32,
985 #[sea_orm(enum_name = "One1")]
986 pub one: i32,
987 #[sea_orm(save_as = "text")]
988 pub two: i32,
989 #[sea_orm(enum_name = "Three3")]
990 pub three: i32,
991 }
992
993 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
994 pub enum Relation {}
995
996 impl ActiveModelBehavior for ActiveModel {}
997 }
998
999 fn assert_it<E, A>(active_model: A)
1000 where
1001 E: EntityTrait,
1002 A: ActiveModelTrait<Entity = E>,
1003 {
1004 assert_eq!(
1005 E::find().build(DbBackend::Postgres).to_string(),
1006 r#"SELECT "hello"."id", "hello"."one1", "hello"."two", "hello"."three3" FROM "hello""#,
1007 );
1008 assert_eq!(
1009 Update::one(active_model)
1010 .validate()
1011 .unwrap()
1012 .build(DbBackend::Postgres)
1013 .to_string(),
1014 r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
1015 );
1016 }
1017
1018 assert_it(hello_expanded::ActiveModel {
1019 id: ActiveValue::set(1),
1020 one: ActiveValue::set(1),
1021 two: ActiveValue::set(2),
1022 three: ActiveValue::set(3),
1023 });
1024 assert_it(hello_compact::ActiveModel {
1025 id: ActiveValue::set(1),
1026 one: ActiveValue::set(1),
1027 two: ActiveValue::set(2),
1028 three: ActiveValue::set(3),
1029 });
1030 }
1031
1032 #[test]
1033 #[cfg(feature = "macros")]
1034 fn select_as_and_value_1() {
1035 use crate::{ActiveModelTrait, ActiveValue, Update};
1036
1037 mod hello_expanded {
1038 use crate as sea_orm;
1039 use crate::entity::prelude::*;
1040 use crate::sea_query::{Expr, ExprTrait};
1041
1042 #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
1043 pub struct Entity;
1044
1045 impl EntityName for Entity {
1046 fn table_name(&self) -> &'static str {
1047 "hello"
1048 }
1049 }
1050
1051 #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
1052 pub struct Model {
1053 pub id: i32,
1054 #[sea_orm(enum_name = "One1")]
1055 pub one: i32,
1056 pub two: i32,
1057 #[sea_orm(enum_name = "Three3")]
1058 pub three: i32,
1059 }
1060
1061 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
1062 pub enum Column {
1063 Id,
1064 One1,
1065 Two,
1066 Three3,
1067 }
1068
1069 impl ColumnTrait for Column {
1070 type EntityName = Entity;
1071
1072 fn def(&self) -> ColumnDef {
1073 match self {
1074 Column::Id => ColumnType::Integer.def(),
1075 Column::One1 => ColumnType::Integer.def(),
1076 Column::Two => ColumnType::Integer.def(),
1077 Column::Three3 => ColumnType::Integer.def(),
1078 }
1079 }
1080
1081 fn select_as(&self, expr: Expr) -> Expr {
1082 match self {
1083 Self::Two => expr.cast_as("integer"),
1084 _ => self.select_enum_as(expr),
1085 }
1086 }
1087
1088 fn save_as(&self, val: Expr) -> Expr {
1089 match self {
1090 Self::Two => val.cast_as("text"),
1091 _ => self.save_enum_as(val),
1092 }
1093 }
1094 }
1095
1096 #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
1097 pub enum PrimaryKey {
1098 Id,
1099 }
1100
1101 impl PrimaryKeyTrait for PrimaryKey {
1102 type ValueType = i32;
1103
1104 fn auto_increment() -> bool {
1105 true
1106 }
1107 }
1108
1109 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1110 pub enum Relation {}
1111
1112 impl ActiveModelBehavior for ActiveModel {}
1113 }
1114
1115 #[allow(clippy::enum_variant_names)]
1116 mod hello_compact {
1117 use crate as sea_orm;
1118 use crate::entity::prelude::*;
1119
1120 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1121 #[sea_orm(table_name = "hello")]
1122 pub struct Model {
1123 #[sea_orm(primary_key)]
1124 pub id: i32,
1125 #[sea_orm(enum_name = "One1")]
1126 pub one: i32,
1127 #[sea_orm(select_as = "integer", save_as = "text")]
1128 pub two: i32,
1129 #[sea_orm(enum_name = "Three3")]
1130 pub three: i32,
1131 }
1132
1133 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1134 pub enum Relation {}
1135
1136 impl ActiveModelBehavior for ActiveModel {}
1137 }
1138
1139 fn assert_it<E, A>(active_model: A)
1140 where
1141 E: EntityTrait,
1142 A: ActiveModelTrait<Entity = E>,
1143 {
1144 assert_eq!(
1145 E::find().build(DbBackend::Postgres).to_string(),
1146 r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer) AS "two", "hello"."three3" FROM "hello""#,
1147 );
1148 assert_eq!(
1149 Update::one(active_model)
1150 .validate()
1151 .unwrap()
1152 .build(DbBackend::Postgres)
1153 .to_string(),
1154 r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
1155 );
1156 }
1157
1158 assert_it(hello_expanded::ActiveModel {
1159 id: ActiveValue::set(1),
1160 one: ActiveValue::set(1),
1161 two: ActiveValue::set(2),
1162 three: ActiveValue::set(3),
1163 });
1164 assert_it(hello_compact::ActiveModel {
1165 id: ActiveValue::set(1),
1166 one: ActiveValue::set(1),
1167 two: ActiveValue::set(2),
1168 three: ActiveValue::set(3),
1169 });
1170 }
1171}