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}