1use crate::traits::SQLiteTable;
2use crate::values::SQLiteValue;
3use core::marker::PhantomData;
4use drizzle_core::builder::{
5 ConflictColumnsTarget, OnConflictBuilder as CoreOnConflictBuilder, OnConflictOutput,
6};
7use drizzle_core::{
8 ConflictTarget, InsertSelectCompatible, InsertSelectTable, InsertTargetColumns,
9 PartialInsertSelectCompatible, SQL, SQLModel, ToSQL, Token,
10};
11
12use super::select::{CompletedSelect, IntoSelectQuery};
13
14pub use drizzle_core::builder::{
19 InsertColumnsSet, InsertDoUpdateSet, InsertInitial, InsertOnConflictSet, InsertReturningSet,
20 InsertValuesSet,
21};
22
23pub type OnConflictBuilder<'a, S, T> = CoreOnConflictBuilder<
32 'a,
33 SQLiteValue<'a>,
34 S,
35 T,
36 ConflictColumnsTarget<'a, SQLiteValue<'a>>,
37 SQLiteOnConflictOutput,
38>;
39
40#[doc(hidden)]
41#[derive(Debug, Clone, Copy, Default)]
42pub struct SQLiteOnConflictOutput;
43
44impl<'a, S, T> OnConflictOutput<'a, SQLiteValue<'a>, S, T> for SQLiteOnConflictOutput {
45 type OnConflictSet = InsertBuilder<'a, S, InsertOnConflictSet, T>;
46 type DoUpdateSet = InsertBuilder<'a, S, InsertDoUpdateSet, T>;
47
48 fn on_conflict(sql: SQL<'a, SQLiteValue<'a>>) -> Self::OnConflictSet {
49 InsertBuilder {
50 sql,
51 schema: PhantomData,
52 state: PhantomData,
53 table: PhantomData,
54 marker: PhantomData,
55 row: PhantomData,
56 grouped: PhantomData,
57 }
58 }
59
60 fn do_update(sql: SQL<'a, SQLiteValue<'a>>) -> Self::DoUpdateSet {
61 InsertBuilder {
62 sql,
63 schema: PhantomData,
64 state: PhantomData,
65 table: PhantomData,
66 marker: PhantomData,
67 row: PhantomData,
68 grouped: PhantomData,
69 }
70 }
71}
72
73pub type InsertBuilder<'a, Schema, State, Table, Marker = (), Row = ()> =
95 super::QueryBuilder<'a, Schema, State, Table, Marker, Row>;
96
97type ReturningMarker<Table, Columns> = drizzle_core::Scoped<
98 <Columns as drizzle_core::IntoSelectTarget>::Marker,
99 drizzle_core::Cons<Table, drizzle_core::Nil>,
100>;
101
102type ReturningRow<Table, Columns> =
103 <<Columns as drizzle_core::IntoSelectTarget>::Marker as drizzle_core::ResolveRow<Table>>::Row;
104
105type ReturningBuilder<'a, S, T, Columns> = InsertBuilder<
106 'a,
107 S,
108 InsertReturningSet,
109 T,
110 ReturningMarker<T, Columns>,
111 ReturningRow<T, Columns>,
112>;
113
114impl<'a, Schema, Table> InsertBuilder<'a, Schema, InsertInitial, Table>
119where
120 Table: SQLiteTable<'a>,
121{
122 #[inline]
127 pub fn value<T>(
128 self,
129 value: Table::Insert<T>,
130 ) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
131 where
132 Table::Insert<T>: SQLModel<'a, SQLiteValue<'a>>,
133 {
134 self.values([value])
135 }
136
137 #[inline]
142 pub fn values<I, T>(self, values: I) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
143 where
144 I: IntoIterator<Item = Table::Insert<T>>,
145 Table::Insert<T>: SQLModel<'a, SQLiteValue<'a>>,
146 {
147 let sql = crate::helpers::values::<'a, Table, T>(values);
148 InsertBuilder {
149 sql: self.sql.append(sql),
150 schema: PhantomData,
151 state: PhantomData,
152 table: PhantomData,
153 marker: PhantomData,
154 row: PhantomData,
155 grouped: PhantomData,
156 }
157 }
158
159 #[inline]
161 pub fn columns<Columns>(
162 self,
163 columns: Columns,
164 ) -> InsertBuilder<'a, Schema, InsertColumnsSet<Columns::Columns>, Table>
165 where
166 Columns: InsertTargetColumns<'a, SQLiteValue<'a>, Table>,
167 {
168 InsertBuilder {
169 sql: self.sql.append(columns.into_target_columns_sql()),
170 schema: PhantomData,
171 state: PhantomData,
172 table: PhantomData,
173 marker: PhantomData,
174 row: PhantomData,
175 grouped: PhantomData,
176 }
177 }
178
179 #[inline]
181 pub fn select<Q, R, ScopeProof, AggProof>(
182 self,
183 query: Q,
184 ) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
185 where
186 Table: InsertSelectTable,
187 Q: IntoSelectQuery<'a, Schema, R>,
188 Q::Marker: InsertSelectCompatible<'a, SQLiteValue<'a>, Table, R>
189 + drizzle_core::InsertSourceInScope<ScopeProof>
190 + drizzle_core::MarkerAggValidFor<Q::Grouped, AggProof>,
191 {
192 let select = query.into_select_query().into_select_sql();
193 InsertBuilder {
194 sql: self
195 .sql
196 .append(Table::insert_columns_sql::<SQLiteValue<'a>>())
197 .append(select),
198 schema: PhantomData,
199 state: PhantomData,
200 table: PhantomData,
201 marker: PhantomData,
202 row: PhantomData,
203 grouped: PhantomData,
204 }
205 }
206
207 #[inline]
212 pub fn select_raw<Q>(self, query: Q) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
213 where
214 Q: ToSQL<'a, SQLiteValue<'a>>,
215 {
216 InsertBuilder {
217 sql: self.sql.append(query.into_sql()),
218 schema: PhantomData,
219 state: PhantomData,
220 table: PhantomData,
221 marker: PhantomData,
222 row: PhantomData,
223 grouped: PhantomData,
224 }
225 }
226}
227
228impl<'a, Schema, Table, Targets> InsertBuilder<'a, Schema, InsertColumnsSet<Targets>, Table>
229where
230 Table: SQLiteTable<'a> + InsertSelectTable,
231{
232 #[inline]
234 pub fn select<Q, R, RequiredProof, ScopeProof, AggProof>(
235 self,
236 query: Q,
237 ) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
238 where
239 Targets: drizzle_core::IncludesRequired<Table::RequiredColumns, RequiredProof>,
240 Q: IntoSelectQuery<'a, Schema, R>,
241 Q::Marker: PartialInsertSelectCompatible<'a, SQLiteValue<'a>, Targets>
242 + drizzle_core::InsertSourceInScope<ScopeProof>
243 + drizzle_core::MarkerAggValidFor<Q::Grouped, AggProof>,
244 {
245 let select = query.into_select_query().into_select_sql();
246 InsertBuilder {
247 sql: self.sql.append(select),
248 schema: PhantomData,
249 state: PhantomData,
250 table: PhantomData,
251 marker: PhantomData,
252 row: PhantomData,
253 grouped: PhantomData,
254 }
255 }
256
257 #[inline]
262 pub fn select_raw<Q, RequiredProof>(
263 self,
264 query: Q,
265 ) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
266 where
267 Targets: drizzle_core::IncludesRequired<Table::RequiredColumns, RequiredProof>,
268 Q: ToSQL<'a, SQLiteValue<'a>>,
269 {
270 InsertBuilder {
271 sql: self.sql.append(query.into_sql()),
272 schema: PhantomData,
273 state: PhantomData,
274 table: PhantomData,
275 marker: PhantomData,
276 row: PhantomData,
277 grouped: PhantomData,
278 }
279 }
280}
281
282impl<'a, S, T> InsertBuilder<'a, S, InsertValuesSet, T> {
287 pub fn on_conflict<C: ConflictTarget<T>>(self, target: C) -> OnConflictBuilder<'a, S, T> {
354 let columns = target.conflict_columns();
355 let target_where = target.conflict_where_clause().map(SQL::raw);
356 let target_sql = SQL::join(columns.iter().map(|c| SQL::ident(*c)), Token::COMMA);
357 OnConflictBuilder::new(
358 crate::helpers::before_upsert(self.sql),
359 ConflictColumnsTarget::new(target_sql),
360 )
361 .with_target_where_sql(target_where)
362 }
363
364 #[must_use]
368 pub fn on_conflict_do_nothing(self) -> InsertBuilder<'a, S, InsertOnConflictSet, T> {
369 let conflict_sql = SQL::from_iter([Token::ON, Token::CONFLICT, Token::DO, Token::NOTHING]);
370 InsertBuilder {
371 sql: crate::helpers::before_upsert(self.sql).append(conflict_sql),
372 schema: PhantomData,
373 state: PhantomData,
374 table: PhantomData,
375 marker: PhantomData,
376 row: PhantomData,
377 grouped: PhantomData,
378 }
379 }
380
381 #[inline]
383 pub fn returning<Columns>(self, columns: Columns) -> ReturningBuilder<'a, S, T, Columns>
384 where
385 Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
386 Columns::Marker: drizzle_core::ResolveRow<T>,
387 {
388 let returning_sql = crate::helpers::returning(columns);
389 InsertBuilder {
390 sql: self.sql.append(returning_sql),
391 schema: PhantomData,
392 state: PhantomData,
393 table: PhantomData,
394 marker: PhantomData,
395 row: PhantomData,
396 grouped: PhantomData,
397 }
398 }
399}
400
401impl<'a, S, T> InsertBuilder<'a, S, InsertOnConflictSet, T> {
406 #[inline]
408 pub fn returning<Columns>(self, columns: Columns) -> ReturningBuilder<'a, S, T, Columns>
409 where
410 Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
411 Columns::Marker: drizzle_core::ResolveRow<T>,
412 {
413 let returning_sql = crate::helpers::returning(columns);
414 InsertBuilder {
415 sql: self.sql.append(returning_sql),
416 schema: PhantomData,
417 state: PhantomData,
418 table: PhantomData,
419 marker: PhantomData,
420 row: PhantomData,
421 grouped: PhantomData,
422 }
423 }
424}
425
426impl<'a, S, T> InsertBuilder<'a, S, InsertDoUpdateSet, T> {
431 pub fn r#where<E>(self, condition: E) -> InsertBuilder<'a, S, InsertOnConflictSet, T>
435 where
436 E: drizzle_core::expr::Expr<'a, SQLiteValue<'a>>,
437 E::SQLType: drizzle_core::types::BooleanLike,
438 {
439 let sql = self
440 .sql
441 .push(Token::WHERE)
442 .append(condition.into_expr_sql());
443 InsertBuilder {
444 sql,
445 schema: PhantomData,
446 state: PhantomData,
447 table: PhantomData,
448 marker: PhantomData,
449 row: PhantomData,
450 grouped: PhantomData,
451 }
452 }
453
454 #[inline]
456 pub fn returning<Columns>(self, columns: Columns) -> ReturningBuilder<'a, S, T, Columns>
457 where
458 Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
459 Columns::Marker: drizzle_core::ResolveRow<T>,
460 {
461 let returning_sql = crate::helpers::returning(columns);
462 InsertBuilder {
463 sql: self.sql.append(returning_sql),
464 schema: PhantomData,
465 state: PhantomData,
466 table: PhantomData,
467 marker: PhantomData,
468 row: PhantomData,
469 grouped: PhantomData,
470 }
471 }
472}