1use crate::{common::Join, values::SQLiteValue};
2use drizzle_core::{
3 SQL, SQLTable, ToSQL, helpers as core_helpers,
4 traits::{SQLColumnInfo, SQLModel, SQLParam},
5};
6
7pub(crate) use core_helpers::{
9 delete, from, group_by, having, limit, offset, order_by, select, set, update, r#where,
10};
11
12fn columns_info_to_sql<'a>(columns: &[&'static dyn SQLColumnInfo]) -> SQL<'a, SQLiteValue<'a>> {
14 let joined_names = columns
16 .iter()
17 .map(|col| col.name())
18 .collect::<Vec<_>>()
19 .join(", ");
20 SQL::raw(joined_names)
21}
22
23fn join_internal<'a, T, Value>(table: T, join: Join, condition: SQL<'a, Value>) -> SQL<'a, Value>
24where
25 T: SQLTable<'a, Value>,
26 Value: SQLParam + 'a,
27{
28 let sql = join.to_sql();
29 let sql = sql.append_raw(" ");
30 let sql = sql.append(table.to_sql());
31 let sql = sql.append_raw(" ON ");
32 sql.append(condition)
33}
34
35pub fn natural_join<'a, T, Value>(table: T, condition: SQL<'a, Value>) -> SQL<'a, Value>
37where
38 T: SQLTable<'a, Value>,
39 Value: SQLParam + 'a,
40{
41 join_internal(table, Join::default().natural(), condition)
42}
43
44pub fn join<'a, T, Value>(table: T, condition: SQL<'a, Value>) -> SQL<'a, Value>
46where
47 T: SQLTable<'a, Value>,
48 Value: SQLParam + 'a,
49{
50 join_internal(table, Join::default(), condition)
51}
52
53pub fn natural_left_join<'a, T, Value>(table: T, condition: SQL<'a, Value>) -> SQL<'a, Value>
54where
55 T: SQLTable<'a, Value>,
56 Value: SQLParam + 'a,
57{
58 join_internal(table, Join::new().natural().left(), condition)
59}
60
61pub fn left_join<'a, T, TableValue>(table: T, condition: SQL<'a, TableValue>) -> SQL<'a, TableValue>
63where
64 T: SQLTable<'a, TableValue>,
65 TableValue: SQLParam + 'a,
66{
67 join_internal(table, Join::new().left(), condition)
68}
69
70pub fn left_outer_join<'a, T, TableValue>(
71 table: T,
72 condition: SQL<'a, TableValue>,
73) -> SQL<'a, TableValue>
74where
75 T: SQLTable<'a, TableValue>,
76 TableValue: SQLParam + 'a,
77{
78 join_internal(table, Join::new().left().outer(), condition)
79}
80
81pub fn natural_left_outer_join<'a, T, TableValue>(
82 table: T,
83 condition: SQL<'a, TableValue>,
84) -> SQL<'a, TableValue>
85where
86 T: SQLTable<'a, TableValue>,
87 TableValue: SQLParam + 'a,
88{
89 join_internal(table, Join::new().natural().left().outer(), condition)
90}
91
92pub fn natural_right_join<'a, T, TableValue>(
93 table: T,
94 condition: SQL<'a, TableValue>,
95) -> SQL<'a, TableValue>
96where
97 T: SQLTable<'a, TableValue>,
98 TableValue: SQLParam + 'a,
99{
100 join_internal(table, Join::new().natural().right(), condition)
101}
102
103pub fn right_join<'a, T, TableValue>(
105 table: T,
106 condition: SQL<'a, TableValue>,
107) -> SQL<'a, TableValue>
108where
109 T: SQLTable<'a, TableValue>,
110 TableValue: SQLParam + 'a,
111{
112 join_internal(table, Join::new().right(), condition)
113}
114
115pub fn right_outer_join<'a, T, TableValue>(
116 table: T,
117 condition: SQL<'a, TableValue>,
118) -> SQL<'a, TableValue>
119where
120 T: SQLTable<'a, TableValue>,
121 TableValue: SQLParam + 'a,
122{
123 join_internal(table, Join::new().right().outer(), condition)
124}
125
126pub fn natural_right_outer_join<'a, T, TableValue>(
127 table: T,
128 condition: SQL<'a, TableValue>,
129) -> SQL<'a, TableValue>
130where
131 T: SQLTable<'a, TableValue>,
132 TableValue: SQLParam + 'a,
133{
134 join_internal(table, Join::new().natural().right().outer(), condition)
135}
136
137pub fn natural_full_join<'a, T, TableValue>(
138 table: T,
139 condition: SQL<'a, TableValue>,
140) -> SQL<'a, TableValue>
141where
142 T: SQLTable<'a, TableValue>,
143 TableValue: SQLParam + 'a,
144{
145 join_internal(table, Join::new().natural().full(), condition)
146}
147
148pub fn full_join<'a, T, TableValue>(table: T, condition: SQL<'a, TableValue>) -> SQL<'a, TableValue>
150where
151 T: SQLTable<'a, TableValue>,
152 TableValue: SQLParam + 'a,
153{
154 join_internal(table, Join::new().full(), condition)
155}
156
157pub fn full_outer_join<'a, T, TableValue>(
158 table: T,
159 condition: SQL<'a, TableValue>,
160) -> SQL<'a, TableValue>
161where
162 T: SQLTable<'a, TableValue>,
163 TableValue: SQLParam + 'a,
164{
165 join_internal(table, Join::new().full().outer(), condition)
166}
167
168pub fn natural_full_outer_join<'a, T, TableValue>(
169 table: T,
170 condition: SQL<'a, TableValue>,
171) -> SQL<'a, TableValue>
172where
173 T: SQLTable<'a, TableValue>,
174 TableValue: SQLParam + 'a,
175{
176 join_internal(table, Join::new().natural().full().outer(), condition)
177}
178
179pub fn natural_inner_join<'a, T, TableValue>(
180 table: T,
181 condition: SQL<'a, TableValue>,
182) -> SQL<'a, TableValue>
183where
184 T: SQLTable<'a, TableValue>,
185 TableValue: SQLParam + 'a,
186{
187 join_internal(table, Join::new().natural().inner(), condition)
188}
189
190pub fn inner_join<'a, T, TableValue>(
192 table: T,
193 condition: SQL<'a, TableValue>,
194) -> SQL<'a, TableValue>
195where
196 T: SQLTable<'a, TableValue>,
197 TableValue: SQLParam + 'a,
198{
199 join_internal(table, Join::new().inner(), condition)
200}
201
202pub fn cross_join<'a, T, TableValue>(
204 table: T,
205 condition: SQL<'a, TableValue>,
206) -> SQL<'a, TableValue>
207where
208 T: SQLTable<'a, TableValue>,
209 TableValue: SQLParam + 'a,
210{
211 join_internal(table, Join::new().cross(), condition)
212}
213
214pub(crate) fn insert<'a, T>(table: T) -> SQL<'a, SQLiteValue<'a>>
216where
217 T: SQLTable<'a, SQLiteValue<'a>>,
218{
219 SQL::text("INSERT INTO").append(&table)
220}
221
222pub(crate) fn values<'a, Table, T>(
225 rows: impl IntoIterator<Item = <Table as SQLTable<'a, SQLiteValue<'a>>>::Insert<T>>,
226) -> SQL<'a, SQLiteValue<'a>>
227where
228 Table: SQLTable<'a, SQLiteValue<'a>> + Default,
229 Table::Insert<T>: SQLModel<'a, SQLiteValue<'a>>,
230{
231 let rows: Vec<_> = rows.into_iter().collect();
232
233 if rows.is_empty() {
234 return SQL::raw("VALUES");
235 }
236
237 let columns_info = rows[0].columns();
240
241 if columns_info.is_empty() {
243 return SQL::raw("DEFAULT VALUES");
244 }
245
246 let columns_sql = columns_info_to_sql(&columns_info);
247 let value_clauses: Vec<_> = rows.iter().map(|row| row.values().subquery()).collect();
248
249 columns_sql
250 .subquery()
251 .append_raw("VALUES")
252 .append(SQL::join(value_clauses, ", "))
253}
254
255pub(crate) fn returning<'a, 'b, I>(columns: I) -> SQL<'a, SQLiteValue<'a>>
257where
258 I: ToSQL<'a, SQLiteValue<'a>>,
259{
260 SQL::raw("RETURNING").append(columns.to_sql())
261}