use super::{AppearsInFromClause, Plus, QuerySource};
use backend::Backend;
use expression::grouped::Grouped;
use expression::nullable::Nullable;
use expression::SelectableExpression;
use prelude::*;
use query_builder::*;
use result::QueryResult;
use sql_types::Bool;
use util::TupleAppend;
#[derive(Debug, Clone, Copy, QueryId)]
pub struct Join<Left, Right, Kind> {
left: Left,
right: Right,
kind: Kind,
}
#[derive(Debug, Clone, Copy, QueryId)]
#[doc(hidden)]
pub struct JoinOn<Join, On> {
join: Join,
on: On,
}
impl<Left, Right, Kind> Join<Left, Right, Kind> {
pub fn new(left: Left, right: Right, kind: Kind) -> Self {
Join {
left: left,
right: right,
kind: kind,
}
}
#[doc(hidden)]
pub fn on<On>(self, on: On) -> JoinOn<Self, On> {
JoinOn { join: self, on: on }
}
}
impl<Left, Right> QuerySource for Join<Left, Right, Inner>
where
Left: QuerySource + AppendSelection<Right::DefaultSelection>,
Right: QuerySource,
Left::Output: SelectableExpression<Self>,
Self: Clone,
{
type FromClause = Self;
type DefaultSelection = Left::Output;
fn from_clause(&self) -> Self::FromClause {
self.clone()
}
fn default_selection(&self) -> Self::DefaultSelection {
self.left.append_selection(self.right.default_selection())
}
}
impl<Left, Right> QuerySource for Join<Left, Right, LeftOuter>
where
Left: QuerySource + AppendSelection<Nullable<Right::DefaultSelection>>,
Right: QuerySource,
Left::Output: SelectableExpression<Self>,
Self: Clone,
{
type FromClause = Self;
type DefaultSelection = Left::Output;
fn from_clause(&self) -> Self::FromClause {
self.clone()
}
fn default_selection(&self) -> Self::DefaultSelection {
self.left
.append_selection(self.right.default_selection().nullable())
}
}
impl<Join, On> QuerySource for JoinOn<Join, On>
where
Join: QuerySource,
On: AppearsOnTable<Join::FromClause, SqlType = Bool> + Clone,
Join::DefaultSelection: SelectableExpression<Self>,
{
type FromClause = Grouped<nodes::InfixNode<'static, Join::FromClause, On>>;
type DefaultSelection = Join::DefaultSelection;
fn from_clause(&self) -> Self::FromClause {
Grouped(nodes::InfixNode::new(
self.join.from_clause(),
self.on.clone(),
" ON ",
))
}
fn default_selection(&self) -> Self::DefaultSelection {
self.join.default_selection()
}
}
impl<Left, Right, Kind, DB> QueryFragment<DB> for Join<Left, Right, Kind>
where
DB: Backend,
Left: QuerySource,
Left::FromClause: QueryFragment<DB>,
Right: QuerySource,
Right::FromClause: QueryFragment<DB>,
Kind: QueryFragment<DB>,
{
fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
self.left.from_clause().walk_ast(out.reborrow())?;
self.kind.walk_ast(out.reborrow())?;
out.push_sql(" JOIN ");
self.right.from_clause().walk_ast(out.reborrow())?;
Ok(())
}
}
impl<Left, Right, Kind, T> SelectableExpression<Join<Left, Right, Kind>> for Nullable<T>
where
T: SelectableExpression<Join<Left, Right, Inner>>,
Nullable<T>: AppearsOnTable<Join<Left, Right, Kind>>,
{
}
impl<Join, On, T> SelectableExpression<JoinOn<Join, On>> for Nullable<T>
where
Nullable<T>: SelectableExpression<Join>,
Nullable<T>: AppearsOnTable<JoinOn<Join, On>>,
{
}
impl<From, T> SelectableExpression<SelectStatement<From>> for Nullable<T>
where
Nullable<T>: SelectableExpression<From>,
Nullable<T>: AppearsOnTable<SelectStatement<From>>,
{
}
pub trait JoinTo<T> {
#[doc(hidden)]
type FromClause;
#[doc(hidden)]
type OnClause;
#[doc(hidden)]
fn join_target(rhs: T) -> (Self::FromClause, Self::OnClause);
}
#[doc(hidden)]
pub trait AppendSelection<Selection> {
type Output;
fn append_selection(&self, selection: Selection) -> Self::Output;
}
impl<T: Table, Selection> AppendSelection<Selection> for T {
type Output = (T::AllColumns, Selection);
fn append_selection(&self, selection: Selection) -> Self::Output {
(T::all_columns(), selection)
}
}
impl<Left, Mid, Selection, Kind> AppendSelection<Selection> for Join<Left, Mid, Kind>
where
Self: QuerySource,
<Self as QuerySource>::DefaultSelection: TupleAppend<Selection>,
{
type Output = <<Self as QuerySource>::DefaultSelection as TupleAppend<Selection>>::Output;
fn append_selection(&self, selection: Selection) -> Self::Output {
self.default_selection().tuple_append(selection)
}
}
impl<Join, On, Selection> AppendSelection<Selection> for JoinOn<Join, On>
where
Join: AppendSelection<Selection>,
{
type Output = Join::Output;
fn append_selection(&self, selection: Selection) -> Self::Output {
self.join.append_selection(selection)
}
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy, Default, QueryId)]
pub struct Inner;
impl<DB: Backend> QueryFragment<DB> for Inner {
fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
out.push_sql(" INNER");
Ok(())
}
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy, Default, QueryId)]
pub struct LeftOuter;
impl<DB: Backend> QueryFragment<DB> for LeftOuter {
fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
out.push_sql(" LEFT OUTER");
Ok(())
}
}
impl<Left, Mid, Right, Kind> JoinTo<Right> for Join<Left, Mid, Kind>
where
Left: JoinTo<Right>,
{
type FromClause = Left::FromClause;
type OnClause = Left::OnClause;
fn join_target(rhs: Right) -> (Self::FromClause, Self::OnClause) {
Left::join_target(rhs)
}
}
impl<Join, On, Right> JoinTo<Right> for JoinOn<Join, On>
where
Join: JoinTo<Right>,
{
type FromClause = Join::FromClause;
type OnClause = Join::OnClause;
fn join_target(rhs: Right) -> (Self::FromClause, Self::OnClause) {
Join::join_target(rhs)
}
}
impl<T, Left, Right, Kind> AppearsInFromClause<T> for Join<Left, Right, Kind>
where
Left: AppearsInFromClause<T>,
Right: AppearsInFromClause<T>,
Left::Count: Plus<Right::Count>,
{
type Count = <Left::Count as Plus<Right::Count>>::Output;
}
impl<T, Join, On> AppearsInFromClause<T> for JoinOn<Join, On>
where
Join: AppearsInFromClause<T>,
{
type Count = Join::Count;
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct OnClauseWrapper<Source, On> {
source: Source,
on: On,
}
impl<Source, On> OnClauseWrapper<Source, On> {
pub fn new(source: Source, on: On) -> Self {
OnClauseWrapper { source, on }
}
}
impl<Lhs, Rhs, On> JoinTo<OnClauseWrapper<Rhs, On>> for Lhs
where
Lhs: Table,
{
type FromClause = Rhs;
type OnClause = On;
fn join_target(rhs: OnClauseWrapper<Rhs, On>) -> (Self::FromClause, Self::OnClause) {
(rhs.source, rhs.on)
}
}