use crate::{EntityName, Iden, IdenStatic, IntoSimpleExpr, Iterable}; use sea_query::{ Alias, BinOper, DynIden, Expr, IntoIden, SeaRc, SelectStatement, SimpleExpr, Value, }; use std::str::FromStr; // The original `sea_orm::ColumnType` enum was dropped since 0.11.0 // It was replaced by `sea_query::ColumnType`, we reexport it here to keep the `ColumnType` symbol pub use sea_query::ColumnType; /// Defines a Column for an Entity #[derive(Debug, Clone, PartialEq)] pub struct ColumnDef { pub(crate) col_type: ColumnType, pub(crate) null: bool, pub(crate) unique: bool, pub(crate) indexed: bool, pub(crate) default_value: Option, } macro_rules! bind_oper { ( $op: ident ) => { #[allow(missing_docs)] fn $op(&self, v: V) -> SimpleExpr where V: Into, { Expr::col((self.entity_name(), *self)).$op(v) } }; } macro_rules! bind_oper_with_enum_casting { ( $op: ident, $bin_op: ident ) => { #[allow(missing_docs)] fn $op(&self, v: V) -> SimpleExpr where V: Into, { let expr = self.save_as(Expr::val(v)); Expr::col((self.entity_name(), *self)).binary(BinOper::$bin_op, expr) } }; } macro_rules! bind_func_no_params { ( $func: ident ) => { /// See also SeaQuery's method with same name. fn $func(&self) -> SimpleExpr { Expr::col((self.entity_name(), *self)).$func() } }; } macro_rules! bind_vec_func { ( $func: ident ) => { #[allow(missing_docs)] #[allow(clippy::wrong_self_convention)] fn $func(&self, v: I) -> SimpleExpr where V: Into, I: IntoIterator, { Expr::col((self.entity_name(), *self)).$func(v) } }; } macro_rules! bind_subquery_func { ( $func: ident ) => { #[allow(clippy::wrong_self_convention)] #[allow(missing_docs)] fn $func(&self, s: SelectStatement) -> SimpleExpr { Expr::col((self.entity_name(), *self)).$func(s) } }; } // LINT: when the operand value does not match column type /// API for working with a `Column`. Mostly a wrapper of the identically named methods in [`sea_query::Expr`] pub trait ColumnTrait: IdenStatic + Iterable + FromStr { #[allow(missing_docs)] type EntityName: EntityName; /// Define a column for an Entity fn def(&self) -> ColumnDef; /// Get the name of the entity the column belongs to fn entity_name(&self) -> DynIden { SeaRc::new(Self::EntityName::default()) as DynIden } /// get the name of the entity the column belongs to fn as_column_ref(&self) -> (DynIden, DynIden) { (self.entity_name(), SeaRc::new(*self) as DynIden) } bind_oper_with_enum_casting!(eq, Equal); bind_oper_with_enum_casting!(ne, NotEqual); bind_oper!(gt); bind_oper!(gte); bind_oper!(lt); bind_oper!(lte); /// ``` /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Id.between(2, 3)) /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` BETWEEN 2 AND 3" /// ); /// ``` fn between(&self, a: V, b: V) -> SimpleExpr where V: Into, { Expr::col((self.entity_name(), *self)).between(a, b) } /// ``` /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Id.not_between(2, 3)) /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` NOT BETWEEN 2 AND 3" /// ); /// ``` fn not_between(&self, a: V, b: V) -> SimpleExpr where V: Into, { Expr::col((self.entity_name(), *self)).not_between(a, b) } /// ``` /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Name.like("cheese")) /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese'" /// ); /// ``` fn like(&self, s: T) -> SimpleExpr where T: Into, { Expr::col((self.entity_name(), *self)).like(s) } /// ``` /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Name.not_like("cheese")) /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` NOT LIKE 'cheese'" /// ); /// ``` fn not_like(&self, s: T) -> SimpleExpr where T: Into, { Expr::col((self.entity_name(), *self)).not_like(s) } /// ``` /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Name.starts_with("cheese")) /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese%'" /// ); /// ``` fn starts_with(&self, s: T) -> SimpleExpr where T: Into, { let pattern = format!("{}%", s.into()); Expr::col((self.entity_name(), *self)).like(pattern) } /// ``` /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Name.ends_with("cheese")) /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese'" /// ); /// ``` fn ends_with(&self, s: T) -> SimpleExpr where T: Into, { let pattern = format!("%{}", s.into()); Expr::col((self.entity_name(), *self)).like(pattern) } /// ``` /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Name.contains("cheese")) /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'" /// ); /// ``` fn contains(&self, s: T) -> SimpleExpr where T: Into, { let pattern = format!("%{}%", s.into()); Expr::col((self.entity_name(), *self)).like(pattern) } bind_func_no_params!(max); bind_func_no_params!(min); bind_func_no_params!(sum); bind_func_no_params!(count); bind_func_no_params!(is_null); bind_func_no_params!(is_not_null); /// Perform an operation if the column is null fn if_null(&self, v: V) -> SimpleExpr where V: Into, { Expr::col((self.entity_name(), *self)).if_null(v) } bind_vec_func!(is_in); bind_vec_func!(is_not_in); bind_subquery_func!(in_subquery); bind_subquery_func!(not_in_subquery); /// Construct a [`SimpleExpr::Column`] wrapped in [`Expr`]. fn into_expr(self) -> Expr { Expr::expr(self.into_simple_expr()) } /// Cast column expression used in select statement. /// It only cast database enum as text if it's an enum column. fn select_as(&self, expr: Expr) -> SimpleExpr { self.select_enum_as(expr) } /// Cast enum column as text; do nothing if `self` is not an enum. 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. /// 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 an enum column as enum type; do nothing if `self` is not an enum. 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) }) } } /// SeaORM's utility methods that act on [ColumnType] pub trait ColumnTypeTrait { /// Instantiate a new [ColumnDef] fn def(self) -> ColumnDef; /// Get the name of the enum if this is a enum column fn get_enum_name(&self) -> Option<&DynIden>; } impl ColumnTypeTrait for ColumnType { fn def(self) -> ColumnDef { ColumnDef { col_type: self, null: false, unique: false, indexed: false, default_value: None, } } fn get_enum_name(&self) -> Option<&DynIden> { enum_name(self) } } impl ColumnTypeTrait for ColumnDef { fn def(self) -> ColumnDef { self } fn get_enum_name(&self) -> Option<&DynIden> { enum_name(&self.col_type) } } fn enum_name(col_type: &ColumnType) -> Option<&DynIden> { match col_type { ColumnType::Enum { name, .. } => Some(name), ColumnType::Array(col_type) => enum_name(col_type), _ => None, } } impl ColumnDef { /// Marks the column as `UNIQUE` pub fn unique(mut self) -> Self { self.unique = true; self } /// Mark the column as nullable pub fn null(self) -> Self { self.nullable() } /// Mark the column as nullable pub fn nullable(mut self) -> Self { self.null = true; self } /// Set the `indexed` field to `true` pub fn indexed(mut self) -> Self { self.indexed = true; self } /// Set the default value pub fn default_value(mut self, value: T) -> Self where T: Into, { self.default_value = Some(value.into()); self } /// Get [ColumnType] as reference pub fn get_column_type(&self) -> &ColumnType { &self.col_type } /// Returns true if the column is nullable pub fn is_null(&self) -> bool { self.null } } struct Text; struct TextArray; impl Iden for Text { fn unquoted(&self, s: &mut dyn std::fmt::Write) { write!(s, "text").unwrap(); } } impl Iden for TextArray { fn unquoted(&self, s: &mut dyn std::fmt::Write) { write!(s, "text[]").unwrap(); } } 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::{ tests_cfg::*, ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait, }; use sea_query::Query; #[test] fn test_in_subquery_1() { assert_eq!( cake::Entity::find() .filter( Condition::any().add( cake::Column::Id.in_subquery( Query::select() .expr(cake::Column::Id.max()) .from(cake::Entity) .to_owned() ) ) ) .build(DbBackend::MySql) .to_string(), [ "SELECT `cake`.`id`, `cake`.`name` FROM `cake`", "WHERE `cake`.`id` IN (SELECT MAX(`cake`.`id`) FROM `cake`)", ] .join(" ") ); } #[test] fn test_in_subquery_2() { assert_eq!( cake::Entity::find() .filter( Condition::any().add( cake::Column::Id.in_subquery( Query::select() .column(cake_filling::Column::CakeId) .from(cake_filling::Entity) .to_owned() ) ) ) .build(DbBackend::MySql) .to_string(), [ "SELECT `cake`.`id`, `cake`.`name` FROM `cake`", "WHERE `cake`.`id` IN (SELECT `cake_id` FROM `cake_filling`)", ] .join(" ") ); } #[test] fn test_col_from_str() { use std::str::FromStr; assert!(matches!( fruit::Column::from_str("id"), Ok(fruit::Column::Id) )); assert!(matches!( fruit::Column::from_str("name"), Ok(fruit::Column::Name) )); assert!(matches!( fruit::Column::from_str("cake_id"), Ok(fruit::Column::CakeId) )); assert!(matches!( fruit::Column::from_str("cakeId"), Ok(fruit::Column::CakeId) )); assert!(matches!( fruit::Column::from_str("does_not_exist"), Err(crate::ColumnFromStrErr(_)) )); } #[test] #[cfg(feature = "macros")] fn entity_model_column_1() { use crate::entity::*; mod hello { 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, pub one: i32, #[sea_orm(unique)] pub two: i8, #[sea_orm(indexed)] pub three: i16, #[sea_orm(nullable)] pub four: i32, #[sea_orm(unique, indexed, nullable)] pub five: i64, #[sea_orm(unique)] pub six: u8, #[sea_orm(indexed)] pub seven: u16, #[sea_orm(nullable)] pub eight: u32, #[sea_orm(unique, indexed, nullable)] pub nine: u64, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} impl ActiveModelBehavior for ActiveModel {} } assert_eq!(hello::Column::One.def(), ColumnType::Integer.def()); assert_eq!( hello::Column::Two.def(), ColumnType::TinyInteger.def().unique() ); assert_eq!( hello::Column::Three.def(), ColumnType::SmallInteger.def().indexed() ); assert_eq!( hello::Column::Four.def(), ColumnType::Integer.def().nullable() ); assert_eq!( hello::Column::Five.def(), ColumnType::BigInteger.def().unique().indexed().nullable() ); assert_eq!( hello::Column::Six.def(), ColumnType::TinyUnsigned.def().unique() ); assert_eq!( hello::Column::Seven.def(), ColumnType::SmallUnsigned.def().indexed() ); assert_eq!( hello::Column::Eight.def(), ColumnType::Unsigned.def().nullable() ); assert_eq!( hello::Column::Nine.def(), ColumnType::BigUnsigned.def().unique().indexed().nullable() ); } #[test] #[cfg(feature = "macros")] fn column_name_1() { use sea_query::Iden; mod hello { 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(column_name = "ONE")] pub one: i32, pub two: i32, #[sea_orm(column_name = "3")] pub three: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} impl ActiveModelBehavior for ActiveModel {} } assert_eq!(hello::Column::One.to_string().as_str(), "ONE"); assert_eq!(hello::Column::Two.to_string().as_str(), "two"); assert_eq!(hello::Column::Three.to_string().as_str(), "3"); } #[test] #[cfg(feature = "macros")] fn column_name_2() { use sea_query::Iden; mod hello { use crate as sea_orm; use crate::entity::prelude::*; #[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, pub one: i32, pub two: i32, pub three: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] pub enum Column { Id, #[sea_orm(column_name = "ONE")] One, Two, #[sea_orm(column_name = "3")] Three, } impl ColumnTrait for Column { type EntityName = Entity; fn def(&self) -> ColumnDef { match self { Column::Id => ColumnType::Integer.def(), Column::One => ColumnType::Integer.def(), Column::Two => ColumnType::Integer.def(), Column::Three => ColumnType::Integer.def(), } } } #[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 {} } assert_eq!(hello::Column::One.to_string().as_str(), "ONE"); assert_eq!(hello::Column::Two.to_string().as_str(), "two"); assert_eq!(hello::Column::Three.to_string().as_str(), "3"); } #[test] #[cfg(feature = "macros")] fn enum_name_1() { use sea_query::Iden; mod hello { 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, pub two: i32, #[sea_orm(enum_name = "Three3")] pub three: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} impl ActiveModelBehavior for ActiveModel {} } assert_eq!(hello::Column::One1.to_string().as_str(), "one1"); assert_eq!(hello::Column::Two.to_string().as_str(), "two"); assert_eq!(hello::Column::Three3.to_string().as_str(), "three3"); } #[test] #[cfg(feature = "macros")] fn enum_name_2() { use sea_query::Iden; mod hello { use crate as sea_orm; use crate::entity::prelude::*; #[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(), } } } #[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 {} } assert_eq!(hello::Column::One1.to_string().as_str(), "one1"); assert_eq!(hello::Column::Two.to_string().as_str(), "two"); assert_eq!(hello::Column::Three3.to_string().as_str(), "three3"); } #[test] #[cfg(feature = "macros")] fn column_name_enum_name_1() { use sea_query::Iden; #[allow(clippy::enum_variant_names)] mod hello { 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, column_name = "ID", enum_name = "IdentityColumn")] pub id: i32, #[sea_orm(column_name = "ONE", enum_name = "One1")] pub one: i32, pub two: i32, #[sea_orm(column_name = "THREE", enum_name = "Three3")] pub three: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} impl ActiveModelBehavior for ActiveModel {} } assert_eq!(hello::Column::IdentityColumn.to_string().as_str(), "ID"); assert_eq!(hello::Column::One1.to_string().as_str(), "ONE"); assert_eq!(hello::Column::Two.to_string().as_str(), "two"); assert_eq!(hello::Column::Three3.to_string().as_str(), "THREE"); } #[test] #[cfg(feature = "macros")] fn column_name_enum_name_2() { use sea_query::Iden; mod hello { use crate as sea_orm; use crate::entity::prelude::*; #[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 { #[sea_orm(enum_name = "IdentityCol")] 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 { #[sea_orm(column_name = "ID")] IdentityCol, #[sea_orm(column_name = "ONE")] One1, Two, #[sea_orm(column_name = "THREE")] Three3, } impl ColumnTrait for Column { type EntityName = Entity; fn def(&self) -> ColumnDef { match self { Column::IdentityCol => ColumnType::Integer.def(), Column::One1 => ColumnType::Integer.def(), Column::Two => ColumnType::Integer.def(), Column::Three3 => ColumnType::Integer.def(), } } } #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] pub enum PrimaryKey { IdentityCol, } 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 {} } assert_eq!(hello::Column::IdentityCol.to_string().as_str(), "ID"); assert_eq!(hello::Column::One1.to_string().as_str(), "ONE"); assert_eq!(hello::Column::Two.to_string().as_str(), "two"); assert_eq!(hello::Column::Three3.to_string().as_str(), "THREE"); } #[test] #[cfg(feature = "macros")] fn column_name_enum_name_3() { use sea_query::Iden; mod my_entity { use crate as sea_orm; use crate::entity::prelude::*; #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[sea_orm(table_name = "my_entity")] pub struct Model { #[sea_orm(primary_key, enum_name = "IdentityColumn", column_name = "id")] pub id: i32, #[sea_orm(column_name = "type")] pub type_: String, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} impl ActiveModelBehavior for ActiveModel {} } 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 => expr.cast_as(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, val: Expr) -> SimpleExpr { match self { Self::Two => val.cast_as(Alias::new("text")), _ => self.save_enum_as(val), } } } #[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 => expr.cast_as(Alias::new("integer")), _ => self.select_enum_as(expr), } } fn save_as(&self, val: Expr) -> SimpleExpr { match self { Self::Two => val.cast_as(Alias::new("text")), _ => self.save_enum_as(val), } } } #[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), }); } }