From 541b94f15d6b968733485a7e3ffde1c33d26dafc Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 3 Sep 2021 11:23:29 +0800 Subject: [PATCH] Update query helper column_as --- src/entity/identity.rs | 34 ++++++++++++++++++++++++++++++++- src/executor/select.rs | 8 ++++---- src/query/combine.rs | 33 ++++++++++++++++++++++++++------ src/query/helper.rs | 40 ++++++--------------------------------- src/query/mod.rs | 2 +- tests/relational_tests.rs | 5 +++-- 6 files changed, 74 insertions(+), 48 deletions(-) diff --git a/src/entity/identity.rs b/src/entity/identity.rs index d1cc3170..d8623b7d 100644 --- a/src/entity/identity.rs +++ b/src/entity/identity.rs @@ -1,5 +1,6 @@ use crate::{ColumnTrait, EntityTrait, IdenStatic}; -use sea_query::{DynIden, IntoIden}; +use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc}; +use std::fmt; #[derive(Debug, Clone)] pub enum Identity { @@ -8,6 +9,25 @@ pub enum Identity { Ternary(DynIden, DynIden, DynIden), } +impl Iden for Identity { + fn unquoted(&self, s: &mut dyn fmt::Write) { + match self { + Identity::Unary(iden) => { + write!(s, "{}", iden.to_string()).unwrap(); + } + Identity::Binary(iden1, iden2) => { + write!(s, "{}", iden1.to_string()).unwrap(); + write!(s, "{}", iden2.to_string()).unwrap(); + } + Identity::Ternary(iden1, iden2, iden3) => { + write!(s, "{}", iden1.to_string()).unwrap(); + write!(s, "{}", iden2.to_string()).unwrap(); + write!(s, "{}", iden3.to_string()).unwrap(); + } + } + } +} + pub trait IntoIdentity { fn into_identity(self) -> Identity; } @@ -19,6 +39,18 @@ where fn identity_of(self) -> Identity; } +impl IntoIdentity for String { + fn into_identity(self) -> Identity { + self.as_str().into_identity() + } +} + +impl IntoIdentity for &str { + fn into_identity(self) -> Identity { + Identity::Unary(SeaRc::new(Alias::new(self))) + } +} + impl IntoIdentity for T where T: IdenStatic, diff --git a/src/executor/select.rs b/src/executor/select.rs index 836ea495..fc3a970b 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -1,6 +1,6 @@ use crate::{ - error::*, query::combine, DatabaseConnection, EntityTrait, FromQueryResult, Iterable, - JsonValue, ModelTrait, Paginator, PrimaryKeyToColumn, QueryResult, Select, SelectTwo, + error::*, DatabaseConnection, EntityTrait, FromQueryResult, IdenStatic, Iterable, JsonValue, + ModelTrait, Paginator, PrimaryKeyToColumn, QueryResult, Select, SelectA, SelectB, SelectTwo, SelectTwoMany, Statement, }; use sea_query::SelectStatement; @@ -66,8 +66,8 @@ where fn from_raw_query_result(res: QueryResult) -> Result { Ok(( - M::from_query_result(&res, combine::SELECT_A)?, - N::from_query_result_optional(&res, combine::SELECT_B)?, + M::from_query_result(&res, SelectA.as_str())?, + N::from_query_result_optional(&res, SelectB.as_str())?, )) } } diff --git a/src/query/combine.rs b/src/query/combine.rs index 8cce0510..0c0f151f 100644 --- a/src/query/combine.rs +++ b/src/query/combine.rs @@ -1,10 +1,31 @@ -use crate::{EntityTrait, IntoSimpleExpr, Iterable, QueryTrait, Select, SelectTwo, SelectTwoMany}; +use crate::{ + EntityTrait, IdenStatic, IntoSimpleExpr, Iterable, QueryTrait, Select, SelectTwo, SelectTwoMany, +}; use core::marker::PhantomData; pub use sea_query::JoinType; use sea_query::{Alias, ColumnRef, Iden, Order, SeaRc, SelectExpr, SelectStatement, SimpleExpr}; -pub const SELECT_A: &str = "A_"; -pub const SELECT_B: &str = "B_"; +macro_rules! select_def { + ( $ident: ident, $str: expr ) => { + #[derive(Debug, Clone, Copy)] + pub struct $ident; + + impl Iden for $ident { + fn unquoted(&self, s: &mut dyn std::fmt::Write) { + write!(s, "{}", self.as_str()).unwrap(); + } + } + + impl IdenStatic for $ident { + fn as_str(&self) -> &str { + $str + } + } + }; +} + +select_def!(SelectA, "A_"); +select_def!(SelectB, "B_"); impl Select where @@ -37,7 +58,7 @@ where where F: EntityTrait, { - self = self.apply_alias(SELECT_A); + self = self.apply_alias(SelectA.as_str()); SelectTwo::new(self.into_query()) } @@ -45,7 +66,7 @@ where where F: EntityTrait, { - self = self.apply_alias(SELECT_A); + self = self.apply_alias(SelectA.as_str()); SelectTwoMany::new(self.into_query()) } } @@ -102,7 +123,7 @@ where S: QueryTrait, { for col in ::iter() { - let alias = format!("{}{}", SELECT_B, col.to_string().as_str()); + let alias = format!("{}{}", SelectB.as_str(), col.as_str()); selector.query().expr(SelectExpr { expr: col.into_simple_expr(), alias: Some(SeaRc::new(Alias::new(&alias))), diff --git a/src/query/helper.rs b/src/query/helper.rs index 4ca44905..88a5c55c 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -1,11 +1,9 @@ use crate::{ - ColumnTrait, EntityTrait, Identity, IntoSimpleExpr, Iterable, ModelTrait, PrimaryKeyToColumn, - RelationDef, -}; -use sea_query::{ - Alias, Expr, Iden, IntoCondition, SeaRc, SelectExpr, SelectStatement, SimpleExpr, TableRef, + ColumnTrait, EntityTrait, Identity, IntoIdentity, IntoSimpleExpr, Iterable, ModelTrait, + PrimaryKeyToColumn, RelationDef, }; pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement}; +use sea_query::{Expr, IntoCondition, SeaRc, SelectExpr, SelectStatement, SimpleExpr, TableRef}; // LINT: when the column does not appear in tables selected from // LINT: when there is a group by clause, but some columns don't have aggregate functions @@ -55,40 +53,14 @@ pub trait QuerySelect: Sized { /// r#"SELECT COUNT("cake"."id") AS "count" FROM "cake""# /// ); /// ``` - fn column_as(mut self, col: C, alias: &str) -> Self + fn column_as(mut self, col: C, alias: I) -> Self where C: IntoSimpleExpr, + I: IntoIdentity, { self.query().expr(SelectExpr { expr: col.into_simple_expr(), - alias: Some(SeaRc::new(Alias::new(alias))), - }); - self - } - - /// Add a select column with prefixed alias - /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; - /// - /// assert_eq!( - /// cake::Entity::find() - /// .select_only() - /// .column_as_prefixed(cake::Column::Id.count(), "A_", cake::Column::Id) - /// .build(DbBackend::Postgres) - /// .to_string(), - /// r#"SELECT COUNT("cake"."id") AS "A_id" FROM "cake""# - /// ); - /// ``` - fn column_as_prefixed(mut self, col: C, prefix: &str, alias: I) -> Self - where - C: IntoSimpleExpr, - I: Iden, - { - self.query().expr(SelectExpr { - expr: col.into_simple_expr(), - alias: Some(SeaRc::new(Alias::new( - vec![prefix, alias.to_string().as_str()].join("").as_str(), - ))), + alias: Some(SeaRc::new(alias.into_identity())), }); self } diff --git a/src/query/mod.rs b/src/query/mod.rs index 899882ba..54cc12dd 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -9,7 +9,7 @@ mod select; mod traits; mod update; -// pub use combine::*; +pub use combine::{SelectA, SelectB}; pub use delete::*; pub use helper::*; pub use insert::*; diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs index 2d129d2d..198d4b24 100644 --- a/tests/relational_tests.rs +++ b/tests/relational_tests.rs @@ -484,6 +484,7 @@ pub async fn having() { ))] pub async fn linked() -> Result<(), DbErr> { use common::bakery_chain::Order; + use sea_orm::{SelectA, SelectB}; let ctx = TestContext::new("test_linked").await; @@ -665,8 +666,8 @@ pub async fn linked() -> Result<(), DbErr> { let baked_for_customers: Vec<(BakerLite, Option)> = Baker::find() .find_also_linked(baker::BakedForCustomer) .select_only() - .column_as_prefixed(baker::Column::Name, "A_", baker::Column::Name) - .column_as_prefixed(customer::Column::Name, "B_", customer::Column::Name) + .column_as(baker::Column::Name, (SelectA, baker::Column::Name)) + .column_as(customer::Column::Name, (SelectB, customer::Column::Name)) .group_by(baker::Column::Id) .group_by(customer::Column::Id) .group_by(baker::Column::Name)