diff --git a/sea-orm-macros/src/derives/entity_model.rs b/sea-orm-macros/src/derives/entity_model.rs index bf42699d13..c744ccd184 100644 --- a/sea-orm-macros/src/derives/entity_model.rs +++ b/sea-orm-macros/src/derives/entity_model.rs @@ -63,6 +63,8 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res // generate Column enum and it's ColumnTrait impl let mut columns_enum: Punctuated<_, Comma> = Punctuated::new(); let mut columns_trait: Punctuated<_, Comma> = Punctuated::new(); + let mut columns_select_as: Punctuated<_, Comma> = Punctuated::new(); + let mut columns_save_as: Punctuated<_, Comma> = Punctuated::new(); let mut primary_keys: Punctuated<_, Comma> = Punctuated::new(); let mut primary_key_types: Punctuated<_, Comma> = Punctuated::new(); let mut auto_increment = true; @@ -90,6 +92,8 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res let mut nullable = false; let mut default_value = None; let mut default_expr = None; + let mut select_as = None; + let mut save_as = None; let mut indexed = false; let mut ignore = false; let mut unique = false; @@ -169,6 +173,24 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res format!("Invalid enum_name {:?}", nv.lit), )); } + } else if name == "select_as" { + if let Lit::Str(litstr) = &nv.lit { + select_as = Some(litstr.value()); + } else { + return Err(Error::new( + field.span(), + format!("Invalid select_as {:?}", nv.lit), + )); + } + } else if name == "save_as" { + if let Lit::Str(litstr) = &nv.lit { + save_as = Some(litstr.value()); + } else { + return Err(Error::new( + field.span(), + format!("Invalid save_as {:?}", nv.lit), + )); + } } } } @@ -224,6 +246,23 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res }); } + if let Some(select_as) = select_as { + columns_select_as.push(quote! { + Self::#field_name => sea_orm::sea_query::SimpleExpr::cast_as( + Into::::into(expr), + sea_orm::sea_query::Alias::new(&#select_as), + ), + }); + } + if let Some(save_as) = save_as { + columns_save_as.push(quote! { + Self::#field_name => sea_orm::sea_query::SimpleExpr::cast_as( + Into::::into(val), + sea_orm::sea_query::Alias::new(&#save_as), + ), + }); + } + let field_type = &field.ty; let field_type = quote! { #field_type } .to_string() //E.g.: "Option < String >" @@ -347,6 +386,20 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res #columns_trait } } + + fn select_as(&self, expr: sea_orm::sea_query::Expr) -> sea_orm::sea_query::SimpleExpr { + match self { + #columns_select_as + _ => sea_orm::prelude::ColumnTrait::select_enum_as(self, expr), + } + } + + fn save_as(&self, val: sea_orm::sea_query::Expr) -> sea_orm::sea_query::SimpleExpr { + match self { + #columns_save_as + _ => sea_orm::prelude::ColumnTrait::save_enum_as(self, val), + } + } } #entity_def diff --git a/src/entity/column.rs b/src/entity/column.rs index 7421488acf..f014dda359 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -1,5 +1,7 @@ -use crate::{cast_text_as_enum, EntityName, IdenStatic, IntoSimpleExpr, Iterable}; -use sea_query::{BinOper, DynIden, Expr, SeaRc, SelectStatement, SimpleExpr, Value}; +use crate::{EntityName, IdenStatic, IntoSimpleExpr, Iterable}; +use sea_query::{ + Alias, BinOper, DynIden, Expr, Iden, IntoIden, SeaRc, SelectStatement, SimpleExpr, Value, +}; use std::str::FromStr; /// Defines a Column for an Entity @@ -134,7 +136,7 @@ macro_rules! bind_oper_with_enum_casting { where V: Into, { - let expr = cast_text_as_enum(Expr::val(v), self); + let expr = self.save_as(Expr::val(v)); Expr::col((self.entity_name(), *self)).binary(BinOper::$bin_op, expr) } }; @@ -338,6 +340,42 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr { fn into_expr(self) -> Expr { Expr::expr(self.into_simple_expr()) } + + /// Cast column expression used in select statement. + /// By default it only cast database enum as text. + fn select_as(&self, expr: Expr) -> SimpleExpr { + self.select_enum_as(expr) + } + + /// Cast enum column as text + fn select_enum_as(&self, expr: Expr) -> SimpleExpr { + cast_enum_as(expr, self, |col, _, col_type| { + let type_name = match col_type { + ColumnType::Array(_) => TextArray.into_iden(), + _ => Text.into_iden(), + }; + col.as_enum(type_name) + }) + } + + /// Cast value of a column into the correct type for database storage. + /// By default it only cast text as enum type if it's an enum column. + fn save_as(&self, val: Expr) -> SimpleExpr { + self.save_enum_as(val) + } + + /// Cast value of a enum column as enum type + fn save_enum_as(&self, val: Expr) -> SimpleExpr { + cast_enum_as(val, self, |col, enum_name, col_type| { + let type_name = match col_type { + ColumnType::Array(_) => { + Alias::new(&format!("{}[]", enum_name.to_string())).into_iden() + } + _ => enum_name, + }; + col.as_enum(type_name) + }) + } } impl ColumnType { @@ -513,6 +551,26 @@ impl From for ColumnType { } } +#[derive(Iden)] +struct Text; + +#[derive(Iden)] +#[iden = "text[]"] +struct TextArray; + +fn cast_enum_as(expr: Expr, col: &C, f: F) -> SimpleExpr +where + C: ColumnTrait, + F: Fn(Expr, DynIden, &ColumnType) -> SimpleExpr, +{ + let col_def = col.def(); + let col_type = col_def.get_column_type(); + match col_type.get_enum_name() { + Some(enum_name) => f(expr, SeaRc::clone(enum_name), col_type), + None => expr.into(), + } +} + #[cfg(test)] mod tests { use crate::{ @@ -1017,4 +1075,414 @@ mod tests { assert_eq!(my_entity::Column::IdentityColumn.to_string().as_str(), "id"); assert_eq!(my_entity::Column::Type.to_string().as_str(), "type"); } + + #[test] + #[cfg(feature = "macros")] + fn select_as_1() { + use crate::{ActiveModelTrait, ActiveValue, Update}; + + mod hello_expanded { + use crate as sea_orm; + use crate::entity::prelude::*; + use crate::sea_query::{Alias, Expr, SimpleExpr}; + + #[derive(Copy, Clone, Default, Debug, DeriveEntity)] + pub struct Entity; + + impl EntityName for Entity { + fn table_name(&self) -> &str { + "hello" + } + } + + #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)] + pub struct Model { + pub id: i32, + #[sea_orm(enum_name = "One1")] + pub one: i32, + pub two: i32, + #[sea_orm(enum_name = "Three3")] + pub three: i32, + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] + pub enum Column { + Id, + One1, + Two, + Three3, + } + + impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Column::Id => ColumnType::Integer.def(), + Column::One1 => ColumnType::Integer.def(), + Column::Two => ColumnType::Integer.def(), + Column::Three3 => ColumnType::Integer.def(), + } + } + + fn select_as(&self, expr: Expr) -> SimpleExpr { + match self { + Self::Two => SimpleExpr::cast_as( + Into::::into(expr), + Alias::new("integer"), + ), + _ => self.select_enum_as(expr), + } + } + } + + #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] + pub enum PrimaryKey { + Id, + } + + impl PrimaryKeyTrait for PrimaryKey { + type ValueType = i32; + + fn auto_increment() -> bool { + true + } + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation {} + + impl ActiveModelBehavior for ActiveModel {} + } + + #[allow(clippy::enum_variant_names)] + mod hello_compact { + use crate as sea_orm; + use crate::entity::prelude::*; + + #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] + #[sea_orm(table_name = "hello")] + pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(enum_name = "One1")] + pub one: i32, + #[sea_orm(select_as = "integer")] + pub two: i32, + #[sea_orm(enum_name = "Three3")] + pub three: i32, + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation {} + + impl ActiveModelBehavior for ActiveModel {} + } + + fn assert_it(active_model: A) + where + E: EntityTrait, + A: ActiveModelTrait, + { + assert_eq!( + E::find().build(DbBackend::Postgres).to_string(), + r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#, + ); + assert_eq!( + Update::one(active_model) + .build(DbBackend::Postgres) + .to_string(), + r#"UPDATE "hello" SET "one1" = 1, "two" = 2, "three3" = 3 WHERE "hello"."id" = 1"#, + ); + } + + assert_it(hello_expanded::ActiveModel { + id: ActiveValue::set(1), + one: ActiveValue::set(1), + two: ActiveValue::set(2), + three: ActiveValue::set(3), + }); + assert_it(hello_compact::ActiveModel { + id: ActiveValue::set(1), + one: ActiveValue::set(1), + two: ActiveValue::set(2), + three: ActiveValue::set(3), + }); + } + + #[test] + #[cfg(feature = "macros")] + fn save_as_1() { + use crate::{ActiveModelTrait, ActiveValue, Update}; + + mod hello_expanded { + use crate as sea_orm; + use crate::entity::prelude::*; + use crate::sea_query::{Alias, Expr, SimpleExpr}; + + #[derive(Copy, Clone, Default, Debug, DeriveEntity)] + pub struct Entity; + + impl EntityName for Entity { + fn table_name(&self) -> &str { + "hello" + } + } + + #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)] + pub struct Model { + pub id: i32, + #[sea_orm(enum_name = "One1")] + pub one: i32, + pub two: i32, + #[sea_orm(enum_name = "Three3")] + pub three: i32, + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] + pub enum Column { + Id, + One1, + Two, + Three3, + } + + impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Column::Id => ColumnType::Integer.def(), + Column::One1 => ColumnType::Integer.def(), + Column::Two => ColumnType::Integer.def(), + Column::Three3 => ColumnType::Integer.def(), + } + } + + fn save_as(&self, expr: Expr) -> SimpleExpr { + match self { + Self::Two => { + SimpleExpr::cast_as(Into::::into(expr), Alias::new("text")) + } + _ => self.save_enum_as(expr), + } + } + } + + #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] + pub enum PrimaryKey { + Id, + } + + impl PrimaryKeyTrait for PrimaryKey { + type ValueType = i32; + + fn auto_increment() -> bool { + true + } + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation {} + + impl ActiveModelBehavior for ActiveModel {} + } + + #[allow(clippy::enum_variant_names)] + mod hello_compact { + use crate as sea_orm; + use crate::entity::prelude::*; + + #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] + #[sea_orm(table_name = "hello")] + pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(enum_name = "One1")] + pub one: i32, + #[sea_orm(save_as = "text")] + pub two: i32, + #[sea_orm(enum_name = "Three3")] + pub three: i32, + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation {} + + impl ActiveModelBehavior for ActiveModel {} + } + + fn assert_it(active_model: A) + where + E: EntityTrait, + A: ActiveModelTrait, + { + assert_eq!( + E::find().build(DbBackend::Postgres).to_string(), + r#"SELECT "hello"."id", "hello"."one1", "hello"."two", "hello"."three3" FROM "hello""#, + ); + assert_eq!( + Update::one(active_model) + .build(DbBackend::Postgres) + .to_string(), + r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#, + ); + } + + assert_it(hello_expanded::ActiveModel { + id: ActiveValue::set(1), + one: ActiveValue::set(1), + two: ActiveValue::set(2), + three: ActiveValue::set(3), + }); + assert_it(hello_compact::ActiveModel { + id: ActiveValue::set(1), + one: ActiveValue::set(1), + two: ActiveValue::set(2), + three: ActiveValue::set(3), + }); + } + + #[test] + #[cfg(feature = "macros")] + fn select_as_and_value_1() { + use crate::{ActiveModelTrait, ActiveValue, Update}; + + mod hello_expanded { + use crate as sea_orm; + use crate::entity::prelude::*; + use crate::sea_query::{Alias, Expr, SimpleExpr}; + + #[derive(Copy, Clone, Default, Debug, DeriveEntity)] + pub struct Entity; + + impl EntityName for Entity { + fn table_name(&self) -> &str { + "hello" + } + } + + #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)] + pub struct Model { + pub id: i32, + #[sea_orm(enum_name = "One1")] + pub one: i32, + pub two: i32, + #[sea_orm(enum_name = "Three3")] + pub three: i32, + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] + pub enum Column { + Id, + One1, + Two, + Three3, + } + + impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Column::Id => ColumnType::Integer.def(), + Column::One1 => ColumnType::Integer.def(), + Column::Two => ColumnType::Integer.def(), + Column::Three3 => ColumnType::Integer.def(), + } + } + + fn select_as(&self, expr: Expr) -> SimpleExpr { + match self { + Self::Two => SimpleExpr::cast_as( + Into::::into(expr), + Alias::new("integer"), + ), + _ => self.select_enum_as(expr), + } + } + + fn save_as(&self, expr: Expr) -> SimpleExpr { + match self { + Self::Two => { + SimpleExpr::cast_as(Into::::into(expr), Alias::new("text")) + } + _ => self.save_enum_as(expr), + } + } + } + + #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] + pub enum PrimaryKey { + Id, + } + + impl PrimaryKeyTrait for PrimaryKey { + type ValueType = i32; + + fn auto_increment() -> bool { + true + } + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation {} + + impl ActiveModelBehavior for ActiveModel {} + } + + #[allow(clippy::enum_variant_names)] + mod hello_compact { + use crate as sea_orm; + use crate::entity::prelude::*; + + #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] + #[sea_orm(table_name = "hello")] + pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(enum_name = "One1")] + pub one: i32, + #[sea_orm(select_as = "integer", save_as = "text")] + pub two: i32, + #[sea_orm(enum_name = "Three3")] + pub three: i32, + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation {} + + impl ActiveModelBehavior for ActiveModel {} + } + + fn assert_it(active_model: A) + where + E: EntityTrait, + A: ActiveModelTrait, + { + assert_eq!( + E::find().build(DbBackend::Postgres).to_string(), + r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#, + ); + assert_eq!( + Update::one(active_model) + .build(DbBackend::Postgres) + .to_string(), + r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#, + ); + } + + assert_it(hello_expanded::ActiveModel { + id: ActiveValue::set(1), + one: ActiveValue::set(1), + two: ActiveValue::set(2), + three: ActiveValue::set(3), + }); + assert_it(hello_compact::ActiveModel { + id: ActiveValue::set(1), + one: ActiveValue::set(1), + two: ActiveValue::set(2), + three: ActiveValue::set(3), + }); + } } diff --git a/src/executor/insert.rs b/src/executor/insert.rs index b990bf5ea7..796cd36290 100644 --- a/src/executor/insert.rs +++ b/src/executor/insert.rs @@ -1,6 +1,6 @@ use crate::{ - cast_enum_as_text, error::*, ActiveModelTrait, ConnectionTrait, EntityTrait, Insert, - IntoActiveModel, Iterable, PrimaryKeyTrait, SelectModel, SelectorRaw, Statement, TryFromU64, + error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, Insert, IntoActiveModel, + Iterable, PrimaryKeyTrait, SelectModel, SelectorRaw, Statement, TryFromU64, }; use sea_query::{Expr, FromValueTuple, Iden, InsertStatement, IntoColumnRef, Query, ValueTuple}; use std::{future::Future, marker::PhantomData}; @@ -189,8 +189,7 @@ where let found = match db.support_returning() { true => { let returning = Query::returning().exprs( - ::Column::iter() - .map(|c| cast_enum_as_text(Expr::col(c), &c)), + ::Column::iter().map(|c| c.select_as(Expr::col(c))), ); insert_statement.returning(returning); SelectorRaw::::Model>>::from_statement( diff --git a/src/executor/update.rs b/src/executor/update.rs index f503fe554c..9e37cf4d2c 100644 --- a/src/executor/update.rs +++ b/src/executor/update.rs @@ -1,5 +1,5 @@ use crate::{ - cast_enum_as_text, error::*, ActiveModelTrait, ConnectionTrait, EntityTrait, IntoActiveModel, + error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, IntoActiveModel, Iterable, PrimaryKeyTrait, SelectModel, SelectorRaw, Statement, UpdateMany, UpdateOne, }; use sea_query::{Expr, FromValueTuple, Query, UpdateStatement}; @@ -95,8 +95,8 @@ where type ValueType = < as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType; match db.support_returning() { true => { - let returning = Query::returning() - .exprs(Column::::iter().map(|c| cast_enum_as_text(Expr::col(c), &c))); + let returning = + Query::returning().exprs(Column::::iter().map(|c| c.select_as(Expr::col(c)))); query.returning(returning); let db_backend = db.get_database_backend(); let found: Option> = diff --git a/src/query/combine.rs b/src/query/combine.rs index 677d7aa0ad..99f2d80217 100644 --- a/src/query/combine.rs +++ b/src/query/combine.rs @@ -1,6 +1,5 @@ use crate::{ - cast_enum_as_text, ColumnTrait, EntityTrait, IdenStatic, Iterable, QueryTrait, Select, - SelectTwo, SelectTwoMany, + ColumnTrait, EntityTrait, IdenStatic, Iterable, QueryTrait, Select, SelectTwo, SelectTwoMany, }; use core::marker::PhantomData; pub use sea_query::JoinType; @@ -149,7 +148,7 @@ where for col in ::iter() { let alias = format!("{}{}", SelectB.as_str(), col.as_str()); selector.query().expr(SelectExpr { - expr: cast_enum_as_text(col.into_expr(), &col), + expr: col.select_as(col.into_expr()), alias: Some(SeaRc::new(Alias::new(&alias))), window: None, }); diff --git a/src/query/helper.rs b/src/query/helper.rs index cea4a66704..29f374927c 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -1,6 +1,6 @@ use crate::{ - ColumnTrait, ColumnType, EntityTrait, Identity, IntoIdentity, IntoSimpleExpr, Iterable, - ModelTrait, PrimaryKeyToColumn, RelationDef, + ColumnTrait, EntityTrait, Identity, IntoIdentity, IntoSimpleExpr, Iterable, ModelTrait, + PrimaryKeyToColumn, RelationDef, }; use sea_query::{ Alias, Expr, Iden, IntoCondition, IntoIden, LockType, SeaRc, SelectExpr, SelectStatement, @@ -67,7 +67,7 @@ pub trait QuerySelect: Sized { where C: ColumnTrait, { - self.query().expr(cast_enum_as_text(col.into_expr(), &col)); + self.query().expr(col.select_as(col.into_expr())); self } @@ -680,49 +680,3 @@ pub(crate) fn unpack_table_alias(table_ref: &TableRef) -> Option { | TableRef::FunctionCall(_, alias) => Some(SeaRc::clone(alias)), } } - -#[derive(Iden)] -struct Text; - -#[derive(Iden)] -#[iden = "text[]"] -struct TextArray; - -pub(crate) fn cast_enum_as_text(expr: Expr, col: &C) -> SimpleExpr -where - C: ColumnTrait, -{ - cast_enum_text_inner(expr, col, |col, _, col_type| { - let type_name = match col_type { - ColumnType::Array(_) => TextArray.into_iden(), - _ => Text.into_iden(), - }; - col.as_enum(type_name) - }) -} - -pub(crate) fn cast_text_as_enum(expr: Expr, col: &C) -> SimpleExpr -where - C: ColumnTrait, -{ - cast_enum_text_inner(expr, col, |col, enum_name, col_type| { - let type_name = match col_type { - ColumnType::Array(_) => Alias::new(&format!("{}[]", enum_name.to_string())).into_iden(), - _ => enum_name, - }; - col.as_enum(type_name) - }) -} - -fn cast_enum_text_inner(expr: Expr, col: &C, f: F) -> SimpleExpr -where - C: ColumnTrait, - F: Fn(Expr, DynIden, &ColumnType) -> SimpleExpr, -{ - let col_def = col.def(); - let col_type = col_def.get_column_type(); - match col_type.get_enum_name() { - Some(enum_name) => f(expr, SeaRc::clone(enum_name), col_type), - None => expr.into(), - } -} diff --git a/src/query/insert.rs b/src/query/insert.rs index 75bfe99dd4..76262c070c 100644 --- a/src/query/insert.rs +++ b/src/query/insert.rs @@ -1,5 +1,5 @@ use crate::{ - cast_text_as_enum, ActiveModelTrait, EntityName, EntityTrait, IntoActiveModel, Iterable, + ActiveModelTrait, ColumnTrait, EntityName, EntityTrait, IntoActiveModel, Iterable, PrimaryKeyTrait, QueryTrait, }; use core::marker::PhantomData; @@ -134,7 +134,7 @@ where } if av_has_val { columns.push(col); - values.push(cast_text_as_enum(Expr::val(av.into_value().unwrap()), &col)); + values.push(col.save_as(Expr::val(av.into_value().unwrap()))); } } self.query.columns(columns); diff --git a/src/query/join.rs b/src/query/join.rs index da60584fea..01d010ef86 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -1,5 +1,5 @@ use crate::{ - cast_enum_as_text, join_tbl_on_condition, unpack_table_ref, EntityTrait, IdenStatic, Iterable, + join_tbl_on_condition, unpack_table_ref, ColumnTrait, EntityTrait, IdenStatic, Iterable, Linked, QuerySelect, Related, Select, SelectA, SelectB, SelectTwo, SelectTwoMany, }; pub use sea_query::JoinType; @@ -100,7 +100,7 @@ where col.into_iden(), )); select_two.query().expr(SelectExpr { - expr: cast_enum_as_text(expr, &col), + expr: col.select_as(expr), alias: Some(SeaRc::new(Alias::new(&alias))), window: None, }); diff --git a/src/query/select.rs b/src/query/select.rs index 7b98ae686a..f747fb582d 100644 --- a/src/query/select.rs +++ b/src/query/select.rs @@ -1,7 +1,4 @@ -use crate::{ - cast_enum_as_text, ColumnTrait, EntityTrait, Iterable, QueryFilter, QueryOrder, QuerySelect, - QueryTrait, -}; +use crate::{ColumnTrait, EntityTrait, Iterable, QueryFilter, QueryOrder, QuerySelect, QueryTrait}; use core::fmt::Debug; use core::marker::PhantomData; pub use sea_query::JoinType; @@ -129,7 +126,7 @@ where fn column_list(&self) -> Vec { E::Column::iter() - .map(|col| cast_enum_as_text(col.into_expr(), &col)) + .map(|col| col.select_as(col.into_expr())) .collect() } diff --git a/src/query/update.rs b/src/query/update.rs index 8d5de74760..b98d93b920 100644 --- a/src/query/update.rs +++ b/src/query/update.rs @@ -1,6 +1,6 @@ use crate::{ - cast_text_as_enum, ActiveModelTrait, ColumnTrait, EntityTrait, Iterable, PrimaryKeyToColumn, - QueryFilter, QueryTrait, + ActiveModelTrait, ColumnTrait, EntityTrait, Iterable, PrimaryKeyToColumn, QueryFilter, + QueryTrait, }; use core::marker::PhantomData; use sea_query::{Expr, IntoIden, SimpleExpr, UpdateStatement}; @@ -109,7 +109,7 @@ where } let av = self.model.get(col); if av.is_set() { - let expr = cast_text_as_enum(Expr::val(av.into_value().unwrap()), &col); + let expr = col.save_as(Expr::val(av.into_value().unwrap())); self.query.value(col, expr); } } @@ -189,7 +189,7 @@ where for col in E::Column::iter() { let av = model.get(col); if av.is_set() { - let expr = cast_text_as_enum(Expr::val(av.into_value().unwrap()), &col); + let expr = col.save_as(Expr::val(av.into_value().unwrap())); self.query.value(col, expr); } } diff --git a/tests/collection_tests.rs b/tests/collection_tests.rs index dc961d1337..848114372b 100644 --- a/tests/collection_tests.rs +++ b/tests/collection_tests.rs @@ -24,6 +24,7 @@ pub async fn insert_collection(db: &DatabaseConnection) -> Result<(), DbErr> { assert_eq!( Model { id: 1, + name: "Collection 1".into(), integers: vec![1, 2, 3], integers_opt: Some(vec![1, 2, 3]), teas: vec![Tea::BreakfastTea], @@ -38,6 +39,7 @@ pub async fn insert_collection(db: &DatabaseConnection) -> Result<(), DbErr> { .await?, Model { id: 1, + name: "Collection 1".into(), integers: vec![1, 2, 3], integers_opt: Some(vec![1, 2, 3]), teas: vec![Tea::BreakfastTea], @@ -52,6 +54,7 @@ pub async fn insert_collection(db: &DatabaseConnection) -> Result<(), DbErr> { assert_eq!( Model { id: 2, + name: "Collection 2".into(), integers: vec![10, 9], integers_opt: None, teas: vec![Tea::BreakfastTea], @@ -66,6 +69,7 @@ pub async fn insert_collection(db: &DatabaseConnection) -> Result<(), DbErr> { .await?, Model { id: 2, + name: "Collection 2".into(), integers: vec![10, 9], integers_opt: None, teas: vec![Tea::BreakfastTea], @@ -80,6 +84,7 @@ pub async fn insert_collection(db: &DatabaseConnection) -> Result<(), DbErr> { assert_eq!( Model { id: 3, + name: "Collection 3".into(), integers: vec![], integers_opt: Some(vec![]), teas: vec![], @@ -94,6 +99,7 @@ pub async fn insert_collection(db: &DatabaseConnection) -> Result<(), DbErr> { .await?, Model { id: 3, + name: "Collection 3".into(), integers: vec![], integers_opt: Some(vec![]), teas: vec![], @@ -128,6 +134,7 @@ pub async fn update_collection(db: &DatabaseConnection) -> Result<(), DbErr> { ActiveModel { id: Unchanged(3), + name: Set("Collection 3".into()), integers: Set(vec![3, 1, 4]), integers_opt: Set(None), teas: Set(vec![Tea::EverydayTea]), diff --git a/tests/common/features/collection.rs b/tests/common/features/collection.rs index 75e6e7cd65..1b02016249 100644 --- a/tests/common/features/collection.rs +++ b/tests/common/features/collection.rs @@ -6,6 +6,12 @@ use sea_orm::entity::prelude::*; pub struct Model { #[sea_orm(primary_key)] pub id: i32, + #[sea_orm( + column_type = r#"Custom("citext".into())"#, + select_as = "text", + save_as = "citext" + )] + pub name: String, pub integers: Vec, pub integers_opt: Option>, pub teas: Vec, diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs index 7dee0611a5..4910e70893 100644 --- a/tests/common/features/schema.rs +++ b/tests/common/features/schema.rs @@ -335,6 +335,12 @@ pub async fn create_json_struct_table(db: &DbConn) -> Result } pub async fn create_collection_table(db: &DbConn) -> Result { + db.execute(sea_orm::Statement::from_string( + db.get_database_backend(), + "CREATE EXTENSION IF NOT EXISTS citext".into(), + )) + .await?; + let stmt = sea_query::Table::create() .table(collection::Entity) .col( @@ -344,6 +350,11 @@ pub async fn create_collection_table(db: &DbConn) -> Result { .auto_increment() .primary_key(), ) + .col( + ColumnDef::new(collection::Column::Name) + .custom(Alias::new("citext")) + .not_null(), + ) .col( ColumnDef::new(collection::Column::Integers) .array(sea_query::ColumnType::Integer)