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)]
26#[diagnostic::on_unimplemented(
27 message = "`{Self}` cannot follow JOIN",
28 label = "join a table, a view, or an aliased subquery"
29)]
30pub trait JoinSource<'a>: join_source_private::Sealed {
31 type JoinedTable;
32
33 fn into_join_source_sql(self) -> SQL<'a, PostgresValue<'a>>;
34}
35
36mod join_source_private {
37 pub trait Sealed {}
38}
39
40impl<'a, Table> join_source_private::Sealed for Table where Table: PostgresTable<'a> {}
41
42impl<'a, Name, Projection, Query> join_source_private::Sealed
43 for drizzle_core::Derived<'a, PostgresValue<'a>, Name, Projection, Query>
44where
45 Name: drizzle_core::Tag,
46 Projection: drizzle_core::DerivedProjection<Name>,
47 Query: ToSQL<'a, PostgresValue<'a>>,
48{
49}
50
51impl<'a, Table> JoinSource<'a> for Table
52where
53 Table: PostgresTable<'a>,
54{
55 type JoinedTable = Table;
56
57 fn into_join_source_sql(self) -> SQL<'a, PostgresValue<'a>> {
58 self.into_sql()
59 }
60}
61
62impl<'a, Name, Projection, Query> JoinSource<'a>
63 for drizzle_core::Derived<'a, PostgresValue<'a>, Name, Projection, Query>
64where
65 Name: drizzle_core::Tag,
66 Projection: drizzle_core::DerivedProjection<Name>,
67 Query: ToSQL<'a, PostgresValue<'a>>,
68{
69 type JoinedTable = Self;
70
71 fn into_join_source_sql(self) -> SQL<'a, PostgresValue<'a>> {
72 self.into_sql()
73 }
74}
75
76#[doc(hidden)]
82pub trait CrossJoinArg<'a, FromTable>: cross_join_arg_private::Sealed {
83 type JoinedTable;
84 type OnSources;
86
87 fn into_cross_join_sql(self) -> SQL<'a, PostgresValue<'a>>;
88}
89
90mod cross_join_arg_private {
91 pub trait Sealed {}
92
93 impl<'a, Source> Sealed for Source where Source: super::JoinSource<'a> {}
94
95 impl<'a, Source, Condition> Sealed for (Source, Condition)
96 where
97 Source: super::JoinSource<'a>,
98 Condition: drizzle_core::ToSQL<'a, crate::values::PostgresValue<'a>>,
99 {
100 }
101}
102
103impl<'a, Source, FromTable> CrossJoinArg<'a, FromTable> for Source
104where
105 Source: JoinSource<'a>,
106{
107 type JoinedTable = Source::JoinedTable;
108 type OnSources = ();
109
110 fn into_cross_join_sql(self) -> SQL<'a, PostgresValue<'a>> {
111 Join::new()
112 .cross()
113 .into_sql()
114 .append(self.into_join_source_sql())
115 }
116}
117
118impl<'a, Source, Condition, FromTable> CrossJoinArg<'a, FromTable> for (Source, Condition)
119where
120 Source: JoinSource<'a>,
121 Condition: ToSQL<'a, PostgresValue<'a>> + drizzle_core::expr::ExprSources,
122{
123 type JoinedTable = Source::JoinedTable;
124 type OnSources = Condition::Sources;
125
126 fn into_cross_join_sql(self) -> SQL<'a, PostgresValue<'a>> {
127 let (source, condition) = self;
128 Join::new()
129 .inner()
130 .into_sql()
131 .append(source.into_join_source_sql())
132 .push(Token::ON)
133 .append(condition.into_sql())
134 }
135}
136
137drizzle_core::impl_join_arg_trait!(
138 table_trait: PostgresTable<'a>,
139 table_info_trait: SQLTableInfo,
140 condition_trait: ToSQL<'a, PostgresValue<'a>>,
141 join_source_trait: JoinSource<'a>,
142 value_type: PostgresValue<'a>,
143);
144
145drizzle_core::impl_join_helpers!(
147 table_trait: PostgresTable<'a>,
148 condition_trait: ToSQL<'a, PostgresValue<'a>>,
149 sql_type: SQL<'a, PostgresValue<'a>>,
150);
151
152pub(crate) fn select_distinct_on<'a, On, Columns>(
154 on: On,
155 columns: Columns,
156) -> SQL<'a, PostgresValue<'a>>
157where
158 On: ToSQL<'a, PostgresValue<'a>>,
159 Columns: ToSQL<'a, PostgresValue<'a>>,
160{
161 SQL::from_iter([Token::SELECT, Token::DISTINCT, Token::ON, Token::LPAREN])
162 .append(on.into_sql())
163 .push(Token::RPAREN)
164 .append(columns.into_sql())
165}
166
167fn join_using_internal<'a, Table>(
172 table: Table,
173 join: Join,
174 columns: impl ToSQL<'a, PostgresValue<'a>>,
175) -> SQL<'a, PostgresValue<'a>>
176where
177 Table: PostgresTable<'a>,
178{
179 join.into_sql()
180 .append(table.into_sql())
181 .push(Token::USING)
182 .push(Token::LPAREN)
183 .append(columns.into_sql())
184 .push(Token::RPAREN)
185}
186
187pub fn join_using<'a, Table>(
270 table: Table,
271 columns: impl ToSQL<'a, PostgresValue<'a>>,
272) -> SQL<'a, PostgresValue<'a>>
273where
274 Table: PostgresTable<'a>,
275{
276 join_using_internal(table, Join::new(), columns)
277}
278
279pub fn inner_join_using<'a, Table>(
281 table: Table,
282 columns: impl ToSQL<'a, PostgresValue<'a>>,
283) -> SQL<'a, PostgresValue<'a>>
284where
285 Table: PostgresTable<'a>,
286{
287 join_using_internal(table, Join::new().inner(), columns)
288}
289
290pub fn left_join_using<'a, Table>(
292 table: Table,
293 columns: impl ToSQL<'a, PostgresValue<'a>>,
294) -> SQL<'a, PostgresValue<'a>>
295where
296 Table: PostgresTable<'a>,
297{
298 join_using_internal(table, Join::new().left(), columns)
299}
300
301pub fn left_outer_join_using<'a, Table>(
303 table: Table,
304 columns: impl ToSQL<'a, PostgresValue<'a>>,
305) -> SQL<'a, PostgresValue<'a>>
306where
307 Table: PostgresTable<'a>,
308{
309 join_using_internal(table, Join::new().left().outer(), columns)
310}
311
312pub fn right_join_using<'a, Table>(
314 table: Table,
315 columns: impl ToSQL<'a, PostgresValue<'a>>,
316) -> SQL<'a, PostgresValue<'a>>
317where
318 Table: PostgresTable<'a>,
319{
320 join_using_internal(table, Join::new().right(), columns)
321}
322
323pub fn right_outer_join_using<'a, Table>(
325 table: Table,
326 columns: impl ToSQL<'a, PostgresValue<'a>>,
327) -> SQL<'a, PostgresValue<'a>>
328where
329 Table: PostgresTable<'a>,
330{
331 join_using_internal(table, Join::new().right().outer(), columns)
332}
333
334pub fn full_join_using<'a, Table>(
336 table: Table,
337 columns: impl ToSQL<'a, PostgresValue<'a>>,
338) -> SQL<'a, PostgresValue<'a>>
339where
340 Table: PostgresTable<'a>,
341{
342 join_using_internal(table, Join::new().full(), columns)
343}
344
345pub fn full_outer_join_using<'a, Table>(
347 table: Table,
348 columns: impl ToSQL<'a, PostgresValue<'a>>,
349) -> SQL<'a, PostgresValue<'a>>
350where
351 Table: PostgresTable<'a>,
352{
353 join_using_internal(table, Join::new().full().outer(), columns)
354}
355
356pub(crate) fn insert<'a, Table>(table: &Table) -> SQL<'a, PostgresValue<'a>>
361where
362 Table: PostgresTable<'a>,
363{
364 SQL::from_iter([Token::INSERT, Token::INTO]).append(table)
365}
366
367pub(crate) fn values<'a, Table, T>(
374 rows: impl IntoIterator<Item = Table::Insert<T>>,
375) -> SQL<'a, PostgresValue<'a>>
376where
377 Table: PostgresTable<'a>,
378{
379 let rows: Vec<_> = rows.into_iter().collect();
380
381 if rows.is_empty() {
382 return match <Table as drizzle_core::SQLSchema<
383 'a,
384 crate::common::PostgresSchemaType,
385 PostgresValue<'a>,
386 >>::TYPE
387 {
388 crate::common::PostgresSchemaType::Table(table) => {
389 drizzle_core::helpers::insert_no_rows(
392 table,
393 "OVERRIDING SYSTEM VALUE SELECT NULL WHERE 1 = 0",
394 )
395 }
396 _ => SQL::from(Token::VALUES),
397 };
398 }
399
400 let columns_info = rows[0].columns();
401 let columns_slice = columns_info.as_ref();
402 if rows[1..]
403 .iter()
404 .any(|row| row.columns().as_ref() != columns_slice)
405 {
406 let rows_sql = drizzle_core::helpers::insert_values_with_defaults(
407 rows.iter()
408 .map(|row| (row.columns(), row.values()))
409 .collect(),
410 );
411 if let Some(rows_sql) = rows_sql {
412 return rows_sql;
413 }
414 }
415
416 if columns_slice.is_empty() {
417 return if rows.len() == 1 {
422 SQL::from_iter([Token::DEFAULT, Token::VALUES])
423 } else {
424 SQL::raw("SELECT FROM").append(SQL::func(
425 "generate_series",
426 SQL::number(1)
427 .push(Token::COMMA)
428 .append(SQL::number(rows.len())),
429 ))
430 };
431 }
432
433 let columns_sql = SQL::columns(columns_slice);
434 let mut values_sql = SQL::with_capacity_chunks(rows.len().saturating_mul(4));
435 for (idx, row) in rows.iter().enumerate() {
436 if idx > 0 {
437 values_sql.push_mut(Token::COMMA);
438 }
439 values_sql.push_mut(Token::LPAREN);
440 values_sql.append_mut(row.values());
441 values_sql.push_mut(Token::RPAREN);
442 }
443
444 columns_sql.parens().push(Token::VALUES).append(values_sql)
445}
446
447pub(crate) fn returning<'a, 'b, I>(columns: I) -> SQL<'a, PostgresValue<'a>>
449where
450 I: ToSQL<'a, PostgresValue<'a>>,
451{
452 let columns = columns.into_sql();
453 let columns = if columns.chunks.is_empty() {
454 SQL::from(Token::STAR)
455 } else {
456 columns
457 };
458 SQL::from(Token::RETURNING).append(columns)
459}
460
461pub(crate) fn for_update<'a>() -> SQL<'a, PostgresValue<'a>> {
467 SQL::from_iter([Token::FOR, Token::UPDATE])
468}
469
470pub(crate) fn for_share<'a>() -> SQL<'a, PostgresValue<'a>> {
472 SQL::from_iter([Token::FOR, Token::SHARE])
473}
474
475pub(crate) fn for_no_key_update<'a>() -> SQL<'a, PostgresValue<'a>> {
477 SQL::from_iter([Token::FOR, Token::NO, Token::KEY, Token::UPDATE])
478}
479
480pub(crate) fn for_key_share<'a>() -> SQL<'a, PostgresValue<'a>> {
482 SQL::from_iter([Token::FOR, Token::KEY, Token::SHARE])
483}
484
485pub(crate) fn for_update_of<'a>(table_name: &str) -> SQL<'a, PostgresValue<'a>> {
487 SQL::from_iter([Token::FOR, Token::UPDATE, Token::OF])
488 .append(SQL::ident(String::from(table_name)))
489}
490
491pub(crate) fn for_share_of<'a>(table_name: &str) -> SQL<'a, PostgresValue<'a>> {
493 SQL::from_iter([Token::FOR, Token::SHARE, Token::OF])
494 .append(SQL::ident(String::from(table_name)))
495}
496
497pub(crate) fn nowait<'a>() -> SQL<'a, PostgresValue<'a>> {
499 SQL::from(Token::NOWAIT)
500}
501
502pub(crate) fn skip_locked<'a>() -> SQL<'a, PostgresValue<'a>> {
504 SQL::from_iter([Token::SKIP, Token::LOCKED])
505}