From 1087706afe9807160def527c2cae05a24f5d043f Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 21 Oct 2021 15:34:23 +0800 Subject: [PATCH 1/7] Cast expression as custom type --- src/func.rs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/func.rs b/src/func.rs index 032e6f503..6bfcfbc3c 100644 --- a/src/func.rs +++ b/src/func.rs @@ -322,7 +322,41 @@ impl Func { V: Into, I: IntoIden, { - Expr::func(Function::Cast).arg(Expr::val(value.into()).bin_oper( + Self::cast_expr_as(Expr::val(value), iden) + } + + /// Call `CAST` function to cast expression into a custom type. + /// + /// # Examples + /// + /// ``` + /// use sea_query::{tests_cfg::*, *}; + /// + /// let query = Query::select() + /// .expr(Func::cast_expr_as( + /// Expr::tbl(Font::Table, Font::Name), + /// Alias::new("MyType"), + /// )) + /// .to_owned(); + /// + /// assert_eq!( + /// query.to_string(MysqlQueryBuilder), + /// r#"SELECT CAST(`font`.`name` AS MyType)"# + /// ); + /// assert_eq!( + /// query.to_string(PostgresQueryBuilder), + /// r#"SELECT CAST("font"."name" AS MyType)"# + /// ); + /// assert_eq!( + /// query.to_string(SqliteQueryBuilder), + /// r#"SELECT CAST(`font`.`name` AS MyType)"# + /// ); + /// ``` + pub fn cast_expr_as(expr: Expr, iden: I) -> SimpleExpr + where + I: IntoIden, + { + Expr::func(Function::Cast).arg(expr.bin_oper( BinOper::As, Expr::cust(iden.into_iden().to_string().as_str()), )) From 6b39d42b907f236f1d6138b6c25e30a07038a4e2 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 26 Oct 2021 16:19:35 +0800 Subject: [PATCH 2/7] Try `EnumValue` --- src/backend/postgres/query.rs | 19 +++++++++++++++++++ src/backend/query_builder.rs | 12 ++++++++++++ src/expr.rs | 1 + 3 files changed, 32 insertions(+) diff --git a/src/backend/postgres/query.rs b/src/backend/postgres/query.rs index 0d4ccdf32..ec9cd3c5f 100644 --- a/src/backend/postgres/query.rs +++ b/src/backend/postgres/query.rs @@ -77,4 +77,23 @@ impl QueryBuilder for PostgresQueryBuilder { _ => self.prepare_function_common(function, sql, collector), } } + + fn prepare_simple_expr( + &self, + simple_expr: &SimpleExpr, + sql: &mut SqlWriter, + collector: &mut dyn FnMut(Value), + ) { + match simple_expr { + SimpleExpr::EnumValue(enum_name, expr) => { + let simple_expr = Expr::func(Function::Cast).arg(SimpleExpr::Binary( + expr.clone(), + BinOper::As, + Box::new(Expr::cust(enum_name.as_str())) + )); + self.prepare_simple_expr_common(&simple_expr, sql, collector); + }, + _ => QueryBuilder::prepare_simple_expr_common(self, simple_expr, sql, collector), + } + } } diff --git a/src/backend/query_builder.rs b/src/backend/query_builder.rs index 3c7a01467..2c4dbd312 100644 --- a/src/backend/query_builder.rs +++ b/src/backend/query_builder.rs @@ -225,6 +225,15 @@ pub trait QueryBuilder: QuotedBuilder { simple_expr: &SimpleExpr, sql: &mut SqlWriter, collector: &mut dyn FnMut(Value), + ) { + self.prepare_simple_expr_common(simple_expr, sql, collector); + } + + fn prepare_simple_expr_common( + &self, + simple_expr: &SimpleExpr, + sql: &mut SqlWriter, + collector: &mut dyn FnMut(Value), ) { match simple_expr { SimpleExpr::Column(column_ref) => { @@ -328,6 +337,9 @@ pub trait QueryBuilder: QuotedBuilder { SimpleExpr::Keyword(keyword) => { self.prepare_keyword(keyword, sql, collector); } + SimpleExpr::EnumValue(_, expr) => { + self.prepare_simple_expr(expr, sql, collector); + } } } diff --git a/src/expr.rs b/src/expr.rs index c653b3eee..6c0f62fc3 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -33,6 +33,7 @@ pub enum SimpleExpr { Custom(String), CustomWithValues(String, Vec), Keyword(Keyword), + EnumValue(String, Box), } impl Expr { From 68308d9222ea6378db3440d80eb8f1ffbf18d40c Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 26 Oct 2021 17:44:42 +0800 Subject: [PATCH 3/7] Refactoring --- src/backend/postgres/query.rs | 8 ++------ src/expr.rs | 21 ++++++++++++++++++++ src/func.rs | 36 +---------------------------------- 3 files changed, 24 insertions(+), 41 deletions(-) diff --git a/src/backend/postgres/query.rs b/src/backend/postgres/query.rs index ec9cd3c5f..ec697eb56 100644 --- a/src/backend/postgres/query.rs +++ b/src/backend/postgres/query.rs @@ -85,12 +85,8 @@ impl QueryBuilder for PostgresQueryBuilder { collector: &mut dyn FnMut(Value), ) { match simple_expr { - SimpleExpr::EnumValue(enum_name, expr) => { - let simple_expr = Expr::func(Function::Cast).arg(SimpleExpr::Binary( - expr.clone(), - BinOper::As, - Box::new(Expr::cust(enum_name.as_str())) - )); + SimpleExpr::EnumValue(type_name, expr) => { + let simple_expr = expr.clone().cast_expr_as(type_name); self.prepare_simple_expr_common(&simple_expr, sql, collector); }, _ => QueryBuilder::prepare_simple_expr_common(self, simple_expr, sql, collector), diff --git a/src/expr.rs b/src/expr.rs index 6c0f62fc3..5d3046c6e 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1425,6 +1425,17 @@ impl Expr { self.into() } + pub fn enum_value(type_name: T, expr: I) -> SimpleExpr + where + T: ToString, + I: Into, + { + SimpleExpr::EnumValue( + type_name.to_string(), + Box::new(expr.into()) + ) + } + fn func_with_args(func: Function, args: Vec) -> SimpleExpr { let mut expr = Expr::new(); expr.func = Some(func); @@ -1794,4 +1805,14 @@ impl SimpleExpr { { self.concatenate(right) } + + pub fn cast_expr_as(self, type_name: T) -> Self + where + T: ToString, + { + Self::FunctionCall( + Function::Cast, + vec![self] + ).binary(BinOper::As, Expr::cust(type_name.to_string().as_str())) + } } diff --git a/src/func.rs b/src/func.rs index 6bfcfbc3c..032e6f503 100644 --- a/src/func.rs +++ b/src/func.rs @@ -322,41 +322,7 @@ impl Func { V: Into, I: IntoIden, { - Self::cast_expr_as(Expr::val(value), iden) - } - - /// Call `CAST` function to cast expression into a custom type. - /// - /// # Examples - /// - /// ``` - /// use sea_query::{tests_cfg::*, *}; - /// - /// let query = Query::select() - /// .expr(Func::cast_expr_as( - /// Expr::tbl(Font::Table, Font::Name), - /// Alias::new("MyType"), - /// )) - /// .to_owned(); - /// - /// assert_eq!( - /// query.to_string(MysqlQueryBuilder), - /// r#"SELECT CAST(`font`.`name` AS MyType)"# - /// ); - /// assert_eq!( - /// query.to_string(PostgresQueryBuilder), - /// r#"SELECT CAST("font"."name" AS MyType)"# - /// ); - /// assert_eq!( - /// query.to_string(SqliteQueryBuilder), - /// r#"SELECT CAST(`font`.`name` AS MyType)"# - /// ); - /// ``` - pub fn cast_expr_as(expr: Expr, iden: I) -> SimpleExpr - where - I: IntoIden, - { - Expr::func(Function::Cast).arg(expr.bin_oper( + Expr::func(Function::Cast).arg(Expr::val(value.into()).bin_oper( BinOper::As, Expr::cust(iden.into_iden().to_string().as_str()), )) From c2d0304f7577f30b999e71105b77964c06d26a3d Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 26 Oct 2021 17:47:26 +0800 Subject: [PATCH 4/7] cargo fmt --- src/backend/postgres/query.rs | 2 +- src/expr.rs | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/backend/postgres/query.rs b/src/backend/postgres/query.rs index ec697eb56..1760d00f5 100644 --- a/src/backend/postgres/query.rs +++ b/src/backend/postgres/query.rs @@ -88,7 +88,7 @@ impl QueryBuilder for PostgresQueryBuilder { SimpleExpr::EnumValue(type_name, expr) => { let simple_expr = expr.clone().cast_expr_as(type_name); self.prepare_simple_expr_common(&simple_expr, sql, collector); - }, + } _ => QueryBuilder::prepare_simple_expr_common(self, simple_expr, sql, collector), } } diff --git a/src/expr.rs b/src/expr.rs index 5d3046c6e..2fabf1394 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1430,10 +1430,7 @@ impl Expr { T: ToString, I: Into, { - SimpleExpr::EnumValue( - type_name.to_string(), - Box::new(expr.into()) - ) + SimpleExpr::EnumValue(type_name.to_string(), Box::new(expr.into())) } fn func_with_args(func: Function, args: Vec) -> SimpleExpr { @@ -1810,9 +1807,7 @@ impl SimpleExpr { where T: ToString, { - Self::FunctionCall( - Function::Cast, - vec![self] - ).binary(BinOper::As, Expr::cust(type_name.to_string().as_str())) + Self::FunctionCall(Function::Cast, vec![self]) + .binary(BinOper::As, Expr::cust(type_name.to_string().as_str())) } } From 32e2bee553de36702d7b3c3717cc55a4b1d2c0d6 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 26 Oct 2021 18:56:55 +0800 Subject: [PATCH 5/7] Rename & Refactoring --- src/backend/postgres/query.rs | 4 ++-- src/backend/query_builder.rs | 2 +- src/expr.rs | 22 +++++++++++++--------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/backend/postgres/query.rs b/src/backend/postgres/query.rs index 1760d00f5..16c138ee0 100644 --- a/src/backend/postgres/query.rs +++ b/src/backend/postgres/query.rs @@ -85,8 +85,8 @@ impl QueryBuilder for PostgresQueryBuilder { collector: &mut dyn FnMut(Value), ) { match simple_expr { - SimpleExpr::EnumValue(type_name, expr) => { - let simple_expr = expr.clone().cast_expr_as(type_name); + SimpleExpr::AsEnum(type_name, expr) => { + let simple_expr = expr.clone().cast_as(SeaRc::clone(type_name)); self.prepare_simple_expr_common(&simple_expr, sql, collector); } _ => QueryBuilder::prepare_simple_expr_common(self, simple_expr, sql, collector), diff --git a/src/backend/query_builder.rs b/src/backend/query_builder.rs index 2c4dbd312..2c7ab9c35 100644 --- a/src/backend/query_builder.rs +++ b/src/backend/query_builder.rs @@ -337,7 +337,7 @@ pub trait QueryBuilder: QuotedBuilder { SimpleExpr::Keyword(keyword) => { self.prepare_keyword(keyword, sql, collector); } - SimpleExpr::EnumValue(_, expr) => { + SimpleExpr::AsEnum(_, expr) => { self.prepare_simple_expr(expr, sql, collector); } } diff --git a/src/expr.rs b/src/expr.rs index 2fabf1394..bcbf65082 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -33,7 +33,7 @@ pub enum SimpleExpr { Custom(String), CustomWithValues(String, Vec), Keyword(Keyword), - EnumValue(String, Box), + AsEnum(DynIden, Box), } impl Expr { @@ -1425,12 +1425,11 @@ impl Expr { self.into() } - pub fn enum_value(type_name: T, expr: I) -> SimpleExpr + pub fn as_enum(self, type_name: T) -> SimpleExpr where - T: ToString, - I: Into, + T: IntoIden, { - SimpleExpr::EnumValue(type_name.to_string(), Box::new(expr.into())) + SimpleExpr::AsEnum(type_name.into_iden(), Box::new(self.into())) } fn func_with_args(func: Function, args: Vec) -> SimpleExpr { @@ -1803,11 +1802,16 @@ impl SimpleExpr { self.concatenate(right) } - pub fn cast_expr_as(self, type_name: T) -> Self + pub fn cast_as(self, type_name: T) -> Self where - T: ToString, + T: IntoIden, { - Self::FunctionCall(Function::Cast, vec![self]) - .binary(BinOper::As, Expr::cust(type_name.to_string().as_str())) + Self::FunctionCall( + Function::Cast, + vec![self.binary( + BinOper::As, + Expr::cust(type_name.into_iden().to_string().as_str()), + )], + ) } } From f78280f414e96bc87c58d74bf3e30fe2a9631d2d Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 27 Oct 2021 18:21:21 +0800 Subject: [PATCH 6/7] Add docs --- src/expr.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/expr.rs b/src/expr.rs index bcbf65082..4da6a4236 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1425,6 +1425,31 @@ impl Expr { self.into() } + /// Express a `AS enum` expression. + /// + /// # Examples + /// + /// ``` + /// use sea_query::{*, tests_cfg::*}; + /// + /// let query = Query::select() + /// .expr(Expr::col(Char::Character).as_enum(Alias::new("Enum"))) + /// .from(Char::Table) + /// .to_owned(); + /// + /// assert_eq!( + /// query.to_string(MysqlQueryBuilder), + /// r#"SELECT `character` FROM `character`"# + /// ); + /// assert_eq!( + /// query.to_string(PostgresQueryBuilder), + /// r#"SELECT CAST("character" AS Enum) FROM "character""# + /// ); + /// assert_eq!( + /// query.to_string(SqliteQueryBuilder), + /// r#"SELECT `character` FROM `character`"# + /// ); + /// ``` pub fn as_enum(self, type_name: T) -> SimpleExpr where T: IntoIden, @@ -1802,6 +1827,30 @@ impl SimpleExpr { self.concatenate(right) } + /// Express a `CAST AS` expression. + /// + /// # Examples + /// + /// ``` + /// use sea_query::{*, tests_cfg::*}; + /// + /// let query = Query::select() + /// .expr(Expr::value("1").cast_as(Alias::new("integer"))) + /// .to_owned(); + /// + /// assert_eq!( + /// query.to_string(MysqlQueryBuilder), + /// r#"SELECT CAST('1' AS integer)"# + /// ); + /// assert_eq!( + /// query.to_string(PostgresQueryBuilder), + /// r#"SELECT CAST('1' AS integer)"# + /// ); + /// assert_eq!( + /// query.to_string(SqliteQueryBuilder), + /// r#"SELECT CAST('1' AS integer)"# + /// ); + /// ``` pub fn cast_as(self, type_name: T) -> Self where T: IntoIden, From 545eda231a11bada6f5b9d9c20d7c2ab51fbe292 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 27 Oct 2021 18:45:58 +0800 Subject: [PATCH 7/7] Update docs --- src/expr.rs | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 4da6a4236..8e73e2b8a 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1430,24 +1430,43 @@ impl Expr { /// # Examples /// /// ``` - /// use sea_query::{*, tests_cfg::*}; + /// use sea_query::{tests_cfg::*, *}; /// /// let query = Query::select() - /// .expr(Expr::col(Char::Character).as_enum(Alias::new("Enum"))) + /// .expr(Expr::col(Char::FontSize).as_enum(Alias::new("text"))) /// .from(Char::Table) /// .to_owned(); /// /// assert_eq!( /// query.to_string(MysqlQueryBuilder), - /// r#"SELECT `character` FROM `character`"# + /// r#"SELECT `font_size` FROM `character`"# + /// ); + /// assert_eq!( + /// query.to_string(PostgresQueryBuilder), + /// r#"SELECT CAST("font_size" AS text) FROM "character""# + /// ); + /// assert_eq!( + /// query.to_string(SqliteQueryBuilder), + /// r#"SELECT `font_size` FROM `character`"# + /// ); + /// + /// let query = Query::insert() + /// .into_table(Char::Table) + /// .columns(vec![Char::FontSize]) + /// .exprs_panic(vec![Expr::val("large").as_enum(Alias::new("FontSizeEnum"))]) + /// .to_owned(); + /// + /// assert_eq!( + /// query.to_string(MysqlQueryBuilder), + /// r#"INSERT INTO `character` (`font_size`) VALUES ('large')"# /// ); /// assert_eq!( /// query.to_string(PostgresQueryBuilder), - /// r#"SELECT CAST("character" AS Enum) FROM "character""# + /// r#"INSERT INTO "character" ("font_size") VALUES (CAST('large' AS FontSizeEnum))"# /// ); /// assert_eq!( /// query.to_string(SqliteQueryBuilder), - /// r#"SELECT `character` FROM `character`"# + /// r#"INSERT INTO `character` (`font_size`) VALUES ('large')"# /// ); /// ``` pub fn as_enum(self, type_name: T) -> SimpleExpr @@ -1832,7 +1851,7 @@ impl SimpleExpr { /// # Examples /// /// ``` - /// use sea_query::{*, tests_cfg::*}; + /// use sea_query::{tests_cfg::*, *}; /// /// let query = Query::select() /// .expr(Expr::value("1").cast_as(Alias::new("integer")))