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 Postgres representation of a JOIN expression.
99 */
100 #[cfg(feature = "postgres")]
101 Postgres(JoinTableData<'until_build, 'post_query>),
102}
103
104impl<'post_query> JoinTable<'post_query> for JoinTableImpl<'_, 'post_query> {
105 fn build(&self, s: &mut String, lookup: &mut Vec<Value<'post_query>>) {
106 match self {
107 #[cfg(feature = "sqlite")]
108 JoinTableImpl::SQLite(d) => write!(
109 s,
110 "{} \"{}\" AS {} ON {}",
111 d.join_type,
112 d.table_name,
113 d.join_alias,
114 d.join_condition.build(DBImpl::SQLite, lookup)
115 )
116 .unwrap(),
117 #[cfg(feature = "postgres")]
118 JoinTableImpl::Postgres(d) => write!(
119 s,
120 "{} \"{}\" AS {} ON {}",
121 d.join_type,
122 d.table_name,
123 d.join_alias,
124 d.join_condition.build(DBImpl::Postgres, lookup)
125 )
126 .unwrap(),
127 }
128 }
129}