From 2fc4520ee82ca8a55f295a786d9d9e11c6a423be Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Wed, 2 Jun 2021 00:35:51 +0800 Subject: [PATCH] Refactor Query as traits --- src/entity/base.rs | 4 +- src/entity/column.rs | 14 +++--- src/entity/prelude.rs | 4 +- src/lib.rs | 2 +- src/query/combine.rs | 2 +- src/query/helper.rs | 114 +++++++++++++++++++++++++----------------- src/query/insert.rs | 2 +- src/query/join.rs | 22 +------- src/query/select.rs | 29 +++++++++-- src/query/traits.rs | 8 +-- 10 files changed, 114 insertions(+), 87 deletions(-) diff --git a/src/entity/base.rs b/src/entity/base.rs index 592c90e6..43124db5 100644 --- a/src/entity/base.rs +++ b/src/entity/base.rs @@ -1,7 +1,7 @@ use crate::{ ActiveModelOf, ActiveModelTrait, ColumnTrait, Insert, ModelTrait, OneOrManyActiveModel, - PrimaryKeyOfModel, PrimaryKeyTrait, RelationBuilder, RelationTrait, RelationType, Select, - SelectHelper, + PrimaryKeyOfModel, PrimaryKeyTrait, QueryFilter, RelationBuilder, RelationTrait, RelationType, + Select, }; use sea_query::{Iden, IntoValueTuple}; use std::fmt::Debug; diff --git a/src/entity/column.rs b/src/entity/column.rs index 42034342..46dc178e 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -57,7 +57,7 @@ pub trait ColumnTrait: IdenStatic + Iterable { bind_oper!(lte); /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -75,7 +75,7 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -93,7 +93,7 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -108,7 +108,7 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -123,7 +123,7 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -139,7 +139,7 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -155,7 +155,7 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index 1482a509..601a4349 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -1,6 +1,6 @@ pub use crate::{ ActiveModelOf, ActiveModelTrait, ColumnTrait, ColumnType, DeriveActiveModel, DeriveColumn, DeriveEntity, DeriveModel, DerivePrimaryKey, EntityName, EntityTrait, EnumIter, Iden, - IdenStatic, ModelTrait, PrimaryKeyOfModel, PrimaryKeyTrait, QueryResult, Related, RelationDef, - RelationTrait, Select, TypeErr, Value, + IdenStatic, ModelTrait, PrimaryKeyOfModel, PrimaryKeyTrait, QueryFilter, QueryResult, Related, + RelationDef, RelationTrait, Select, TypeErr, Value, }; diff --git a/src/lib.rs b/src/lib.rs index b44ee556..cbafdce8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ mod connector; mod database; mod driver; pub mod entity; -mod query; +pub mod query; pub mod tests_cfg; mod util; diff --git a/src/query/combine.rs b/src/query/combine.rs index c387193a..54edfbdd 100644 --- a/src/query/combine.rs +++ b/src/query/combine.rs @@ -71,7 +71,7 @@ where #[cfg(test)] mod tests { use crate::tests_cfg::{cake, fruit}; - use crate::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper}; + use crate::{ColumnTrait, EntityTrait, QueryFilter, QueryTrait, SelectHelper}; use sea_query::MysqlQueryBuilder; #[test] diff --git a/src/query/helper.rs b/src/query/helper.rs index 914b2adc..8f2a5a24 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -1,6 +1,9 @@ -use crate::{ColumnTrait, Identity, IntoSimpleExpr, RelationDef}; +use crate::{ + ColumnTrait, EntityTrait, Identity, IntoSimpleExpr, Iterable, ModelTrait, PrimaryKeyOfModel, + RelationDef, +}; use sea_query::{Alias, Expr, IntoCondition, SelectExpr, SelectStatement, SimpleExpr}; -pub use sea_query::{Condition, JoinType, Order}; +pub use sea_query::{Condition, ConditionalStatement, JoinType, Order}; use std::rc::Rc; pub trait SelectHelper: Sized { @@ -14,7 +17,7 @@ pub trait SelectHelper: Sized { /// Add a select column /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -35,7 +38,7 @@ pub trait SelectHelper: Sized { /// Add a select column with alias /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -57,47 +60,9 @@ pub trait SelectHelper: Sized { self } - /// Add an AND WHERE expression - /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; - /// - /// assert_eq!( - /// cake::Entity::find() - /// .filter(cake::Column::Id.eq(4)) - /// .filter(cake::Column::Id.eq(5)) - /// .build(MysqlQueryBuilder) - /// .to_string(), - /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 AND `cake`.`id` = 5" - /// ); - /// ``` - /// - /// Add a condition tree. - /// ``` - /// use sea_orm::{Condition, ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; - /// - /// assert_eq!( - /// cake::Entity::find() - /// .filter( - /// Condition::any() - /// .add(cake::Column::Id.eq(4)) - /// .add(cake::Column::Id.eq(5)) - /// ) - /// .build(MysqlQueryBuilder) - /// .to_string(), - /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 OR `cake`.`id` = 5" - /// ); - /// ``` - fn filter(mut self, filter: F) -> Self - where - F: IntoCondition, - { - self.query().cond_where(filter.into_condition()); - self - } - /// Add a group by column /// ``` - /// use sea_orm::{ColumnTrait, EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -119,7 +84,7 @@ pub trait SelectHelper: Sized { /// Add an order_by expression /// ``` - /// use sea_orm::{EntityTrait, Order, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -140,7 +105,7 @@ pub trait SelectHelper: Sized { /// Add an order_by expression (ascending) /// ``` - /// use sea_orm::{EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -161,7 +126,7 @@ pub trait SelectHelper: Sized { /// Add an order_by expression (descending) /// ``` - /// use sea_orm::{EntityTrait, QueryTrait, SelectHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// /// assert_eq!( /// cake::Entity::find() @@ -214,6 +179,63 @@ pub trait SelectHelper: Sized { } } +pub trait QueryFilter: Sized { + type QueryStatement: ConditionalStatement; + + fn query(&mut self) -> &mut Self::QueryStatement; + + /// Add an AND WHERE expression + /// ``` + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// + /// assert_eq!( + /// cake::Entity::find() + /// .filter(cake::Column::Id.eq(4)) + /// .filter(cake::Column::Id.eq(5)) + /// .build(MysqlQueryBuilder) + /// .to_string(), + /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 AND `cake`.`id` = 5" + /// ); + /// ``` + /// + /// Add a condition tree. + /// ``` + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// + /// assert_eq!( + /// cake::Entity::find() + /// .filter( + /// Condition::any() + /// .add(cake::Column::Id.eq(4)) + /// .add(cake::Column::Id.eq(5)) + /// ) + /// .build(MysqlQueryBuilder) + /// .to_string(), + /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 OR `cake`.`id` = 5" + /// ); + /// ``` + fn filter(mut self, filter: F) -> Self + where + F: IntoCondition, + { + self.query().cond_where(filter.into_condition()); + self + } + + /// Apply a where condition using the model's primary key + fn belongs_to(mut self, model: &E::Model) -> Self + where + E: EntityTrait, + E::PrimaryKey: PrimaryKeyOfModel, + { + for key in E::PrimaryKey::iter() { + let col = key.into_column(); + self = self.filter(col.eq(model.get(col))); + } + self + } +} + fn join_condition(rel: RelationDef) -> SimpleExpr { let from_tbl = rel.from_tbl.clone(); let to_tbl = rel.to_tbl.clone(); diff --git a/src/query/insert.rs b/src/query/insert.rs index 48208f92..5ee2b696 100644 --- a/src/query/insert.rs +++ b/src/query/insert.rs @@ -71,7 +71,7 @@ impl QueryTrait for Insert where A: ActiveModelTrait, { - type QueryStatementBuilder = InsertStatement; + type QueryStatement = InsertStatement; fn query(&mut self) -> &mut InsertStatement { &mut self.query diff --git a/src/query/join.rs b/src/query/join.rs index f9425394..294707d0 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -1,28 +1,10 @@ -use crate::{ - ColumnTrait, EntityTrait, Iterable, ModelTrait, PrimaryKeyOfModel, Related, Select, - SelectHelper, SelectTwo, -}; +use crate::{EntityTrait, Related, Select, SelectHelper, SelectTwo}; pub use sea_query::JoinType; impl Select where E: EntityTrait, { - /// Apply a where condition using the model's primary key - pub fn belongs_to(self, model: &R::Model) -> Self - where - R: EntityTrait + Related, - R::PrimaryKey: PrimaryKeyOfModel, - { - if let Some(key) = R::PrimaryKey::iter().next() { - // TODO: supporting composite primary key - let col = key.into_column(); - self.filter(col.eq(model.get(col))) - } else { - panic!("undefined primary key"); - } - } - /// Left Join with a Related Entity. pub fn left_join(self, _: R) -> Self where @@ -71,7 +53,7 @@ where #[cfg(test)] mod tests { use crate::tests_cfg::{cake, filling, fruit}; - use crate::{QueryTrait, ColumnTrait, EntityTrait, SelectHelper}; + use crate::{ColumnTrait, EntityTrait, QueryFilter, QueryTrait}; use sea_query::MysqlQueryBuilder; #[test] diff --git a/src/query/select.rs b/src/query/select.rs index c562ca24..15ec6ff8 100644 --- a/src/query/select.rs +++ b/src/query/select.rs @@ -1,4 +1,4 @@ -use crate::{ColumnTrait, EntityTrait, Iterable, QueryTrait, SelectHelper}; +use crate::{ColumnTrait, EntityTrait, Iterable, QueryFilter, QueryTrait, SelectHelper}; use core::fmt::Debug; use core::marker::PhantomData; pub use sea_query::JoinType; @@ -37,6 +37,17 @@ where } } +impl QueryFilter for Select +where + E: EntityTrait, +{ + type QueryStatement = SelectStatement; + + fn query(&mut self) -> &mut SelectStatement { + &mut self.query + } +} + impl SelectHelper for SelectTwo where E: EntityTrait, @@ -47,6 +58,18 @@ where } } +impl QueryFilter for SelectTwo +where + E: EntityTrait, + F: EntityTrait, +{ + type QueryStatement = SelectStatement; + + fn query(&mut self) -> &mut SelectStatement { + &mut self.query + } +} + impl IntoSimpleExpr for C where C: ColumnTrait, @@ -95,7 +118,7 @@ impl QueryTrait for Select where E: EntityTrait, { - type QueryStatementBuilder = SelectStatement; + type QueryStatement = SelectStatement; fn query(&mut self) -> &mut SelectStatement { &mut self.query } @@ -112,7 +135,7 @@ where E: EntityTrait, F: EntityTrait, { - type QueryStatementBuilder = SelectStatement; + type QueryStatement = SelectStatement; fn query(&mut self) -> &mut SelectStatement { &mut self.query } diff --git a/src/query/traits.rs b/src/query/traits.rs index 73b00311..e4e6c77d 100644 --- a/src/query/traits.rs +++ b/src/query/traits.rs @@ -2,16 +2,16 @@ use crate::Statement; use sea_query::{QueryBuilder, QueryStatementBuilder}; pub trait QueryTrait { - type QueryStatementBuilder: QueryStatementBuilder; + type QueryStatement: QueryStatementBuilder; /// Get a mutable ref to the query builder - fn query(&mut self) -> &mut Self::QueryStatementBuilder; + fn query(&mut self) -> &mut Self::QueryStatement; /// Get an immutable ref to the query builder - fn as_query(&self) -> &Self::QueryStatementBuilder; + fn as_query(&self) -> &Self::QueryStatement; /// Take ownership of the query builder - fn into_query(self) -> Self::QueryStatementBuilder; + fn into_query(self) -> Self::QueryStatement; /// Build the query as [`Statement`] fn build(&self, builder: B) -> Statement