1#[cfg(not(feature = "std"))]
10use crate::prelude::*;
11use crate::traits::PostgresTable;
12use crate::values::PostgresValue;
13use drizzle_core::{SQL, SQLTableInfo, ToSQL, Token, helpers, traits::SQLModel};
14
15pub(crate) use helpers::{
17 delete, except, except_all, from, group_by_expr, having, intersect, intersect_all, limit,
18 offset, order_by, select, select_distinct, set, union, union_all, update, r#where,
19};
20
21pub use drizzle_core::Join;
23
24#[doc(hidden)]
26pub trait JoinSource<'a>: join_source_private::Sealed {
27 type JoinedTable;
28
29 fn into_join_source_sql(self) -> SQL<'a, PostgresValue<'a>>;
30}
31
32mod join_source_private {
33 pub trait Sealed {}
34}
35
36impl<'a, Table> join_source_private::Sealed for Table where Table: PostgresTable<'a> {}
37
38impl<'a, Name, Projection, Query> join_source_private::Sealed
39 for drizzle_core::Derived<'a, PostgresValue<'a>, Name, Projection, Query>
40where
41 Name: drizzle_core::Tag,
42 Projection: drizzle_core::DerivedProjection<Name>,
43 Query: ToSQL<'a, PostgresValue<'a>>,
44{
45}
46
47impl<'a, Table> JoinSource<'a> for Table
48where
49 Table: PostgresTable<'a>,
50{
51 type JoinedTable = Table;
52
53 fn into_join_source_sql(self) -> SQL<'a, PostgresValue<'a>> {
54 self.into_sql()
55 }
56}
57
58impl<'a, Name, Projection, Query> JoinSource<'a>
59 for drizzle_core::Derived<'a, PostgresValue<'a>, Name, Projection, Query>
60where
61 Name: drizzle_core::Tag,
62 Projection: drizzle_core::DerivedProjection<Name>,
63 Query: ToSQL<'a, PostgresValue<'a>>,
64{
65 type JoinedTable = Self;
66
67 fn into_join_source_sql(self) -> SQL<'a, PostgresValue<'a>> {
68 self.into_sql()
69 }
70}
71
72#[doc(hidden)]
78pub trait CrossJoinArg<'a, FromTable>: cross_join_arg_private::Sealed {
79 type JoinedTable;
80 type OnSources;
82
83 fn into_cross_join_sql(self) -> SQL<'a, PostgresValue<'a>>;
84}
85
86mod cross_join_arg_private {
87 pub trait Sealed {}
88
89 impl<'a, Source> Sealed for Source where Source: super::JoinSource<'a> {}
90
91 impl<'a, Source, Condition> Sealed for (Source, Condition)
92 where
93 Source: super::JoinSource<'a>,
94 Condition: drizzle_core::ToSQL<'a, crate::values::PostgresValue<'a>>,
95 {
96 }
97}
98
99impl<'a, Source, FromTable> CrossJoinArg<'a, FromTable> for Source
100where
101 Source: JoinSource<'a>,
102{
103 type JoinedTable = Source::JoinedTable;
104 type OnSources = ();
105
106 fn into_cross_join_sql(self) -> SQL<'a, PostgresValue<'a>> {
107 Join::new()
108 .cross()
109 .into_sql()
110 .append(self.into_join_source_sql())
111 }
112}
113
114impl<'a, Source, Condition, FromTable> CrossJoinArg<'a, FromTable> for (Source, Condition)
115where
116 Source: JoinSource<'a>,
117 Condition: ToSQL<'a, PostgresValue<'a>> + drizzle_core::expr::ExprSources,
118{
119 type JoinedTable = Source::JoinedTable;
120 type OnSources = Condition::Sources;
121
122 fn into_cross_join_sql(self) -> SQL<'a, PostgresValue<'a>> {
123 let (source, condition) = self;
124 Join::new()
125 .inner()
126 .into_sql()
127 .append(source.into_join_source_sql())
128 .push(Token::ON)
129 .append(condition.into_sql())
130 }
131}
132
133drizzle_core::impl_join_arg_trait!(
134 table_trait: PostgresTable<'a>,
135 table_info_trait: SQLTableInfo,
136 condition_trait: ToSQL<'a, PostgresValue<'a>>,
137 join_source_trait: JoinSource<'a>,
138 value_type: PostgresValue<'a>,
139);
140
141drizzle_core::impl_join_helpers!(
143 table_trait: PostgresTable<'a>,
144 condition_trait: ToSQL<'a, PostgresValue<'a>>,
145 sql_type: SQL<'a, PostgresValue<'a>>,
146);
147
148pub(crate) fn select_distinct_on<'a, On, Columns>(
150 on: On,
151 columns: Columns,
152) -> SQL<'a, PostgresValue<'a>>
153where
154 On: ToSQL<'a, PostgresValue<'a>>,
155 Columns: ToSQL<'a, PostgresValue<'a>>,
156{
157 SQL::from_iter([Token::SELECT, Token::DISTINCT, Token::ON, Token::LPAREN])
158 .append(on.into_sql())
159 .push(Token::RPAREN)
160 .append(columns.into_sql())
161}
162
163fn join_using_internal<'a, Table>(
168 table: Table,
169 join: Join,
170 columns: impl ToSQL<'a, PostgresValue<'a>>,
171) -> SQL<'a, PostgresValue<'a>>
172where
173 Table: PostgresTable<'a>,
174{
175 join.into_sql()
176 .append(table.into_sql())
177 .push(Token::USING)
178 .push(Token::LPAREN)
179 .append(columns.into_sql())
180 .push(Token::RPAREN)
181}
182
183pub fn join_using<'a, Table>(
266 table: Table,
267 columns: impl ToSQL<'a, PostgresValue<'a>>,
268) -> SQL<'a, PostgresValue<'a>>
269where
270 Table: PostgresTable<'a>,
271{
272 join_using_internal(table, Join::new(), columns)
273}
274
275pub fn inner_join_using<'a, Table>(
277 table: Table,
278 columns: impl ToSQL<'a, PostgresValue<'a>>,
279) -> SQL<'a, PostgresValue<'a>>
280where
281 Table: PostgresTable<'a>,
282{
283 join_using_internal(table, Join::new().inner(), columns)
284}
285
286pub fn left_join_using<'a, Table>(
288 table: Table,
289 columns: impl ToSQL<'a, PostgresValue<'a>>,
290) -> SQL<'a, PostgresValue<'a>>
291where
292 Table: PostgresTable<'a>,
293{
294 join_using_internal(table, Join::new().left(), columns)
295}
296
297pub fn left_outer_join_using<'a, Table>(
299 table: Table,
300 columns: impl ToSQL<'a, PostgresValue<'a>>,
301) -> SQL<'a, PostgresValue<'a>>
302where
303 Table: PostgresTable<'a>,
304{
305 join_using_internal(table, Join::new().left().outer(), columns)
306}
307
308pub fn right_join_using<'a, Table>(
310 table: Table,
311 columns: impl ToSQL<'a, PostgresValue<'a>>,
312) -> SQL<'a, PostgresValue<'a>>
313where
314 Table: PostgresTable<'a>,
315{
316 join_using_internal(table, Join::new().right(), columns)
317}
318
319pub fn right_outer_join_using<'a, Table>(
321 table: Table,
322 columns: impl ToSQL<'a, PostgresValue<'a>>,
323) -> SQL<'a, PostgresValue<'a>>
324where
325 Table: PostgresTable<'a>,
326{
327 join_using_internal(table, Join::new().right().outer(), columns)
328}
329
330pub fn full_join_using<'a, Table>(
332 table: Table,
333 columns: impl ToSQL<'a, PostgresValue<'a>>,
334) -> SQL<'a, PostgresValue<'a>>
335where
336 Table: PostgresTable<'a>,
337{
338 join_using_internal(table, Join::new().full(), columns)
339}
340
341pub fn full_outer_join_using<'a, Table>(
343 table: Table,
344 columns: impl ToSQL<'a, PostgresValue<'a>>,
345) -> SQL<'a, PostgresValue<'a>>
346where
347 Table: PostgresTable<'a>,
348{
349 join_using_internal(table, Join::new().full().outer(), columns)
350}
351
352pub(crate) fn insert<'a, Table>(table: &Table) -> SQL<'a, PostgresValue<'a>>
357where
358 Table: PostgresTable<'a>,
359{
360 SQL::from_iter([Token::INSERT, Token::INTO]).append(table)
361}
362
363pub(crate) fn values<'a, Table, T>(
370 rows: impl IntoIterator<Item = Table::Insert<T>>,
371) -> SQL<'a, PostgresValue<'a>>
372where
373 Table: PostgresTable<'a>,
374{
375 let rows: Vec<_> = rows.into_iter().collect();
376
377 if rows.is_empty() {
378 return SQL::from(Token::VALUES);
379 }
380
381 let columns_info = rows[0].columns();
382 let columns_slice = columns_info.as_ref();
383 if rows[1..]
384 .iter()
385 .any(|row| row.columns().as_ref() != columns_slice)
386 {
387 let rows_sql = drizzle_core::helpers::insert_values_with_defaults(
388 rows.iter()
389 .map(|row| (row.columns(), row.values()))
390 .collect(),
391 );
392 if let Some(rows_sql) = rows_sql {
393 return rows_sql;
394 }
395 }
396
397 if columns_slice.is_empty() {
398 return if rows.len() == 1 {
403 SQL::from_iter([Token::DEFAULT, Token::VALUES])
404 } else {
405 SQL::raw("SELECT FROM").append(SQL::func(
406 "generate_series",
407 SQL::number(1)
408 .push(Token::COMMA)
409 .append(SQL::number(rows.len())),
410 ))
411 };
412 }
413
414 let columns_sql = SQL::columns(columns_slice);
415 let mut values_sql = SQL::with_capacity_chunks(rows.len().saturating_mul(4));
416 for (idx, row) in rows.iter().enumerate() {
417 if idx > 0 {
418 values_sql.push_mut(Token::COMMA);
419 }
420 values_sql.push_mut(Token::LPAREN);
421 values_sql.append_mut(row.values());
422 values_sql.push_mut(Token::RPAREN);
423 }
424
425 columns_sql.parens().push(Token::VALUES).append(values_sql)
426}
427
428pub(crate) fn returning<'a, 'b, I>(columns: I) -> SQL<'a, PostgresValue<'a>>
430where
431 I: ToSQL<'a, PostgresValue<'a>>,
432{
433 let columns = columns.into_sql();
434 let columns = if columns.chunks.is_empty() {
435 SQL::from(Token::STAR)
436 } else {
437 columns
438 };
439 SQL::from(Token::RETURNING).append(columns)
440}
441
442pub(crate) fn for_update<'a>() -> SQL<'a, PostgresValue<'a>> {
448 SQL::from_iter([Token::FOR, Token::UPDATE])
449}
450
451pub(crate) fn for_share<'a>() -> SQL<'a, PostgresValue<'a>> {
453 SQL::from_iter([Token::FOR, Token::SHARE])
454}
455
456pub(crate) fn for_no_key_update<'a>() -> SQL<'a, PostgresValue<'a>> {
458 SQL::from_iter([Token::FOR, Token::NO, Token::KEY, Token::UPDATE])
459}
460
461pub(crate) fn for_key_share<'a>() -> SQL<'a, PostgresValue<'a>> {
463 SQL::from_iter([Token::FOR, Token::KEY, Token::SHARE])
464}
465
466pub(crate) fn for_update_of<'a>(table_name: &str) -> SQL<'a, PostgresValue<'a>> {
468 SQL::from_iter([Token::FOR, Token::UPDATE, Token::OF])
469 .append(SQL::ident(String::from(table_name)))
470}
471
472pub(crate) fn for_share_of<'a>(table_name: &str) -> SQL<'a, PostgresValue<'a>> {
474 SQL::from_iter([Token::FOR, Token::SHARE, Token::OF])
475 .append(SQL::ident(String::from(table_name)))
476}
477
478pub(crate) fn nowait<'a>() -> SQL<'a, PostgresValue<'a>> {
480 SQL::from(Token::NOWAIT)
481}
482
483pub(crate) fn skip_locked<'a>() -> SQL<'a, PostgresValue<'a>> {
485 SQL::from_iter([Token::SKIP, Token::LOCKED])
486}