Add select APIs

This commit is contained in:
Chris Tsang 2021-05-11 02:05:05 +08:00
parent 5667eb06e9
commit dde85d83bd
3 changed files with 118 additions and 22 deletions

View File

@ -104,22 +104,12 @@ async fn count_fruits_by_cake(db: &Database) -> Result<(), QueryErr> {
print!("count fruits by cake: "); print!("count fruits by cake: ");
let mut select = cake::Entity::find().left_join(cake::Relation::Fruit); let select = cake::Entity::find()
{ .left_join(cake::Relation::Fruit)
use sea_orm::sea_query::*; .clear_selects()
type Cake = cake::Column; .column(cake::Column::Name)
type Fruit = fruit::Column; .expr_as(fruit::Column::Id.count(), "num_of_fruits")
.group_by(cake::Column::Name);
select
.query()
.clear_selects()
.column((cake::Entity, Cake::Name))
.expr_as(
Expr::tbl(fruit::Entity, Fruit::Id).count(),
Alias::new("num_of_fruits"),
)
.group_by_col((cake::Entity, Cake::Name));
}
let results = select.into_model::<SelectResult>().all(db).await?; let results = select.into_model::<SelectResult>().all(db).await?;

View File

@ -15,6 +15,27 @@ macro_rules! bind_oper {
}; };
} }
macro_rules! bind_agg_func {
( $func: ident ) => {
fn $func(&self) -> SimpleExpr {
Expr::tbl(self.entity_name(), *self).$func()
}
};
}
macro_rules! bind_vec_func {
( $func: ident ) => {
#[allow(clippy::wrong_self_convention)]
fn $func<V, I>(&self, v: I) -> SimpleExpr
where
V: Into<Value>,
I: IntoIterator<Item = V>,
{
Expr::tbl(self.entity_name(), *self).$func(v)
}
};
}
pub trait ColumnTrait: IdenStatic { pub trait ColumnTrait: IdenStatic {
type EntityName: EntityName; type EntityName: EntityName;
@ -24,6 +45,10 @@ pub trait ColumnTrait: IdenStatic {
Rc::new(Self::EntityName::default()) as Rc<dyn Iden> Rc::new(Self::EntityName::default()) as Rc<dyn Iden>
} }
fn as_column_ref(&self) -> (Rc<dyn Iden>, Rc<dyn Iden>) {
(self.entity_name(), Rc::new(*self) as Rc<dyn Iden>)
}
bind_oper!(eq); bind_oper!(eq);
bind_oper!(ne); bind_oper!(ne);
bind_oper!(gt); bind_oper!(gt);
@ -144,4 +169,19 @@ pub trait ColumnTrait: IdenStatic {
let pattern = format!("%{}%", s); let pattern = format!("%{}%", s);
Expr::tbl(self.entity_name(), *self).like(&pattern) Expr::tbl(self.entity_name(), *self).like(&pattern)
} }
}
bind_agg_func!(max);
bind_agg_func!(min);
bind_agg_func!(sum);
bind_agg_func!(count);
fn if_null<V>(&self, v: V) -> SimpleExpr
where
V: Into<Value>,
{
Expr::tbl(self.entity_name(), *self).if_null(v)
}
bind_vec_func!(is_in);
bind_vec_func!(is_not_in);
}

View File

@ -1,11 +1,13 @@
use crate::{ use crate::{
EntityTrait, Identity, Iterable, PrimaryKeyOfModel, Related, RelationDef, RelationTrait, ColumnTrait, EntityTrait, Identity, Iterable, ModelTrait, PrimaryKeyOfModel, Related,
Statement, RelationDef, RelationTrait, Statement,
}; };
use core::fmt::Debug; use core::fmt::Debug;
use core::marker::PhantomData; use core::marker::PhantomData;
pub use sea_query::JoinType; pub use sea_query::JoinType;
use sea_query::{Expr, Iden, IntoIden, Order, QueryBuilder, SelectStatement, SimpleExpr}; use sea_query::{
Alias, Expr, Iden, IntoIden, Order, QueryBuilder, SelectExpr, SelectStatement, SimpleExpr,
};
use std::rc::Rc; use std::rc::Rc;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -74,6 +76,72 @@ where
self self
} }
pub fn clear_selects(mut self) -> Self {
self.query.clear_selects();
self
}
/// ```
/// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::PostgresQueryBuilder};
///
/// assert_eq!(
/// cake::Entity::find()
/// .clear_selects()
/// .column(cake::Column::Name)
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// r#"SELECT "cake"."name" FROM "cake""#
/// );
/// ```
pub fn column<C>(mut self, col: C) -> Self
where
C: ColumnTrait,
{
self.query.column(col.as_column_ref());
self
}
/// ```
/// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::PostgresQueryBuilder};
///
/// assert_eq!(
/// cake::Entity::find()
/// .clear_selects()
/// .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<C>(mut self, col: C) -> Self
where
C: ColumnTrait,
{
self.query.group_by_col(col.as_column_ref());
self
}
/// ```
/// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::PostgresQueryBuilder};
///
/// assert_eq!(
/// cake::Entity::find()
/// .clear_selects()
/// .expr_as(cake::Column::Id.count(), "count")
/// .build(PostgresQueryBuilder)
/// .to_string(),
/// r#"SELECT COUNT("cake"."id") AS "count" FROM "cake""#
/// );
/// ```
pub fn expr_as(mut self, expr: SimpleExpr, alias: &str) -> Self {
self.query.expr(SelectExpr {
expr,
alias: Some(Rc::new(Alias::new(alias))),
});
self
}
/// ``` /// ```
/// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder}; /// use sea_orm::{ColumnTrait, EntityTrait, tests_cfg::cake, sea_query::MysqlQueryBuilder};
/// ///
@ -95,8 +163,6 @@ where
R: EntityTrait + Related<E>, R: EntityTrait + Related<E>,
R::PrimaryKey: PrimaryKeyOfModel<R::Model>, R::PrimaryKey: PrimaryKeyOfModel<R::Model>,
{ {
use crate::{ColumnTrait, ModelTrait};
if let Some(key) = R::PrimaryKey::iter().next() { if let Some(key) = R::PrimaryKey::iter().next() {
// TODO: supporting composite primary key // TODO: supporting composite primary key
let col = key.into_column(); let col = key.into_column();