use crate::{
backend::QueryBuilder,
expr::*,
prepare::*,
query::{condition::*, OrderedStatement},
types::*,
value::*,
QueryStatementBuilder,
};
use std::iter::FromIterator;
use std::rc::Rc;
#[derive(Debug, Clone)]
pub struct SelectStatement {
pub(crate) distinct: Option<SelectDistinct>,
pub(crate) selects: Vec<SelectExpr>,
pub(crate) from: Option<Box<TableRef>>,
pub(crate) join: Vec<JoinExpr>,
pub(crate) wherei: ConditionHolder,
pub(crate) groups: Vec<SimpleExpr>,
pub(crate) having: ConditionHolder,
pub(crate) orders: Vec<OrderExpr>,
pub(crate) limit: Option<Value>,
pub(crate) offset: Option<Value>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SelectDistinct {
All,
Distinct,
DistinctRow,
}
#[derive(Debug, Clone)]
pub struct SelectExpr {
pub expr: SimpleExpr,
pub alias: Option<Rc<dyn Iden>>,
}
#[derive(Debug, Clone)]
pub struct JoinExpr {
pub join: JoinType,
pub table: Box<TableRef>,
pub on: Option<JoinOn>,
}
impl Into<SelectExpr> for SimpleExpr {
fn into(self) -> SelectExpr {
SelectExpr {
expr: self,
alias: None,
}
}
}
impl Default for SelectStatement {
fn default() -> Self {
Self::new()
}
}
impl SelectStatement {
pub fn new() -> Self {
Self {
distinct: None,
selects: Vec::new(),
from: None,
join: Vec::new(),
wherei: ConditionHolder::new(),
groups: Vec::new(),
having: ConditionHolder::new(),
orders: Vec::new(),
limit: None,
offset: None,
}
}
pub fn take(&mut self) -> Self {
Self {
distinct: self.distinct.take(),
selects: std::mem::replace(&mut self.selects, Vec::new()),
from: self.from.take(),
join: std::mem::replace(&mut self.join, Vec::new()),
wherei: std::mem::replace(&mut self.wherei, ConditionHolder::new()),
groups: std::mem::replace(&mut self.groups, Vec::new()),
having: std::mem::replace(&mut self.having, ConditionHolder::new()),
orders: std::mem::replace(&mut self.orders, Vec::new()),
limit: self.limit.take(),
offset: self.offset.take(),
}
}
pub fn conditions<T, F>(&mut self, b: bool, if_true: T, if_false: F) -> &mut Self
where
T: FnOnce(&mut Self),
F: FnOnce(&mut Self),
{
if b {
if_true(self)
} else {
if_false(self)
}
self
}
pub fn clear_selects(&mut self) -> &mut Self {
self.selects = Vec::new();
self
}
pub fn expr<T>(&mut self, expr: T) -> &mut Self
where
T: Into<SelectExpr>,
{
self.selects.push(expr.into());
self
}
pub fn exprs<T, I>(&mut self, exprs: I) -> &mut Self
where
T: Into<SelectExpr>,
I: IntoIterator<Item = T>,
{
self.selects
.append(&mut exprs.into_iter().map(|c| c.into()).collect());
self
}
pub fn exprs_mut_for_each<F>(&mut self, func: F)
where
F: FnMut(&mut SelectExpr),
{
self.selects.iter_mut().for_each(func);
}
pub fn distinct(&mut self) -> &mut Self {
self.distinct = Some(SelectDistinct::Distinct);
self
}
pub fn column<C>(&mut self, col: C) -> &mut Self
where
C: IntoColumnRef,
{
self.expr(SimpleExpr::Column(col.into_column_ref()))
}
#[deprecated(
since = "0.9.0",
note = "Please use the [`SelectStatement::column`] with a tuple as [`ColumnRef`]"
)]
pub fn table_column<T, C>(&mut self, t: T, c: C) -> &mut Self
where
T: IntoIden,
C: IntoIden,
{
self.column((t.into_iden(), c.into_iden()))
}
pub fn columns<T, I>(&mut self, cols: I) -> &mut Self
where
T: IntoColumnRef,
I: IntoIterator<Item = T>,
{
self.exprs(
cols.into_iter()
.map(|c| SimpleExpr::Column(c.into_column_ref()))
.collect::<Vec<SimpleExpr>>(),
)
}
#[deprecated(
since = "0.9.0",
note = "Please use the [`SelectStatement::columns`] with a tuple as [`ColumnRef`]"
)]
pub fn table_columns<T, C>(&mut self, cols: Vec<(T, C)>) -> &mut Self
where
T: IntoIden,
C: IntoIden,
{
self.columns(
cols.into_iter()
.map(|(t, c)| (t.into_iden(), c.into_iden()))
.collect::<Vec<_>>(),
)
}
pub fn expr_as<T, A>(&mut self, expr: T, alias: A) -> &mut Self
where
T: Into<SimpleExpr>,
A: IntoIden,
{
self.expr(SelectExpr {
expr: expr.into(),
alias: Some(alias.into_iden()),
});
self
}
#[deprecated(
since = "0.6.1",
note = "Please use the [`SelectStatement::expr_as`] instead"
)]
pub fn expr_alias<T, A>(&mut self, expr: T, alias: A) -> &mut Self
where
T: Into<SimpleExpr>,
A: IntoIden,
{
self.expr_as(expr, alias)
}
pub fn from<R>(&mut self, tbl_ref: R) -> &mut Self
where
R: IntoTableRef,
{
self.from_from(tbl_ref.into_table_ref())
}
#[deprecated(
since = "0.9.0",
note = "Please use the [`SelectStatement::from`] with a tuple as [`TableRef`]"
)]
pub fn from_schema<S: 'static, T: 'static>(&mut self, schema: S, table: T) -> &mut Self
where
S: IntoIden,
T: IntoIden,
{
self.from((schema, table))
}
pub fn from_as<R, A>(&mut self, tbl_ref: R, alias: A) -> &mut Self
where
R: IntoTableRef,
A: IntoIden,
{
self.from_from(tbl_ref.into_table_ref().alias(alias.into_iden()))
}
#[deprecated(
since = "0.6.1",
note = "Please use the [`SelectStatement::from_as`] instead"
)]
pub fn from_alias<R, A>(&mut self, tbl_ref: R, alias: A) -> &mut Self
where
R: IntoTableRef,
A: IntoIden,
{
self.from_as(tbl_ref, alias)
}
#[deprecated(
since = "0.9.0",
note = "Please use the [`SelectStatement::from_as`] with a tuple as [`TableRef`]"
)]
pub fn from_schema_as<S: 'static, T: 'static, A>(
&mut self,
schema: S,
table: T,
alias: A,
) -> &mut Self
where
S: IntoIden,
T: IntoIden,
A: IntoIden,
{
self.from_as((schema, table), alias)
}
pub fn from_subquery<T>(&mut self, query: SelectStatement, alias: T) -> &mut Self
where
T: IntoIden,
{
self.from_from(TableRef::SubQuery(query, alias.into_iden()))
}
fn from_from(&mut self, select: TableRef) -> &mut Self {
self.from = Some(Box::new(select));
self
}
pub fn left_join<R>(&mut self, tbl_ref: R, condition: SimpleExpr) -> &mut Self
where
R: IntoTableRef,
{
self.join(JoinType::LeftJoin, tbl_ref, condition)
}
pub fn inner_join<R>(&mut self, tbl_ref: R, condition: SimpleExpr) -> &mut Self
where
R: IntoTableRef,
{
self.join(JoinType::InnerJoin, tbl_ref, condition)
}
pub fn join<R>(&mut self, join: JoinType, tbl_ref: R, condition: SimpleExpr) -> &mut Self
where
R: IntoTableRef,
{
self.join_join(
join,
tbl_ref.into_table_ref(),
JoinOn::Condition(Box::new(condition)),
)
}
pub fn join_as<R, A>(
&mut self,
join: JoinType,
tbl_ref: R,
alias: A,
condition: SimpleExpr,
) -> &mut Self
where
R: IntoTableRef,
A: IntoIden,
{
self.join_join(
join,
tbl_ref.into_table_ref().alias(alias.into_iden()),
JoinOn::Condition(Box::new(condition)),
)
}
#[deprecated(
since = "0.6.1",
note = "Please use the [`SelectStatement::join_as`] instead"
)]
pub fn join_alias<R, A>(
&mut self,
join: JoinType,
tbl_ref: R,
alias: A,
condition: SimpleExpr,
) -> &mut Self
where
R: IntoTableRef,
A: IntoIden,
{
self.join_as(join, tbl_ref, alias, condition)
}
pub fn join_subquery<T>(
&mut self,
join: JoinType,
query: SelectStatement,
alias: T,
condition: SimpleExpr,
) -> &mut Self
where
T: IntoIden,
{
self.join_join(
join,
TableRef::SubQuery(query, alias.into_iden()),
JoinOn::Condition(Box::new(condition)),
)
}
fn join_join(&mut self, join: JoinType, table: TableRef, on: JoinOn) -> &mut Self {
self.join.push(JoinExpr {
join,
table: Box::new(table),
on: Some(on),
});
self
}
pub fn group_by_columns<T, I>(&mut self, cols: I) -> &mut Self
where
T: IntoColumnRef,
I: IntoIterator<Item = T>,
{
self.add_group_by(
cols.into_iter()
.map(|c| SimpleExpr::Column(c.into_column_ref()))
.collect::<Vec<_>>(),
)
}
pub fn group_by_col<T>(&mut self, col: T) -> &mut Self
where
T: IntoColumnRef,
{
self.group_by_columns(vec![col])
}
#[deprecated(
since = "0.9.0",
note = "Please use the [`SelectStatement::group_by_columns`] with a tuple as [`ColumnRef`]"
)]
pub fn group_by_table_columns<T, C>(&mut self, cols: Vec<(T, C)>) -> &mut Self
where
T: IntoIden,
C: IntoIden,
{
self.group_by_columns(
cols.into_iter()
.map(|(t, c)| (t.into_iden(), c.into_iden()))
.collect::<Vec<_>>(),
)
}
pub fn add_group_by<I>(&mut self, expr: I) -> &mut Self
where
I: IntoIterator<Item = SimpleExpr>,
{
self.groups.append(&mut Vec::from_iter(expr.into_iter()));
self
}
pub fn cond_having(&mut self, condition: Condition) -> &mut Self {
self.having.add_condition(condition);
self
}
pub fn and_having(&mut self, other: SimpleExpr) -> &mut Self {
self.having.add_and_or(LogicalChainOper::And(other));
self
}
#[deprecated(
since = "0.11.0",
note = "Please use [`SelectStatement::cond_having`] or only [`SelectStatement::and_having`]. The evaluation of mixed `and_having` and `or_having` can be surprising."
)]
pub fn or_having(&mut self, other: SimpleExpr) -> &mut Self {
self.having.add_and_or(LogicalChainOper::Or(other));
self
}
pub fn limit(&mut self, limit: u64) -> &mut Self {
self.limit = Some(Value::BigUnsigned(limit));
self
}
pub fn offset(&mut self, offset: u64) -> &mut Self {
self.offset = Some(Value::BigUnsigned(offset));
self
}
}
impl QueryStatementBuilder for SelectStatement {
fn build_collect<T: QueryBuilder>(
&self,
query_builder: T,
collector: &mut dyn FnMut(Value),
) -> String {
let mut sql = SqlWriter::new();
query_builder.prepare_select_statement(self, &mut sql, collector);
sql.result()
}
fn build_collect_any(
&self,
query_builder: &dyn QueryBuilder,
collector: &mut dyn FnMut(Value),
) -> String {
let mut sql = SqlWriter::new();
query_builder.prepare_select_statement(self, &mut sql, collector);
sql.result()
}
}
impl OrderedStatement for SelectStatement {
fn add_order_by(&mut self, order: OrderExpr) -> &mut Self {
self.orders.push(order);
self
}
}
impl ConditionalStatement for SelectStatement {
fn and_or_where(&mut self, condition: LogicalChainOper) -> &mut Self {
self.wherei.add_and_or(condition);
self
}
fn cond_where<C>(&mut self, condition: C) -> &mut Self
where
C: IntoCondition,
{
self.wherei.add_condition(condition.into_condition());
self
}
}