use crate::{SQL, ToSQL, traits::SQLParam};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum JoinType {
#[default]
Join,
Inner,
Left,
Right,
Full,
Cross,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct Join {
pub natural: bool,
pub join_type: JoinType,
pub outer: bool, }
impl Join {
pub const fn new() -> Self {
Self {
natural: false,
join_type: JoinType::Join,
outer: false,
}
}
pub const fn natural(mut self) -> Self {
self.natural = true;
self
}
pub const fn inner(mut self) -> Self {
self.join_type = JoinType::Inner;
self
}
pub const fn left(mut self) -> Self {
self.join_type = JoinType::Left;
self
}
pub const fn right(mut self) -> Self {
self.join_type = JoinType::Right;
self
}
pub const fn full(mut self) -> Self {
self.join_type = JoinType::Full;
self
}
pub const fn cross(mut self) -> Self {
self.join_type = JoinType::Cross;
self
}
pub const fn outer(mut self) -> Self {
self.outer = true;
self
}
}
impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for Join {
fn to_sql(&self) -> SQL<'a, V> {
let join_str = match (self.natural, self.join_type, self.outer) {
(true, JoinType::Join, _) => "NATURAL JOIN",
(true, JoinType::Inner, _) => "NATURAL INNER JOIN",
(true, JoinType::Left, false) => "NATURAL LEFT JOIN",
(true, JoinType::Left, true) => "NATURAL LEFT OUTER JOIN",
(true, JoinType::Right, false) => "NATURAL RIGHT JOIN",
(true, JoinType::Right, true) => "NATURAL RIGHT OUTER JOIN",
(true, JoinType::Full, false) => "NATURAL FULL JOIN",
(true, JoinType::Full, true) => "NATURAL FULL OUTER JOIN",
(true, JoinType::Cross, _) => "NATURAL CROSS JOIN",
(false, JoinType::Join, _) => "JOIN",
(false, JoinType::Inner, _) => "INNER JOIN",
(false, JoinType::Left, false) => "LEFT JOIN",
(false, JoinType::Left, true) => "LEFT OUTER JOIN",
(false, JoinType::Right, false) => "RIGHT JOIN",
(false, JoinType::Right, true) => "RIGHT OUTER JOIN",
(false, JoinType::Full, false) => "FULL JOIN",
(false, JoinType::Full, true) => "FULL OUTER JOIN",
(false, JoinType::Cross, _) => "CROSS JOIN",
};
SQL::raw(join_str)
}
}
#[macro_export]
macro_rules! impl_join_helpers {
(
table_trait: $TableTrait:path,
condition_trait: $ConditionTrait:path,
sql_type: $SQLType:ty $(,)?
) => {
fn join_internal<'a, Table>(
table: Table,
join: $crate::Join,
condition: impl $ConditionTrait,
) -> $SQLType
where
Table: $TableTrait,
{
use $crate::ToSQL;
join.to_sql()
.append(&table)
.push($crate::Token::ON)
.append(&condition)
}
pub fn natural_join<'a, Table>(table: Table, condition: impl $ConditionTrait) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().natural(), condition)
}
pub fn join<'a, Table>(table: Table, condition: impl $ConditionTrait) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new(), condition)
}
pub fn natural_left_join<'a, Table>(
table: Table,
condition: impl $ConditionTrait,
) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().natural().left(), condition)
}
pub fn left_join<'a, Table>(table: Table, condition: impl $ConditionTrait) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().left(), condition)
}
pub fn left_outer_join<'a, Table>(table: Table, condition: impl $ConditionTrait) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().left().outer(), condition)
}
pub fn natural_left_outer_join<'a, Table>(
table: Table,
condition: impl $ConditionTrait,
) -> $SQLType
where
Table: $TableTrait,
{
join_internal(
table,
$crate::Join::new().natural().left().outer(),
condition,
)
}
pub fn natural_right_join<'a, Table>(
table: Table,
condition: impl $ConditionTrait,
) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().natural().right(), condition)
}
pub fn right_join<'a, Table>(table: Table, condition: impl $ConditionTrait) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().right(), condition)
}
pub fn right_outer_join<'a, Table>(
table: Table,
condition: impl $ConditionTrait,
) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().right().outer(), condition)
}
pub fn natural_right_outer_join<'a, Table>(
table: Table,
condition: impl $ConditionTrait,
) -> $SQLType
where
Table: $TableTrait,
{
join_internal(
table,
$crate::Join::new().natural().right().outer(),
condition,
)
}
pub fn natural_full_join<'a, Table>(
table: Table,
condition: impl $ConditionTrait,
) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().natural().full(), condition)
}
pub fn full_join<'a, Table>(table: Table, condition: impl $ConditionTrait) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().full(), condition)
}
pub fn full_outer_join<'a, Table>(table: Table, condition: impl $ConditionTrait) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().full().outer(), condition)
}
pub fn natural_full_outer_join<'a, Table>(
table: Table,
condition: impl $ConditionTrait,
) -> $SQLType
where
Table: $TableTrait,
{
join_internal(
table,
$crate::Join::new().natural().full().outer(),
condition,
)
}
pub fn natural_inner_join<'a, Table>(
table: Table,
condition: impl $ConditionTrait,
) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().natural().inner(), condition)
}
pub fn inner_join<'a, Table>(table: Table, condition: impl $ConditionTrait) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().inner(), condition)
}
pub fn cross_join<'a, Table>(table: Table, condition: impl $ConditionTrait) -> $SQLType
where
Table: $TableTrait,
{
join_internal(table, $crate::Join::new().cross(), condition)
}
};
}