1#[cfg(not(feature = "std"))]
2use crate::prelude::*;
3use crate::traits::PostgresTable;
4use crate::values::PostgresValue;
5use drizzle_core::{SQL, SQLTableInfo, ToSQL, Token, helpers, traits::SQLModel};
6
7pub(crate) use helpers::{
9 delete, except, except_all, from, group_by_expr, having, intersect, intersect_all, limit,
10 offset, order_by, select, select_distinct, set, union, union_all, update, r#where,
11};
12
13pub use drizzle_core::Join;
15
16#[doc(hidden)]
18pub trait JoinSource<'a>: join_source_private::Sealed {
19 type JoinedTable;
20
21 fn into_join_source_sql(self) -> SQL<'a, PostgresValue<'a>>;
22}
23
24mod join_source_private {
25 pub trait Sealed {}
26}
27
28impl<'a, Table> join_source_private::Sealed for Table where Table: PostgresTable<'a> {}
29
30impl<'a, Name, Projection, Query> join_source_private::Sealed
31 for drizzle_core::Derived<'a, PostgresValue<'a>, Name, Projection, Query>
32where
33 Name: drizzle_core::Tag,
34 Projection: drizzle_core::DerivedProjection<Name>,
35 Query: ToSQL<'a, PostgresValue<'a>>,
36{
37}
38
39impl<'a, Table> JoinSource<'a> for Table
40where
41 Table: PostgresTable<'a>,
42{
43 type JoinedTable = Table;
44
45 fn into_join_source_sql(self) -> SQL<'a, PostgresValue<'a>> {
46 self.into_sql()
47 }
48}
49
50impl<'a, Name, Projection, Query> JoinSource<'a>
51 for drizzle_core::Derived<'a, PostgresValue<'a>, Name, Projection, Query>
52where
53 Name: drizzle_core::Tag,
54 Projection: drizzle_core::DerivedProjection<Name>,
55 Query: ToSQL<'a, PostgresValue<'a>>,
56{
57 type JoinedTable = Self;
58
59 fn into_join_source_sql(self) -> SQL<'a, PostgresValue<'a>> {
60 self.into_sql()
61 }
62}
63
64#[doc(hidden)]
70pub trait CrossJoinArg<'a, FromTable>: cross_join_arg_private::Sealed {
71 type JoinedTable;
72
73 fn into_cross_join_sql(self) -> SQL<'a, PostgresValue<'a>>;
74}
75
76mod cross_join_arg_private {
77 pub trait Sealed {}
78
79 impl<'a, Source> Sealed for Source where Source: super::JoinSource<'a> {}
80
81 impl<'a, Source, Condition> Sealed for (Source, Condition)
82 where
83 Source: super::JoinSource<'a>,
84 Condition: drizzle_core::ToSQL<'a, crate::values::PostgresValue<'a>>,
85 {
86 }
87}
88
89impl<'a, Source, FromTable> CrossJoinArg<'a, FromTable> for Source
90where
91 Source: JoinSource<'a>,
92{
93 type JoinedTable = Source::JoinedTable;
94
95 fn into_cross_join_sql(self) -> SQL<'a, PostgresValue<'a>> {
96 Join::new()
97 .cross()
98 .into_sql()
99 .append(self.into_join_source_sql())
100 }
101}
102
103impl<'a, Source, Condition, FromTable> CrossJoinArg<'a, FromTable> for (Source, Condition)
104where
105 Source: JoinSource<'a>,
106 Condition: ToSQL<'a, PostgresValue<'a>>,
107{
108 type JoinedTable = Source::JoinedTable;
109
110 fn into_cross_join_sql(self) -> SQL<'a, PostgresValue<'a>> {
111 let (source, condition) = self;
112 Join::new()
113 .inner()
114 .into_sql()
115 .append(source.into_join_source_sql())
116 .push(Token::ON)
117 .append(condition.into_sql())
118 }
119}
120
121drizzle_core::impl_join_arg_trait!(
122 table_trait: PostgresTable<'a>,
123 table_info_trait: SQLTableInfo,
124 condition_trait: ToSQL<'a, PostgresValue<'a>>,
125 join_source_trait: JoinSource<'a>,
126 value_type: PostgresValue<'a>,
127);
128
129drizzle_core::impl_join_helpers!(
131 table_trait: PostgresTable<'a>,
132 condition_trait: ToSQL<'a, PostgresValue<'a>>,
133 sql_type: SQL<'a, PostgresValue<'a>>,
134);
135
136pub(crate) fn select_distinct_on<'a, On, Columns>(
138 on: On,
139 columns: Columns,
140) -> SQL<'a, PostgresValue<'a>>
141where
142 On: ToSQL<'a, PostgresValue<'a>>,
143 Columns: ToSQL<'a, PostgresValue<'a>>,
144{
145 SQL::from_iter([Token::SELECT, Token::DISTINCT, Token::ON, Token::LPAREN])
146 .append(on.into_sql())
147 .push(Token::RPAREN)
148 .append(columns.into_sql())
149}
150
151fn join_using_internal<'a, Table>(
156 table: Table,
157 join: Join,
158 columns: impl ToSQL<'a, PostgresValue<'a>>,
159) -> SQL<'a, PostgresValue<'a>>
160where
161 Table: PostgresTable<'a>,
162{
163 join.into_sql()
164 .append(table.into_sql())
165 .push(Token::USING)
166 .push(Token::LPAREN)
167 .append(columns.into_sql())
168 .push(Token::RPAREN)
169}
170
171pub fn join_using<'a, Table>(
177 table: Table,
178 columns: impl ToSQL<'a, PostgresValue<'a>>,
179) -> SQL<'a, PostgresValue<'a>>
180where
181 Table: PostgresTable<'a>,
182{
183 join_using_internal(table, Join::new(), columns)
184}
185
186pub fn inner_join_using<'a, Table>(
188 table: Table,
189 columns: impl ToSQL<'a, PostgresValue<'a>>,
190) -> SQL<'a, PostgresValue<'a>>
191where
192 Table: PostgresTable<'a>,
193{
194 join_using_internal(table, Join::new().inner(), columns)
195}
196
197pub fn left_join_using<'a, Table>(
199 table: Table,
200 columns: impl ToSQL<'a, PostgresValue<'a>>,
201) -> SQL<'a, PostgresValue<'a>>
202where
203 Table: PostgresTable<'a>,
204{
205 join_using_internal(table, Join::new().left(), columns)
206}
207
208pub fn left_outer_join_using<'a, Table>(
210 table: Table,
211 columns: impl ToSQL<'a, PostgresValue<'a>>,
212) -> SQL<'a, PostgresValue<'a>>
213where
214 Table: PostgresTable<'a>,
215{
216 join_using_internal(table, Join::new().left().outer(), columns)
217}
218
219pub fn right_join_using<'a, Table>(
221 table: Table,
222 columns: impl ToSQL<'a, PostgresValue<'a>>,
223) -> SQL<'a, PostgresValue<'a>>
224where
225 Table: PostgresTable<'a>,
226{
227 join_using_internal(table, Join::new().right(), columns)
228}
229
230pub fn right_outer_join_using<'a, Table>(
232 table: Table,
233 columns: impl ToSQL<'a, PostgresValue<'a>>,
234) -> SQL<'a, PostgresValue<'a>>
235where
236 Table: PostgresTable<'a>,
237{
238 join_using_internal(table, Join::new().right().outer(), columns)
239}
240
241pub fn full_join_using<'a, Table>(
243 table: Table,
244 columns: impl ToSQL<'a, PostgresValue<'a>>,
245) -> SQL<'a, PostgresValue<'a>>
246where
247 Table: PostgresTable<'a>,
248{
249 join_using_internal(table, Join::new().full(), columns)
250}
251
252pub fn full_outer_join_using<'a, Table>(
254 table: Table,
255 columns: impl ToSQL<'a, PostgresValue<'a>>,
256) -> SQL<'a, PostgresValue<'a>>
257where
258 Table: PostgresTable<'a>,
259{
260 join_using_internal(table, Join::new().full().outer(), columns)
261}
262
263pub(crate) fn insert<'a, Table>(table: &Table) -> SQL<'a, PostgresValue<'a>>
268where
269 Table: PostgresTable<'a>,
270{
271 SQL::from_iter([Token::INSERT, Token::INTO]).append(table)
272}
273
274pub(crate) fn values<'a, Table, T>(
281 rows: impl IntoIterator<Item = Table::Insert<T>>,
282) -> SQL<'a, PostgresValue<'a>>
283where
284 Table: PostgresTable<'a>,
285{
286 let rows: Vec<_> = rows.into_iter().collect();
287
288 if rows.is_empty() {
289 return SQL::from(Token::VALUES);
290 }
291
292 let columns_info = rows[0].columns();
293 let columns_slice = columns_info.as_ref();
294 if rows[1..]
295 .iter()
296 .any(|row| row.columns().as_ref() != columns_slice)
297 {
298 let rows_sql = drizzle_core::helpers::insert_values_with_defaults(
299 rows.iter()
300 .map(|row| (row.columns(), row.values()))
301 .collect(),
302 );
303 if let Some(rows_sql) = rows_sql {
304 return rows_sql;
305 }
306 }
307
308 if columns_slice.is_empty() {
309 return if rows.len() == 1 {
314 SQL::from_iter([Token::DEFAULT, Token::VALUES])
315 } else {
316 SQL::raw("SELECT FROM").append(SQL::func(
317 "generate_series",
318 SQL::number(1)
319 .push(Token::COMMA)
320 .append(SQL::number(rows.len())),
321 ))
322 };
323 }
324
325 let columns_sql = SQL::columns(columns_slice);
326 let mut values_sql = SQL::with_capacity_chunks(rows.len().saturating_mul(4));
327 for (idx, row) in rows.iter().enumerate() {
328 if idx > 0 {
329 values_sql.push_mut(Token::COMMA);
330 }
331 values_sql.push_mut(Token::LPAREN);
332 values_sql.append_mut(row.values());
333 values_sql.push_mut(Token::RPAREN);
334 }
335
336 columns_sql.parens().push(Token::VALUES).append(values_sql)
337}
338
339pub(crate) fn returning<'a, 'b, I>(columns: I) -> SQL<'a, PostgresValue<'a>>
341where
342 I: ToSQL<'a, PostgresValue<'a>>,
343{
344 let columns = columns.into_sql();
345 let columns = if columns.chunks.is_empty() {
346 SQL::from(Token::STAR)
347 } else {
348 columns
349 };
350 SQL::from(Token::RETURNING).append(columns)
351}
352
353pub(crate) fn for_update<'a>() -> SQL<'a, PostgresValue<'a>> {
359 SQL::from_iter([Token::FOR, Token::UPDATE])
360}
361
362pub(crate) fn for_share<'a>() -> SQL<'a, PostgresValue<'a>> {
364 SQL::from_iter([Token::FOR, Token::SHARE])
365}
366
367pub(crate) fn for_no_key_update<'a>() -> SQL<'a, PostgresValue<'a>> {
369 SQL::from_iter([Token::FOR, Token::NO, Token::KEY, Token::UPDATE])
370}
371
372pub(crate) fn for_key_share<'a>() -> SQL<'a, PostgresValue<'a>> {
374 SQL::from_iter([Token::FOR, Token::KEY, Token::SHARE])
375}
376
377pub(crate) fn for_update_of<'a>(table_name: &str) -> SQL<'a, PostgresValue<'a>> {
380 SQL::from_iter([Token::FOR, Token::UPDATE, Token::OF])
381 .append(SQL::ident(String::from(table_name)))
382}
383
384pub(crate) fn for_share_of<'a>(table_name: &str) -> SQL<'a, PostgresValue<'a>> {
387 SQL::from_iter([Token::FOR, Token::SHARE, Token::OF])
388 .append(SQL::ident(String::from(table_name)))
389}
390
391pub(crate) fn nowait<'a>() -> SQL<'a, PostgresValue<'a>> {
393 SQL::from(Token::NOWAIT)
394}
395
396pub(crate) fn skip_locked<'a>() -> SQL<'a, PostgresValue<'a>> {
398 SQL::from_iter([Token::SKIP, Token::LOCKED])
399}