blob: 0c0eb849ba9133093ecea939740d29a7e6654126 [file] [log] [blame]
use std::marker::PhantomData;
use crate::backend::Backend;
use crate::dsl::AsExprOf;
use crate::expression::subselect::ValidSubselect;
use crate::expression::*;
use crate::insertable::Insertable;
use crate::query_builder::distinct_clause::DistinctClause;
use crate::query_builder::group_by_clause::GroupByClause;
use crate::query_builder::insert_statement::InsertFromSelect;
use crate::query_builder::limit_clause::LimitClause;
use crate::query_builder::offset_clause::OffsetClause;
use crate::query_builder::order_clause::OrderClause;
use crate::query_builder::where_clause::*;
use crate::query_builder::*;
use crate::query_dsl::methods::*;
use crate::query_dsl::*;
use crate::query_source::joins::*;
use crate::query_source::{QuerySource, Table};
use crate::result::QueryResult;
use crate::sql_types::{BigInt, Bool, NotNull, Nullable};
#[allow(missing_debug_implementations)]
pub struct BoxedSelectStatement<'a, ST, QS, DB> {
select: Box<dyn QueryFragment<DB> + 'a>,
from: QS,
distinct: Box<dyn QueryFragment<DB> + 'a>,
where_clause: BoxedWhereClause<'a, DB>,
order: Option<Box<dyn QueryFragment<DB> + 'a>>,
limit: Box<dyn QueryFragment<DB> + 'a>,
offset: Box<dyn QueryFragment<DB> + 'a>,
group_by: Box<dyn QueryFragment<DB> + 'a>,
_marker: PhantomData<ST>,
}
impl<'a, ST, QS, DB> BoxedSelectStatement<'a, ST, QS, DB> {
#[allow(clippy::too_many_arguments)]
pub fn new(
select: Box<dyn QueryFragment<DB> + 'a>,
from: QS,
distinct: Box<dyn QueryFragment<DB> + 'a>,
where_clause: BoxedWhereClause<'a, DB>,
order: Option<Box<dyn QueryFragment<DB> + 'a>>,
limit: Box<dyn QueryFragment<DB> + 'a>,
offset: Box<dyn QueryFragment<DB> + 'a>,
group_by: Box<dyn QueryFragment<DB> + 'a>,
) -> Self {
BoxedSelectStatement {
select: select,
from: from,
distinct: distinct,
where_clause: where_clause,
order: order,
limit: limit,
offset: offset,
group_by: group_by,
_marker: PhantomData,
}
}
}
impl<'a, ST, QS, DB> Query for BoxedSelectStatement<'a, ST, QS, DB>
where
DB: Backend,
{
type SqlType = ST;
}
impl<'a, ST, QS, DB> SelectQuery for BoxedSelectStatement<'a, ST, QS, DB>
where
DB: Backend,
{
type SqlType = ST;
}
impl<'a, ST, QS, QS2, DB> ValidSubselect<QS2> for BoxedSelectStatement<'a, ST, QS, DB> where
Self: Query<SqlType = ST>
{
}
impl<'a, ST, QS, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, QS, DB>
where
DB: Backend,
QS: QuerySource,
QS::FromClause: QueryFragment<DB>,
{
fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
out.push_sql("SELECT ");
self.distinct.walk_ast(out.reborrow())?;
self.select.walk_ast(out.reborrow())?;
out.push_sql(" FROM ");
self.from.from_clause().walk_ast(out.reborrow())?;
self.where_clause.walk_ast(out.reborrow())?;
self.group_by.walk_ast(out.reborrow())?;
if let Some(ref order) = self.order {
out.push_sql(" ORDER BY ");
order.walk_ast(out.reborrow())?;
}
self.limit.walk_ast(out.reborrow())?;
self.offset.walk_ast(out.reborrow())?;
Ok(())
}
}
impl<'a, ST, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, (), DB>
where
DB: Backend,
{
fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
out.push_sql("SELECT ");
self.distinct.walk_ast(out.reborrow())?;
self.select.walk_ast(out.reborrow())?;
self.where_clause.walk_ast(out.reborrow())?;
self.group_by.walk_ast(out.reborrow())?;
self.order.walk_ast(out.reborrow())?;
self.limit.walk_ast(out.reborrow())?;
self.offset.walk_ast(out.reborrow())?;
Ok(())
}
}
impl<'a, ST, QS, DB> QueryId for BoxedSelectStatement<'a, ST, QS, DB> {
type QueryId = ();
const HAS_STATIC_QUERY_ID: bool = false;
}
impl<'a, ST, QS, DB, Rhs, Kind, On> InternalJoinDsl<Rhs, Kind, On>
for BoxedSelectStatement<'a, ST, QS, DB>
where
BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>: AsQuery,
{
type Output = BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>;
fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
BoxedSelectStatement::new(
self.select,
Join::new(self.from, rhs, kind).on(on),
self.distinct,
self.where_clause,
self.order,
self.limit,
self.offset,
self.group_by,
)
}
}
impl<'a, ST, QS, DB> DistinctDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
DB: Backend,
DistinctClause: QueryFragment<DB>,
{
type Output = Self;
fn distinct(mut self) -> Self::Output {
self.distinct = Box::new(DistinctClause);
self
}
}
impl<'a, ST, QS, DB, Selection> SelectDsl<Selection> for BoxedSelectStatement<'a, ST, QS, DB>
where
DB: Backend,
Selection: SelectableExpression<QS> + QueryFragment<DB> + 'a,
{
type Output = BoxedSelectStatement<'a, Selection::SqlType, QS, DB>;
fn select(self, selection: Selection) -> Self::Output {
BoxedSelectStatement::new(
Box::new(selection),
self.from,
self.distinct,
self.where_clause,
self.order,
self.limit,
self.offset,
self.group_by,
)
}
}
impl<'a, ST, QS, DB, Predicate> FilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
BoxedWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedWhereClause<'a, DB>>,
Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
type Output = Self;
fn filter(mut self, predicate: Predicate) -> Self::Output {
self.where_clause = self.where_clause.and(predicate);
self
}
}
impl<'a, ST, QS, DB, Predicate> OrFilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
BoxedWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedWhereClause<'a, DB>>,
Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
type Output = Self;
fn or_filter(mut self, predicate: Predicate) -> Self::Output {
self.where_clause = self.where_clause.or(predicate);
self
}
}
impl<'a, ST, QS, DB> LimitDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
DB: Backend,
LimitClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
type Output = Self;
fn limit(mut self, limit: i64) -> Self::Output {
self.limit = Box::new(LimitClause(limit.into_sql::<BigInt>()));
self
}
}
impl<'a, ST, QS, DB> OffsetDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
DB: Backend,
OffsetClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
type Output = Self;
fn offset(mut self, offset: i64) -> Self::Output {
self.offset = Box::new(OffsetClause(offset.into_sql::<BigInt>()));
self
}
}
impl<'a, ST, QS, DB, Order> OrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
DB: Backend,
Order: QueryFragment<DB> + AppearsOnTable<QS> + 'a,
{
type Output = Self;
fn order(mut self, order: Order) -> Self::Output {
self.order = OrderClause(order).into();
self
}
}
impl<'a, ST, QS, DB, Order> ThenOrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
DB: Backend + 'a,
Order: QueryFragment<DB> + AppearsOnTable<QS> + 'a,
{
type Output = Self;
fn then_order_by(mut self, order: Order) -> Self::Output {
self.order = match self.order {
Some(old) => Some(Box::new((old, order))),
None => Some(Box::new(order)),
};
self
}
}
impl<'a, ST, QS, DB, Expr> GroupByDsl<Expr> for BoxedSelectStatement<'a, ST, QS, DB>
where
DB: Backend,
Expr: QueryFragment<DB> + AppearsOnTable<QS> + 'a,
Self: Query,
{
type Output = Self;
fn group_by(mut self, group_by: Expr) -> Self::Output {
self.group_by = Box::new(GroupByClause(group_by));
self
}
}
// FIXME: Should we disable joining when `.group_by` has been called? Are there
// any other query methods where a join no longer has the same semantics as
// joining on just the table?
impl<'a, ST, QS, DB, Rhs> JoinTo<Rhs> for BoxedSelectStatement<'a, ST, QS, DB>
where
QS: JoinTo<Rhs>,
{
type FromClause = QS::FromClause;
type OnClause = QS::OnClause;
fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
QS::join_target(rhs)
}
}
impl<'a, ST, QS, DB> QueryDsl for BoxedSelectStatement<'a, ST, QS, DB> {}
impl<'a, ST, QS, DB, Conn> RunQueryDsl<Conn> for BoxedSelectStatement<'a, ST, QS, DB> {}
impl<'a, ST, QS, DB, T> Insertable<T> for BoxedSelectStatement<'a, ST, QS, DB>
where
T: Table,
Self: Query,
{
type Values = InsertFromSelect<Self, T::AllColumns>;
fn values(self) -> Self::Values {
InsertFromSelect::new(self)
}
}
impl<'a, 'b, ST, QS, DB, T> Insertable<T> for &'b BoxedSelectStatement<'a, ST, QS, DB>
where
T: Table,
Self: Query,
{
type Values = InsertFromSelect<Self, T::AllColumns>;
fn values(self) -> Self::Values {
InsertFromSelect::new(self)
}
}
impl<'a, ST, QS, DB> SelectNullableDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
ST: NotNull,
{
type Output = BoxedSelectStatement<'a, Nullable<ST>, QS, DB>;
fn nullable(self) -> Self::Output {
BoxedSelectStatement {
select: self.select,
from: self.from,
distinct: self.distinct,
where_clause: self.where_clause,
order: self.order,
limit: self.limit,
offset: self.offset,
group_by: self.group_by,
_marker: PhantomData,
}
}
}