rorm_sql/
join_table.rs

1use std::borrow::Cow;
2use std::fmt::{Display, Formatter, Write};
3
4use crate::conditional::{BuildCondition, Condition};
5use crate::value::Value;
6use crate::DBImpl;
7
8/**
9Definition of all available Join types
10*/
11#[derive(Copy, Clone, Debug)]
12pub enum JoinType {
13    /// Normal join operation.
14    ///
15    /// Equivalent to INNER JOIN
16    Join,
17    /// Cartesian product of the tables
18    CrossJoin,
19    /// Given:
20    /// T1 LEFT JOIN T2 ON ..
21    ///
22    /// First, an inner join is performed.
23    /// Then, for each row in T1 that does not satisfy the join condition with any row in T2,
24    /// a joined row is added with null values in columns of T2.
25    LeftJoin,
26    /// Given:
27    /// T1 RIGHT JOIN T2 ON ..
28    ///
29    /// First, an inner join is performed.
30    /// Then, for each row in T2 that does not satisfy the join condition with any row in T1,
31    /// a joined row is added with null values in columns of T1.
32    RightJoin,
33    /// Given:
34    /// T1 FULL JOIN T2 ON ..
35    ///
36    /// First, an inner join is performed.
37    /// Then, for each row in T2 that does not satisfy the join condition with any row in T1,
38    /// a joined row is added with null values in columns of T1.
39    /// Also, for each row in T1 that does not satisfy the join condition with any row in T2,
40    /// a joined row is added with null values in columns of T2.
41    FullJoin,
42}
43
44impl Display for JoinType {
45    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
46        match self {
47            JoinType::Join => write!(f, "JOIN"),
48            JoinType::CrossJoin => write!(f, "CROSS JOIN"),
49            JoinType::LeftJoin => write!(f, "LEFT JOIN"),
50            JoinType::RightJoin => write!(f, "RIGHT JOIN"),
51            JoinType::FullJoin => write!(f, "FULL JOIN"),
52        }
53    }
54}
55
56/**
57Trait representing a join table builder.
58 */
59pub trait JoinTable<'post_query> {
60    /**
61    Method to build a join table expression.
62
63    **Parameter**:
64    - `s`: Mutable reference to String to write to.
65    - `lookup`: List of values for bind parameter.
66    */
67    fn build(&self, s: &mut String, lookup: &mut Vec<Value<'post_query>>);
68}
69
70/**
71Data of a JOIN expression.
72*/
73#[derive(Debug, Clone)]
74pub struct JoinTableData<'until_build, 'post_query> {
75    /// Type of the join operation
76    pub join_type: JoinType,
77    /// Name of the join table
78    pub table_name: &'until_build str,
79    /// Alias for the join table
80    pub join_alias: &'until_build str,
81    /// Condition to apply the join on
82    pub join_condition: Cow<'until_build, Condition<'post_query>>,
83}
84
85/**
86Representation of the JOIN expression
87
88Should only be constructed via [DBImpl::join_table].
89*/
90#[derive(Debug, Clone)]
91pub enum JoinTableImpl<'until_build, 'post_query> {
92    /**
93    SQLite representation of a JOIN expression.
94     */
95    #[cfg(feature = "sqlite")]
96    SQLite(JoinTableData<'until_build, 'post_query>),
97    /**
98    MySQL representation of a JOIN expression.
99     */
100    #[cfg(feature = "mysql")]
101    MySQL(JoinTableData<'until_build, 'post_query>),
102    /**
103    Postgres representation of a JOIN expression.
104     */
105    #[cfg(feature = "postgres")]
106    Postgres(JoinTableData<'until_build, 'post_query>),
107}
108
109impl<'post_query> JoinTable<'post_query> for JoinTableImpl<'_, 'post_query> {
110    fn build(&self, s: &mut String, lookup: &mut Vec<Value<'post_query>>) {
111        match self {
112            #[cfg(feature = "sqlite")]
113            JoinTableImpl::SQLite(d) => write!(
114                s,
115                "{} \"{}\" AS {} ON {}",
116                d.join_type,
117                d.table_name,
118                d.join_alias,
119                d.join_condition.build(DBImpl::SQLite, lookup)
120            )
121            .unwrap(),
122            #[cfg(feature = "mysql")]
123            JoinTableImpl::MySQL(d) => write!(
124                s,
125                "{} {} AS {} ON {}",
126                d.join_type,
127                d.table_name,
128                d.join_alias,
129                d.join_condition.build(DBImpl::MySQL, lookup)
130            )
131            .unwrap(),
132            #[cfg(feature = "postgres")]
133            JoinTableImpl::Postgres(d) => write!(
134                s,
135                "{} \"{}\" AS {} ON {}",
136                d.join_type,
137                d.table_name,
138                d.join_alias,
139                d.join_condition.build(DBImpl::Postgres, lookup)
140            )
141            .unwrap(),
142        }
143    }
144}