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