1use crate::{
2 PostgresSQL, ToPostgresSQL, common::Join, traits::PostgresTable, values::PostgresValue,
3};
4use drizzle_core::{
5 SQL, ToSQL, Token, helpers,
6 traits::{SQLColumnInfo, SQLModel},
7};
8
9pub(crate) use helpers::{
11 delete, from, group_by, having, limit, offset, order_by, select, set, update, r#where,
12};
13
14fn columns_info_to_sql<'a>(columns: &[&'static dyn SQLColumnInfo]) -> PostgresSQL<'a> {
16 let joined_names = columns
18 .iter()
19 .map(|col| col.name())
20 .collect::<Vec<_>>()
21 .join(", ");
22 SQL::raw(joined_names)
23}
24
25fn join_internal<'a, Table>(
26 table: Table,
27 join: Join,
28 condition: impl ToPostgresSQL<'a>,
29) -> PostgresSQL<'a>
30where
31 Table: PostgresTable<'a>,
32{
33 join.to_sql()
34 .append(table.to_sql())
35 .push(Token::ON)
36 .append(condition.to_sql())
37}
38
39fn join_using_internal<'a, Table>(
40 table: Table,
41 join: Join,
42 columns: impl ToPostgresSQL<'a>,
43) -> PostgresSQL<'a>
44where
45 Table: PostgresTable<'a>,
46{
47 join.to_sql()
48 .append(table.to_sql())
49 .push(Token::USING)
50 .push(Token::LPAREN)
51 .append(columns.to_sql())
52 .push(Token::RPAREN)
53}
54
55pub fn natural_join<'a, Table>(table: Table, condition: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
57where
58 Table: PostgresTable<'a>,
59{
60 join_internal(table, Join::default().natural(), condition)
61}
62
63pub fn join<'a, Table>(table: Table, condition: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
65where
66 Table: PostgresTable<'a>,
67{
68 join_internal(table, Join::default(), condition)
69}
70
71pub fn natural_left_join<'a, Table>(
72 table: Table,
73 condition: impl ToPostgresSQL<'a>,
74) -> PostgresSQL<'a>
75where
76 Table: PostgresTable<'a>,
77{
78 join_internal(table, Join::new().natural().left(), condition)
79}
80
81pub fn left_join<'a, Table>(table: Table, condition: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
83where
84 Table: PostgresTable<'a>,
85{
86 join_internal(table, Join::new().left(), condition)
87}
88
89pub fn left_outer_join<'a, Table>(
90 table: Table,
91 condition: impl ToPostgresSQL<'a>,
92) -> PostgresSQL<'a>
93where
94 Table: PostgresTable<'a>,
95{
96 join_internal(table, Join::new().left().outer(), condition)
97}
98
99pub fn natural_left_outer_join<'a, Table>(
100 table: Table,
101 condition: impl ToPostgresSQL<'a>,
102) -> PostgresSQL<'a>
103where
104 Table: PostgresTable<'a>,
105{
106 join_internal(table, Join::new().natural().left().outer(), condition)
107}
108
109pub fn natural_right_join<'a, Table>(
110 table: Table,
111 condition: impl ToPostgresSQL<'a>,
112) -> PostgresSQL<'a>
113where
114 Table: PostgresTable<'a>,
115{
116 join_internal(table, Join::new().natural().right(), condition)
117}
118
119pub fn right_join<'a, Table>(table: Table, condition: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
121where
122 Table: PostgresTable<'a>,
123{
124 join_internal(table, Join::new().right(), condition)
125}
126
127pub fn right_outer_join<'a, Table>(
128 table: Table,
129 condition: impl ToPostgresSQL<'a>,
130) -> PostgresSQL<'a>
131where
132 Table: PostgresTable<'a>,
133{
134 join_internal(table, Join::new().right().outer(), condition)
135}
136
137pub fn natural_right_outer_join<'a, Table>(
138 table: Table,
139 condition: impl ToPostgresSQL<'a>,
140) -> PostgresSQL<'a>
141where
142 Table: PostgresTable<'a>,
143{
144 join_internal(table, Join::new().natural().right().outer(), condition)
145}
146
147pub fn natural_full_join<'a, Table>(
148 table: Table,
149 condition: impl ToPostgresSQL<'a>,
150) -> PostgresSQL<'a>
151where
152 Table: PostgresTable<'a>,
153{
154 join_internal(table, Join::new().natural().full(), condition)
155}
156
157pub fn full_join<'a, Table>(table: Table, condition: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
159where
160 Table: PostgresTable<'a>,
161{
162 join_internal(table, Join::new().full(), condition)
163}
164
165pub fn full_outer_join<'a, Table>(
166 table: Table,
167 condition: impl ToPostgresSQL<'a>,
168) -> PostgresSQL<'a>
169where
170 Table: PostgresTable<'a>,
171{
172 join_internal(table, Join::new().full().outer(), condition)
173}
174
175pub fn natural_full_outer_join<'a, Table>(
176 table: Table,
177 condition: impl ToPostgresSQL<'a>,
178) -> PostgresSQL<'a>
179where
180 Table: PostgresTable<'a>,
181{
182 join_internal(table, Join::new().natural().full().outer(), condition)
183}
184
185pub fn natural_inner_join<'a, Table>(
186 table: Table,
187 condition: impl ToPostgresSQL<'a>,
188) -> PostgresSQL<'a>
189where
190 Table: PostgresTable<'a>,
191{
192 join_internal(table, Join::new().natural().inner(), condition)
193}
194
195pub fn inner_join<'a, Table>(table: Table, condition: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
197where
198 Table: PostgresTable<'a>,
199{
200 join_internal(table, Join::new().inner(), condition)
201}
202
203pub fn cross_join<'a, Table>(table: Table, condition: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
205where
206 Table: PostgresTable<'a>,
207{
208 join_internal(table, Join::new().cross(), condition)
209}
210
211pub fn join_using<'a, Table>(table: Table, columns: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
216where
217 Table: PostgresTable<'a>,
218{
219 join_using_internal(table, Join::new(), columns)
220}
221
222pub fn inner_join_using<'a, Table>(table: Table, columns: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
223where
224 Table: PostgresTable<'a>,
225{
226 join_using_internal(table, Join::new().inner(), columns)
227}
228
229pub fn left_join_using<'a, Table>(table: Table, columns: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
230where
231 Table: PostgresTable<'a>,
232{
233 join_using_internal(table, Join::new().left(), columns)
234}
235
236pub fn left_outer_join_using<'a, Table>(
237 table: Table,
238 columns: impl ToPostgresSQL<'a>,
239) -> PostgresSQL<'a>
240where
241 Table: PostgresTable<'a>,
242{
243 join_using_internal(table, Join::new().left().outer(), columns)
244}
245
246pub fn right_join_using<'a, Table>(table: Table, columns: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
247where
248 Table: PostgresTable<'a>,
249{
250 join_using_internal(table, Join::new().right(), columns)
251}
252
253pub fn right_outer_join_using<'a, Table>(
254 table: Table,
255 columns: impl ToPostgresSQL<'a>,
256) -> PostgresSQL<'a>
257where
258 Table: PostgresTable<'a>,
259{
260 join_using_internal(table, Join::new().right().outer(), columns)
261}
262
263pub fn full_join_using<'a, Table>(table: Table, columns: impl ToPostgresSQL<'a>) -> PostgresSQL<'a>
264where
265 Table: PostgresTable<'a>,
266{
267 join_using_internal(table, Join::new().full(), columns)
268}
269
270pub fn full_outer_join_using<'a, Table>(
271 table: Table,
272 columns: impl ToPostgresSQL<'a>,
273) -> PostgresSQL<'a>
274where
275 Table: PostgresTable<'a>,
276{
277 join_using_internal(table, Join::new().full().outer(), columns)
278}
279
280pub(crate) fn insert<'a, Table>(table: Table) -> SQL<'a, PostgresValue<'a>>
285where
286 Table: PostgresTable<'a>,
287{
288 SQL::from_iter([Token::INSERT, Token::INTO]).append(&table)
289}
290
291pub(crate) fn values<'a, Table, T>(
294 rows: impl IntoIterator<Item = Table::Insert<T>>,
295) -> SQL<'a, PostgresValue<'a>>
296where
297 Table: PostgresTable<'a>,
298{
299 let rows: Vec<_> = rows.into_iter().collect();
300
301 if rows.is_empty() {
302 return SQL::from(Token::VALUES);
303 }
304
305 let columns_info = rows[0].columns();
308
309 if columns_info.is_empty() {
311 return SQL::from_iter([Token::DEFAULT, Token::VALUES]);
312 }
313
314 let columns_sql = columns_info_to_sql(&columns_info);
315 let value_clauses: Vec<_> = rows.iter().map(|row| row.values().parens()).collect();
316
317 columns_sql
318 .parens()
319 .push(Token::VALUES)
320 .append(SQL::join(value_clauses, Token::COMMA))
321}
322
323pub(crate) fn returning<'a, 'b, I>(columns: I) -> PostgresSQL<'a>
325where
326 I: ToPostgresSQL<'a>,
327{
328 SQL::from(Token::RETURNING).append(columns.to_sql())
329}
330
331pub(crate) fn on_conflict<'a, T>(
333 conflict_target: Option<PostgresSQL<'a>>,
334 action: impl ToPostgresSQL<'a>,
335) -> PostgresSQL<'a> {
336 let mut sql = SQL::from_iter([Token::ON, Token::CONFLICT]);
337
338 if let Some(target) = conflict_target {
339 sql = sql.push(Token::LPAREN).append(target).push(Token::RPAREN);
340 }
341
342 sql.append(action.to_sql())
343}