From 2a2e5d6ba64640268d511d832a3abafe4b190fbb Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sat, 15 May 2021 01:17:53 +0800 Subject: [PATCH] SelectQuery Trait --- examples/sqlx-mysql/src/main.rs | 2 +- src/connector/select.rs | 10 + src/entity/base.rs | 2 +- src/entity/column.rs | 14 +- src/query/select.rs | 314 ++++++++++++++++++-------------- 5 files changed, 199 insertions(+), 143 deletions(-) diff --git a/examples/sqlx-mysql/src/main.rs b/examples/sqlx-mysql/src/main.rs index 458e1d8a..2bb1c652 100644 --- a/examples/sqlx-mysql/src/main.rs +++ b/examples/sqlx-mysql/src/main.rs @@ -1,4 +1,4 @@ -use sea_orm::{ColumnTrait, Database, EntityTrait, QueryErr}; +use sea_orm::{ColumnTrait, Database, EntityTrait, QueryErr, SelectQuery}; mod example_cake; mod example_fruit; diff --git a/src/connector/select.rs b/src/connector/select.rs index a1f7769c..1c1ba533 100644 --- a/src/connector/select.rs +++ b/src/connector/select.rs @@ -11,6 +11,16 @@ where model: PhantomData, } +#[derive(Clone, Debug)] +pub struct DoubleSelect +where + M: FromQueryResult, + N: FromQueryResult, +{ + query: SelectStatement, + model: PhantomData<(M, N)>, +} + impl Select where E: EntityTrait, diff --git a/src/entity/base.rs b/src/entity/base.rs index 05eff331..43b2beb9 100644 --- a/src/entity/base.rs +++ b/src/entity/base.rs @@ -1,6 +1,6 @@ use crate::{ ColumnTrait, ModelTrait, PrimaryKeyOfModel, PrimaryKeyTrait, RelationBuilder, RelationTrait, - RelationType, Select, + RelationType, Select, SelectQuery, }; use sea_query::{Iden, IntoIden, Value}; use std::fmt::Debug; diff --git a/src/entity/column.rs b/src/entity/column.rs index a8b7651b..a4702537 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -57,7 +57,7 @@ pub trait ColumnTrait: IdenStatic { bind_oper!(lte); /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -75,7 +75,7 @@ pub trait ColumnTrait: IdenStatic { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -93,7 +93,7 @@ pub trait ColumnTrait: IdenStatic { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -108,7 +108,7 @@ pub trait ColumnTrait: IdenStatic { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -123,7 +123,7 @@ pub trait ColumnTrait: IdenStatic { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -139,7 +139,7 @@ pub trait ColumnTrait: IdenStatic { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -155,7 +155,7 @@ pub trait ColumnTrait: IdenStatic { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() diff --git a/src/query/select.rs b/src/query/select.rs index 3814dc23..bdc101ae 100644 --- a/src/query/select.rs +++ b/src/query/select.rs @@ -6,13 +6,13 @@ use core::fmt::Debug; use core::marker::PhantomData; pub use sea_query::JoinType; use sea_query::{ - Alias, Expr, Iden, IntoColumnRef, IntoIden, Order, QueryBuilder, SelectExpr, SelectStatement, - SimpleExpr, + Alias, ColumnRef, Expr, Iden, IntoColumnRef, IntoIden, Order, QueryBuilder, SelectExpr, + SelectStatement, SimpleExpr, }; use std::rc::Rc; #[derive(Clone, Debug)] -pub struct Select +pub struct Select where E: EntityTrait, { @@ -39,7 +39,7 @@ impl IntoSimpleExpr for SimpleExpr { } } -impl Select +impl Select where E: EntityTrait, { @@ -67,76 +67,29 @@ where self } - pub fn select_only(mut self) -> Self { - self.query.clear_selects(); - self - } - - /// Add a select column - /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::PostgresQueryBuilder}; - /// - /// assert_eq!( - /// cake::Entity::find() - /// .select_only() - /// .column(cake::Column::Name) - /// .build(PostgresQueryBuilder) - /// .to_string(), - /// r#"SELECT "cake"."name" FROM "cake""# - /// ); - /// ``` - pub fn column(mut self, col: C) -> Self - where - C: IntoSimpleExpr, - { - self.query.expr(SelectExpr { - expr: col.into_simple_expr(), - alias: None, + fn apply_alias(mut self, pre: &str) -> Self { + self.query().exprs_mut_for_each(|sel| { + match &sel.alias { + Some(alias) => { + let alias = format!("{}{}", pre, alias.to_string().as_str()); + sel.alias = Some(Rc::new(Alias::new(&alias))); + } + None => { + let col = match &sel.expr { + SimpleExpr::Column(col_ref) => match &col_ref { + ColumnRef::Column(col) => col, + ColumnRef::TableColumn(_, col) => col, + }, + _ => panic!("cannot apply alias for expr other than Column"), + }; + let alias = format!("{}{}", pre, col.to_string().as_str()); + sel.alias = Some(Rc::new(Alias::new(&alias))); + } + }; }); self } - /// Add a select column with alias - /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::PostgresQueryBuilder}; - /// - /// assert_eq!( - /// cake::Entity::find() - /// .select_only() - /// .column_as(cake::Column::Id.count(), "count") - /// .build(PostgresQueryBuilder) - /// .to_string(), - /// r#"SELECT COUNT("cake"."id") AS "count" FROM "cake""# - /// ); - /// ``` - pub fn column_as(mut self, col: C, alias: &str) -> Self - where - C: IntoSimpleExpr, - { - self.query.expr(SelectExpr { - expr: col.into_simple_expr(), - alias: Some(Rc::new(Alias::new(alias))), - }); - self - } - - /// Add an AND WHERE expression - /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; - /// - /// assert_eq!( - /// cake::Entity::find() - /// .filter(cake::Column::Id.eq(5)) - /// .build(MysqlQueryBuilder) - /// .to_string(), - /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 5" - /// ); - /// ``` - pub fn filter(mut self, expr: SimpleExpr) -> Self { - self.query.and_where(expr); - self - } - pub fn belongs_to(self, model: &R::Model) -> Self where R: EntityTrait + Related, @@ -151,69 +104,6 @@ where } } - /// Add a group by column - /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::PostgresQueryBuilder}; - /// - /// assert_eq!( - /// cake::Entity::find() - /// .select_only() - /// .column(cake::Column::Name) - /// .group_by(cake::Column::Name) - /// .build(PostgresQueryBuilder) - /// .to_string(), - /// r#"SELECT "cake"."name" FROM "cake" GROUP BY "cake"."name""# - /// ); - /// ``` - pub fn group_by(mut self, col: C) -> Self - where - C: IntoSimpleExpr, - { - self.query.add_group_by(vec![col.into_simple_expr()]); - self - } - - /// Add an order_by expression (ascending) - /// ``` - /// use sea_orm::{EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; - /// - /// assert_eq!( - /// cake::Entity::find() - /// .order_by(cake::Column::Id) - /// .build(MysqlQueryBuilder) - /// .to_string(), - /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` ORDER BY `cake`.`id` ASC" - /// ); - /// ``` - pub fn order_by(mut self, col: C) -> Self - where - C: IntoSimpleExpr, - { - self.query.order_by_expr(col.into_simple_expr(), Order::Asc); - self - } - - /// Add an order_by expression (descending) - /// ``` - /// use sea_orm::{EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; - /// - /// assert_eq!( - /// cake::Entity::find() - /// .order_by_desc(cake::Column::Id) - /// .build(MysqlQueryBuilder) - /// .to_string(), - /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` ORDER BY `cake`.`id` DESC" - /// ); - /// ``` - pub fn order_by_desc(mut self, col: C) -> Self - where - C: IntoSimpleExpr, - { - self.query - .order_by_expr(col.into_simple_expr(), Order::Desc); - self - } - /// Join via [`RelationDef`]. pub fn join(mut self, join: JoinType, rel: RelationDef) -> Self { let own_tbl = E::default().into_iden(); @@ -305,10 +195,154 @@ where } } +pub trait SelectQuery: Sized { + fn query(&mut self) -> &mut SelectStatement; + + fn select_only(mut self) -> Self { + self.query().clear_selects(); + self + } + + /// Add a select column + /// ``` + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// + /// assert_eq!( + /// cake::Entity::find() + /// .select_only() + /// .column(cake::Column::Name) + /// .build(PostgresQueryBuilder) + /// .to_string(), + /// r#"SELECT "cake"."name" FROM "cake""# + /// ); + /// ``` + fn column(mut self, col: C) -> Self + where + C: ColumnTrait, + { + self.query().expr(col.into_simple_expr()); + self + } + + /// Add a select column with alias + /// ``` + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// + /// assert_eq!( + /// cake::Entity::find() + /// .select_only() + /// .column_as(cake::Column::Id.count(), "count") + /// .build(PostgresQueryBuilder) + /// .to_string(), + /// r#"SELECT COUNT("cake"."id") AS "count" FROM "cake""# + /// ); + /// ``` + fn column_as(mut self, col: C, alias: &str) -> Self + where + C: IntoSimpleExpr, + { + self.query().expr(SelectExpr { + expr: col.into_simple_expr(), + alias: Some(Rc::new(Alias::new(alias))), + }); + self + } + + /// Add an AND WHERE expression + /// ``` + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// + /// assert_eq!( + /// cake::Entity::find() + /// .filter(cake::Column::Id.eq(5)) + /// .build(MysqlQueryBuilder) + /// .to_string(), + /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 5" + /// ); + /// ``` + fn filter(mut self, expr: SimpleExpr) -> Self { + self.query().and_where(expr); + self + } + + /// Add a group by column + /// ``` + /// use sea_orm::{ColumnTrait, EntityTrait, SelectQuery, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// + /// assert_eq!( + /// cake::Entity::find() + /// .select_only() + /// .column(cake::Column::Name) + /// .group_by(cake::Column::Name) + /// .build(PostgresQueryBuilder) + /// .to_string(), + /// r#"SELECT "cake"."name" FROM "cake" GROUP BY "cake"."name""# + /// ); + /// ``` + fn group_by(mut self, col: C) -> Self + where + C: IntoSimpleExpr, + { + self.query().add_group_by(vec![col.into_simple_expr()]); + self + } + + /// Add an order_by expression (ascending) + /// ``` + /// use sea_orm::{EntityTrait, SelectQuery, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// + /// assert_eq!( + /// cake::Entity::find() + /// .order_by(cake::Column::Id) + /// .build(MysqlQueryBuilder) + /// .to_string(), + /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` ORDER BY `cake`.`id` ASC" + /// ); + /// ``` + fn order_by(mut self, col: C) -> Self + where + C: IntoSimpleExpr, + { + self.query() + .order_by_expr(col.into_simple_expr(), Order::Asc); + self + } + + /// Add an order_by expression (descending) + /// ``` + /// use sea_orm::{EntityTrait, SelectQuery, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// + /// assert_eq!( + /// cake::Entity::find() + /// .order_by_desc(cake::Column::Id) + /// .build(MysqlQueryBuilder) + /// .to_string(), + /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` ORDER BY `cake`.`id` DESC" + /// ); + /// ``` + fn order_by_desc(mut self, col: C) -> Self + where + C: IntoSimpleExpr, + { + self.query() + .order_by_expr(col.into_simple_expr(), Order::Desc); + self + } +} + +impl SelectQuery for Select +where + E: EntityTrait, +{ + fn query(&mut self) -> &mut SelectStatement { + &mut self.query + } +} + #[cfg(test)] mod tests { use crate::tests_cfg::{cake, fruit}; - use crate::{ColumnTrait, EntityTrait}; + use crate::{ColumnTrait, EntityTrait, SelectQuery}; use sea_query::MysqlQueryBuilder; #[test] @@ -394,4 +428,16 @@ mod tests { .join(" ") ); } + + #[test] + fn alias_1() { + assert_eq!( + cake::Entity::find() + .column_as(cake::Column::Id, "B") + .apply_alias("A_") + .build(MysqlQueryBuilder) + .to_string(), + "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`, `cake`.`id` AS `A_B` FROM `cake`", + ); + } }