1use super::{Entity, ModelColumn, Schema, query::QueryExt};
2use zino_core::model::Query;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
6pub(super) enum JoinType {
7 #[default]
9 Default,
10 Inner,
12 Left,
14 Right,
16 Full,
18 Cross,
20}
21
22impl JoinType {
23 #[inline]
25 pub(super) fn as_str(&self) -> &'static str {
26 match self {
27 JoinType::Default => "JOIN",
28 JoinType::Inner => "INNER JOIN",
29 JoinType::Left => "LEFT JOIN",
30 JoinType::Right => "RIGHT JOIN",
31 JoinType::Full => "FULL JOIN",
32 JoinType::Cross => "CROSS JOIN",
33 }
34 }
35}
36
37#[derive(Debug, Clone)]
64pub struct JoinOn {
65 join_type: JoinType,
67 join_table: String,
69 conditions: Vec<String>,
71}
72
73impl JoinOn {
74 #[inline]
76 pub fn new<M: Schema>() -> Self {
77 Self {
78 join_type: JoinType::default(),
79 join_table: Self::format_join_table::<M>(),
80 conditions: Vec::new(),
81 }
82 }
83
84 #[inline]
86 pub fn inner_join<M: Schema>() -> Self {
87 Self {
88 join_type: JoinType::Inner,
89 join_table: Self::format_join_table::<M>(),
90 conditions: Vec::new(),
91 }
92 }
93
94 #[inline]
96 pub fn left_join<M: Schema>() -> Self {
97 Self {
98 join_type: JoinType::Left,
99 join_table: Self::format_join_table::<M>(),
100 conditions: Vec::new(),
101 }
102 }
103
104 #[inline]
106 pub fn right_join<M: Schema>() -> Self {
107 Self {
108 join_type: JoinType::Right,
109 join_table: Self::format_join_table::<M>(),
110 conditions: Vec::new(),
111 }
112 }
113
114 #[inline]
116 pub fn full_join<M: Schema>() -> Self {
117 Self {
118 join_type: JoinType::Full,
119 join_table: Self::format_join_table::<M>(),
120 conditions: Vec::new(),
121 }
122 }
123
124 #[inline]
126 pub fn cross_join<M: Schema>() -> Self {
127 Self {
128 join_type: JoinType::Cross,
129 join_table: Self::format_join_table::<M>(),
130 conditions: Vec::new(),
131 }
132 }
133
134 #[inline]
136 pub fn eq<E1, E2, C1, C2>(self, left_col: C1, right_col: C2) -> Self
137 where
138 E1: Entity,
139 E2: Entity,
140 C1: ModelColumn<E1>,
141 C2: ModelColumn<E2>,
142 {
143 self.push_op::<E1, E2, C1, C2>(left_col, "=", right_col)
144 }
145
146 #[inline]
148 pub fn ne<E1, E2, C1, C2>(self, left_col: C1, right_col: C2) -> Self
149 where
150 E1: Entity,
151 E2: Entity,
152 C1: ModelColumn<E1>,
153 C2: ModelColumn<E2>,
154 {
155 self.push_op::<E1, E2, C1, C2>(left_col, "<>", right_col)
156 }
157
158 #[inline]
160 pub fn lt<E1, E2, C1, C2>(self, left_col: C1, right_col: C2) -> Self
161 where
162 E1: Entity,
163 E2: Entity,
164 C1: ModelColumn<E1>,
165 C2: ModelColumn<E2>,
166 {
167 self.push_op::<E1, E2, C1, C2>(left_col, "<", right_col)
168 }
169
170 #[inline]
172 pub fn le<E1, E2, C1, C2>(self, left_col: C1, right_col: C2) -> Self
173 where
174 E1: Entity,
175 E2: Entity,
176 C1: ModelColumn<E1>,
177 C2: ModelColumn<E2>,
178 {
179 self.push_op::<E1, E2, C1, C2>(left_col, "<=", right_col)
180 }
181
182 #[inline]
184 pub fn gt<E1, E2, C1, C2>(self, left_col: C1, right_col: C2) -> Self
185 where
186 E1: Entity,
187 E2: Entity,
188 C1: ModelColumn<E1>,
189 C2: ModelColumn<E2>,
190 {
191 self.push_op::<E1, E2, C1, C2>(left_col, ">", right_col)
192 }
193
194 #[inline]
196 pub fn ge<E1, E2, C1, C2>(self, left_col: C1, right_col: C2) -> Self
197 where
198 E1: Entity,
199 E2: Entity,
200 C1: ModelColumn<E1>,
201 C2: ModelColumn<E2>,
202 {
203 self.push_op::<E1, E2, C1, C2>(left_col, ">=", right_col)
204 }
205
206 #[inline]
208 pub(super) fn join_type(&self) -> JoinType {
209 self.join_type
210 }
211
212 #[inline]
214 pub(super) fn join_table(&self) -> &str {
215 &self.join_table
216 }
217
218 #[inline]
220 pub(super) fn format_conditions(&self) -> String {
221 self.conditions.join(" AND ")
222 }
223
224 #[inline]
226 fn format_join_table<M: Schema>() -> String {
227 let table_name = Query::escape_table_name(M::table_name());
228 let model_name = Query::escape_table_name(M::model_name());
229 format!("{table_name} AS {model_name}")
230 }
231
232 fn push_op<E1, E2, C1, C2>(mut self, left_col: C1, operator: &str, right_col: C2) -> Self
234 where
235 E1: Entity,
236 E2: Entity,
237 C1: ModelColumn<E1>,
238 C2: ModelColumn<E2>,
239 {
240 let left_col = left_col.into_column_expr();
241 let right_col = right_col.into_column_expr();
242 let left_col_field = Query::format_field(&left_col);
243 let right_col_field = Query::format_field(&right_col);
244 let condition = format!("{left_col_field} {operator} {right_col_field}");
245 self.conditions.push(condition);
246 self
247 }
248}