qbrs_core/insert.rs
1//! `INSERT INTO ..`, from values or from a query.
2//!
3//! A column with a schema default gets a `Defaultable<T>` field, so "omit"
4//! and "explicit value" stay distinguishable — and `Defaultable<Option<T>>`
5//! when it's also nullable, making that three distinct states. Omission
6//! renders as the `DEFAULT` keyword in that row's `VALUES (..)` tuple rather
7//! than changing the column list, so rows that omit different fields still
8//! share one statement.
9//!
10//! An `ON CONFLICT` target names columns, and the database infers an index
11//! from them — one over exactly those columns whose own predicate the
12//! target's implies. A *partial* unique index therefore needs its predicate
13//! repeated, which is what `partial_index(..)` is for.
14
15use std::marker::PhantomData;
16
17use crate::dialect::{Dialect, SupportsOnConflict};
18use crate::expr::{Column, ColumnKey, ExprKind, Value};
19use crate::render::{QuerySink, Sink, render_ident};
20use crate::scope::{BaseTable, Table};
21use crate::statement::{Statement, WrittenTable};
22use crate::update::Assignments;
23
24/// What a column's setter accepts, keyed by what that column's field
25/// holds: the column's own Rust type — `&str` for text — plus the `Option`
26/// a request struct already carries, wherever leaving the column out means
27/// something. What `None` means is the position's own: on an insert it is
28/// NULL for a nullable column and the schema's default for a defaulted one
29/// (`.<column>_null()` says the other, where a column is both); on an
30/// update it is *untouched*, since an `UPDATE` that says nothing about a
31/// column leaves it alone.
32#[diagnostic::on_unimplemented(
33 message = "`{Self}` isn't a value this column accepts",
34 label = "expected the column's own Rust type, or an `Option` of it"
35)]
36pub trait IntoColumnValue<V> {
37 fn into_column_value(self) -> V;
38}
39
40mod insertable {
41 /// Sealed like the other markers a derive emits. Unlike `Filled`, whose
42 /// doc explains why forging it buys nothing, forging this one turns a
43 /// bulk insert into a single `DEFAULT VALUES` — rows lost quietly — so
44 /// it gets the door even though a determined caller can still write it.
45 pub trait Sealed {}
46}
47
48#[doc(hidden)]
49pub use insertable::Sealed as InsertableSealed;
50
51/// A table with at least one column a statement may insert into. Emitted by
52/// `#[derive(Table)]` unless every column is generated, which leaves an
53/// `INSERT` with nothing to name: SQL spells that `DEFAULT VALUES`, and
54/// spells it for exactly one row.
55#[diagnostic::on_unimplemented(
56 message = "every column of `{Self}`'s table is generated, so only one row at a time can be inserted",
57 label = "`DEFAULT VALUES` is what SQL calls a row with nothing in it, and it names no columns to repeat",
58 note = "insert them one statement at a time"
59)]
60pub trait Insertable: InsertableSealed {}
61
62/// Proof that a builder's slot for column `C` holds that column's value.
63/// Deliberately unsealed, unlike `scope::Find`: forging it buys nothing,
64/// because `*Insert`'s fields are public and a complete row with a value of
65/// the caller's choosing is directly constructible. What the type-state
66/// builder prevents is *forgetting* a column, not choosing its value — and
67/// a seal here can't hold anyway, since the derive must implement this in
68/// the schema's own crate, where any nameable proof is nameable twice.
69/// `Missing<C>` doesn't implement it, which is what `build()` is bounded
70/// by — on the method rather than by the slot's type, so an incomplete row
71/// is a sentence naming the column rather than a missing `build`.
72#[diagnostic::on_unimplemented(
73 message = "column `{C}` hasn't been given a value yet",
74 label = "every column that is neither nullable nor defaulted needs one before `.build()`"
75)]
76pub trait Filled<C> {
77 #[doc(hidden)]
78 type Value;
79 #[doc(hidden)]
80 fn filled(self) -> Self::Value;
81}
82
83/// A column an `*Insert` builder hasn't been given a value for yet. Named
84/// after the column so the builder's type says which one is missing, rather
85/// than leaving a bare `()` to be counted by position.
86pub struct Missing<C>(std::marker::PhantomData<fn() -> C>);
87
88impl<C> Missing<C> {
89 #[doc(hidden)]
90 pub const fn new() -> Self {
91 Missing(std::marker::PhantomData)
92 }
93}
94
95impl<C> Default for Missing<C> {
96 fn default() -> Self {
97 Missing::new()
98 }
99}
100
101#[derive(Debug, Clone, PartialEq, Default)]
102pub enum Defaultable<T> {
103 #[default]
104 Default,
105 Value(T),
106}
107
108#[derive(Debug, Clone)]
109pub enum InsertValue {
110 Value(Value),
111 /// Renders as the bare `DEFAULT` keyword in the `VALUES` list.
112 Default,
113}
114
115impl<T: Into<Value>> From<Defaultable<T>> for InsertValue {
116 fn from(d: Defaultable<T>) -> Self {
117 match d {
118 Defaultable::Default => InsertValue::Default,
119 Defaultable::Value(v) => InsertValue::Value(v.into()),
120 }
121 }
122}
123
124/// Implemented by the `#[derive(Table)]`-generated `*Insert` struct for each
125/// table. One list of `(column, value)` pairs rather than a name list beside
126/// a value list, for the reason `select::AllColumns` carries one list: the
127/// seal is `#[doc(hidden)] pub` — the derive has to write it in the schema's
128/// own crate — so two lists that have to line up position for position
129/// could be made not to, and `INSERT INTO t (a, b, c) VALUES ($1)` is
130/// malformed whatever the table looks like. `update::UpdateRow::sets` has
131/// always had this shape.
132pub trait InsertRow: private::Sealed {
133 type Table: Table;
134
135 /// This row's columns *and* values as one chain: the keys spell the
136 /// statement's header, the cells carry what goes under them. One type,
137 /// because two lists reconciled at render time is the shape that made
138 /// every earlier version of this trait able to produce SQL malformed
139 /// for any table, or to drop a value silently — a `COLUMNS` const
140 /// beside positional values, then pairs matched against the first row's
141 /// names, then pairs matched against a declared header. A chain can
142 /// carry neither a surplus cell nor a missing one.
143 type Values: InsertValues;
144
145 fn into_values(self) -> Self::Values;
146}
147
148mod insert_values {
149 /// Sealed to the two shapes a chain has, so `Values` is always a real
150 /// one — the reason `row::ColumnNames` is sealed.
151 pub trait Sealed {}
152}
153
154/// One row's cells, in the order its chain declares them.
155fn collect_values<R: InsertRow>(row: R) -> Vec<InsertValue> {
156 let mut out = Vec::new();
157 row.into_values().push_values(&mut out);
158 out
159}
160
161/// A chain of `(column, value)` cells: `RowCons<C, InsertValue, Tail>` down
162/// to `RowNil`. Walked once for the header and once for each row's values,
163/// so the two cannot disagree.
164pub trait InsertValues: insert_values::Sealed {
165 #[doc(hidden)]
166 fn push_names(out: &mut Vec<&'static str>);
167 #[doc(hidden)]
168 fn push_values(self, out: &mut Vec<InsertValue>);
169}
170
171impl insert_values::Sealed for crate::row::RowNil {}
172
173impl InsertValues for crate::row::RowNil {
174 fn push_names(_out: &mut Vec<&'static str>) {}
175 fn push_values(self, _out: &mut Vec<InsertValue>) {}
176}
177
178impl<C: crate::row::Named, Tail: InsertValues> insert_values::Sealed
179 for crate::row::RowCons<C, InsertValue, Tail>
180{
181}
182
183impl<C: crate::row::Named, Tail: InsertValues> InsertValues
184 for crate::row::RowCons<C, InsertValue, Tail>
185{
186 fn push_names(out: &mut Vec<&'static str>) {
187 out.push(<C as crate::row::Named>::NAME);
188 Tail::push_names(out);
189 }
190
191 fn push_values(self, out: &mut Vec<InsertValue>) {
192 let (value, tail) = self.into_cell();
193 out.push(value);
194 tail.push_values(out);
195 }
196}
197
198/// The columns an `ON CONFLICT` target infers an index from: one or more,
199/// proven by `T` to belong to the table being inserted into, where a raw
200/// `&[&str]` would let a typo through to the database. Implemented for a
201/// bare `Column<C>` and for tuples of up to three; add arities as real
202/// schemas need them.
203#[diagnostic::on_unimplemented(
204 message = "`{Self}` isn't a column list for `{T}`",
205 label = "a column of that table, or a tuple of up to three of them"
206)]
207pub trait ConflictColumns<T: Table>: conflict_target::ColumnsSealed<T> {
208 #[doc(hidden)]
209 fn column_names(&self) -> Vec<&'static str>;
210}
211
212/// An `ON CONFLICT` target: the columns, and for a partial unique index the
213/// predicate that picks it. Implemented for everything `ConflictColumns`
214/// is, plus the [`partial_index`] those columns pass through.
215#[diagnostic::on_unimplemented(
216 message = "`{Self}` isn't an `ON CONFLICT` target for `{T}`",
217 label = "a column of that table, a tuple of up to three of them, or `partial_index(..)` of either"
218)]
219pub trait ConflictTarget<T: Table>: conflict_target::Sealed<T> {
220 #[doc(hidden)]
221 fn into_target(self) -> Target;
222}
223
224/// The rendered half of a conflict target: the columns a dialect infers an
225/// index from, and the `index_predicate` that picks a *partial* one.
226#[doc(hidden)]
227pub struct Target {
228 columns: Vec<&'static str>,
229 index_predicate: Option<ExprKind>,
230}
231
232mod conflict_target {
233 /// Sealed for the reason `InsertRow` is: a hand-written impl could name
234 /// a column that isn't there, and the point of taking `Column<C>`s is
235 /// that it can't. Both seals carry the trait's own table parameter — a
236 /// seal on `Self` alone leaves that table a free slot the caller fills
237 /// with their own type, which is all the orphan rule asks for, and
238 /// `ON CONFLICT ("nickname")` against a table without one is exactly
239 /// the typo the seal is here to stop.
240 pub trait ColumnsSealed<T> {}
241 pub trait Sealed<T> {}
242}
243
244impl<C: ColumnKey> conflict_target::ColumnsSealed<C::Table> for Column<C> {}
245impl<C: ColumnKey> conflict_target::Sealed<C::Table> for Column<C> {}
246
247impl<C: ColumnKey> ConflictColumns<C::Table> for Column<C> {
248 fn column_names(&self) -> Vec<&'static str> {
249 vec![C::NAME]
250 }
251}
252
253impl<C: ColumnKey> ConflictTarget<C::Table> for Column<C> {
254 fn into_target(self) -> Target {
255 Target {
256 columns: self.column_names(),
257 index_predicate: None,
258 }
259 }
260}
261
262macro_rules! conflict_target_tuple {
263 ($($name:ident),+) => {
264 // Elements constrained, or the seal admits a tuple of anything.
265 impl<T: Table, $($name: ColumnKey<Table = T>,)+> conflict_target::ColumnsSealed<T>
266 for ($(Column<$name>,)+) {}
267 impl<T: Table, $($name: ColumnKey<Table = T>,)+> conflict_target::Sealed<T>
268 for ($(Column<$name>,)+) {}
269
270 #[allow(non_snake_case)]
271 impl<T: Table, $($name: ColumnKey<Table = T>,)+> ConflictColumns<T> for ($(Column<$name>,)+) {
272 fn column_names(&self) -> Vec<&'static str> {
273 vec![$(<$name as crate::row::Named>::NAME),+]
274 }
275 }
276
277 impl<T: Table, $($name: ColumnKey<Table = T>,)+> ConflictTarget<T> for ($(Column<$name>,)+) {
278 fn into_target(self) -> Target {
279 Target {
280 columns: self.column_names(),
281 index_predicate: None,
282 }
283 }
284 }
285 };
286}
287// Columns, not nested targets: a conflict target is a list of columns, and
288// letting it nest is what made the documented limit of three not one.
289conflict_target_tuple!(A);
290conflict_target_tuple!(A, B);
291conflict_target_tuple!(A, B, C);
292
293/// `ON CONFLICT (a, b) WHERE deleted_at IS NULL` — the conflict target of a
294/// **partial** unique index.
295///
296/// A target of bare columns is matched against an index over exactly those
297/// columns whose own predicate the target's implies, and a target with no
298/// predicate implies only an index with none — so a partial index is
299/// unreachable without one. Implication, not equality: a predicate saying
300/// more than the index's still picks it. This is Postgres's
301/// `index_predicate`, and SQLite spells it the same way. It is only ever
302/// that: it does not filter which rows the conflict applies to, and where
303/// the columns also carry an unfiltered unique index that one still wins.
304///
305/// A predicate that implies no index at all is refused by the database
306/// rather than silently matching a different one.
307///
308/// ```ignore
309/// insert(members::Table)
310/// .values(row)
311/// .on_conflict_do_update(
312/// partial_index((members::team, members::handle), members::left_at.is_null()),
313/// assignments,
314/// )
315/// ```
316pub fn partial_index<T, Cols, E, Req, Idxs>(columns: Cols, index_predicate: E) -> PartialIndex<T>
317where
318 T: Table,
319 Cols: ConflictColumns<T>,
320 E: crate::expr::IntoExpr<Req = Req>,
321 E::Sql: crate::expr::BoolLike,
322 WrittenTable<T>: crate::scope::Superset<Req, Idxs>,
323{
324 PartialIndex {
325 target: Target {
326 columns: columns.column_names(),
327 index_predicate: Some(index_predicate.into_expr().kind),
328 },
329 _marker: PhantomData,
330 }
331}
332
333/// A conflict target narrowed to a partial unique index, from
334/// [`partial_index`]. It takes the columns rather than another target, so
335/// the predicate it carries is the only one there is.
336pub struct PartialIndex<T> {
337 target: Target,
338 _marker: PhantomData<fn() -> T>,
339}
340
341impl<T> conflict_target::Sealed<T> for PartialIndex<T> {}
342
343impl<T: Table> ConflictTarget<T> for PartialIndex<T> {
344 fn into_target(self) -> Target {
345 self.target
346 }
347}
348
349enum ConflictAction<T> {
350 DoNothing,
351 /// The same `SET` list `UPDATE` takes: an `*Update` value, or
352 /// `Assignments` of expressions.
353 ///
354 /// **Known limitation**: no `EXCLUDED.column` (`SET total = total +
355 /// EXCLUDED.total`) — the row being inserted isn't a table the scope
356 /// knows, so referring to it needs its own typed API. Everything else a
357 /// `SET` list can say, including expressions over the target's own
358 /// columns, works here.
359 ///
360 /// **Known limitation**: no `DO UPDATE SET .. WHERE ..` either. That
361 /// `WHERE` decides whether the update fires at all, which is a
362 /// different clause from the one [`partial_index`] carries — that one
363 /// only picks which index the conflict is inferred against.
364 DoUpdate(Assignments<T>),
365}
366
367struct ConflictClause<T> {
368 target: Target,
369 action: ConflictAction<T>,
370}
371
372fn render_conflict_clause<D: Dialect, T>(clause: &ConflictClause<T>, sink: &mut dyn Sink) {
373 sink.text(" ON CONFLICT (");
374 for (i, c) in clause.target.columns.iter().enumerate() {
375 if i > 0 {
376 sink.text(", ");
377 }
378 render_ident::<D>(sink, c);
379 }
380 sink.ch(')');
381 if let Some(predicate) = &clause.target.index_predicate {
382 sink.text(" WHERE ");
383 crate::render::render_expr::<D>(predicate, sink);
384 }
385 match &clause.action {
386 ConflictAction::DoNothing => sink.text(" DO NOTHING"),
387 ConflictAction::DoUpdate(sets) => {
388 sink.text(" DO UPDATE SET ");
389 sets.render_into::<D>(sink);
390 }
391 }
392}
393
394mod private {
395 /// The row's `(column, value)` pairs are what a statement writes;
396 /// `#[derive(Table)]` is what guarantees that, so it is the only thing
397 /// that can produce an `InsertRow`.
398 pub trait Sealed {}
399}
400
401#[doc(hidden)]
402pub use private::Sealed as InsertRowSealed;
403
404pub struct InsertSeed<D, T> {
405 _marker: PhantomData<fn() -> (D, T)>,
406}
407
408pub fn insert<D, T: BaseTable>(_table: T) -> InsertSeed<D, T> {
409 InsertSeed {
410 _marker: PhantomData,
411 }
412}
413
414impl<D, T: Table> InsertSeed<D, T> {
415 pub fn values<R: InsertRow<Table = T>>(self, row: R) -> Insert<D, R> {
416 Insert {
417 rows: vec![collect_values(row)],
418 on_conflict: None,
419 _marker: PhantomData,
420 }
421 }
422
423 /// `INSERT INTO t (..) SELECT ..` — the rows a query produces, checked
424 /// against the target's own row by `row::SameShape`, the same one
425 /// comparison a `UNION` branch and a CTE body go through.
426 ///
427 /// The query fills every column the target lets a statement write: all
428 /// of them but the generated ones, which the database writes itself and
429 /// refuses a value for. `SameShape` compares name and type cell by
430 /// cell, so the source's columns must be spelled and typed as the
431 /// target's — SQL would widen an `INTEGER` into a `BIGINT` and take a
432 /// NOT NULL value for a nullable column, and neither is accepted here.
433 /// A source column under another name takes a `label!{}` one.
434 ///
435 /// **Known limitations**: the source is a `Select`, so a `SetOp`
436 /// (`UNION`) or a `DynSelect` cannot be one; a one-column target still
437 /// needs a one-tuple (`select((t::only,))`), since a bare selection is
438 /// a value rather than a row.
439 pub fn select<Scope, Sel, SelIdx, TgtIdx>(
440 self,
441 query: &crate::select::Select<D, Scope, Sel>,
442 ) -> InsertSelect<D, T>
443 where
444 D: Dialect,
445 T: WrittenColumns,
446 T::Columns: crate::select::ColumnList<WrittenTable<T>, TgtIdx>,
447 TargetRow<T, TgtIdx>: crate::row::ColumnNames,
448 Sel: crate::select::Selection<Scope, SelIdx>,
449 Sel::Output: crate::row::SameShape<crate::row::Row<TargetRow<T, TgtIdx>>>,
450 {
451 InsertSelect {
452 // Read off the very row the query was checked against, the way
453 // a `WITH` header is: one fact rather than two that could name
454 // different columns.
455 header: <TargetRow<T, TgtIdx> as crate::row::ColumnNames>::names(),
456 body: query.fragment::<SelIdx>(),
457 _marker: PhantomData,
458 }
459 }
460
461 /// Every row of a collection at once — the shape a bulk import has,
462 /// where the rows are already in a `Vec` and the first one isn't
463 /// special. `INSERT` with no rows has no SQL form, so an empty
464 /// collection is refused here rather than rendered.
465 pub fn values_all<R: InsertRow<Table = T> + Insertable>(
466 self,
467 rows: impl IntoIterator<Item = R>,
468 ) -> Result<Insert<D, R>, NothingToInsert> {
469 let rows: Vec<_> = rows.into_iter().map(collect_values).collect();
470 if rows.is_empty() {
471 return Err(NothingToInsert);
472 }
473 Ok(Insert {
474 rows,
475 on_conflict: None,
476 _marker: PhantomData,
477 })
478 }
479}
480
481/// The columns of a table an `INSERT` may name: all of them but the
482/// generated ones, which the database writes itself and refuses a value
483/// for. Emitted by `#[derive(Table)]` beside `select::AllColumns`, which is
484/// the other list — what a `SELECT` of the whole table reads.
485#[doc(hidden)]
486pub trait WrittenColumns {
487 /// `Cons<Column<C>, ..>`, in the schema's own order.
488 type Columns;
489}
490
491/// The row an `INSERT INTO t (..) SELECT ..` has to be handed: the target's
492/// writable columns, read in the one-table scope a write statement has.
493type TargetRow<T, Idx> = <<T as WrittenColumns>::Columns as crate::select::ColumnList<
494 WrittenTable<T>,
495 Idx,
496>>::Fields<crate::row::RowNil>;
497
498/// `INSERT INTO t (..) SELECT ..` — rows a query produces rather than rows
499/// a caller holds. From [`InsertSeed::select`].
500///
501/// The header is the target's own writable columns, so the two sides line
502/// up by the target's order rather than by whatever order its
503/// `CREATE TABLE` happened to use. The body is a `render::Fragment`,
504/// rendered before the statement knows how many parameters precede it, for
505/// the reason a CTE body is one.
506///
507/// **Known limitation**: no `ON CONFLICT` on this shape, and no column
508/// subset — the query fills every column the target lets one write.
509pub struct InsertSelect<D, T> {
510 header: Vec<&'static str>,
511 body: crate::render::Fragment,
512 _marker: PhantomData<fn() -> (D, T)>,
513}
514
515impl<D: Dialect, T: Table> crate::statement::private::Sealed for InsertSelect<D, T> {}
516
517impl<D: Dialect, T: Table> Statement for InsertSelect<D, T> {
518 type Dialect = D;
519 type Table = T;
520 fn render(&self) -> QuerySink<D> {
521 let mut sink = QuerySink::<D>::new();
522 sink.text("INSERT INTO ");
523 render_ident::<D>(&mut sink, T::NAME);
524 sink.text(" (");
525 for (i, name) in self.header.iter().enumerate() {
526 if i > 0 {
527 sink.text(", ");
528 }
529 render_ident::<D>(&mut sink, name);
530 }
531 sink.text(") ");
532 self.body.splice_into(&mut sink);
533 sink
534 }
535}
536
537/// An `INSERT` was given no rows at all. Returned rather than panicked for
538/// the reason `update::NothingToSet` gives: an empty collection is ordinary
539/// request-shaped data, and the caller decides whether it is a no-op or an
540/// error.
541#[derive(Debug, Clone, Copy, PartialEq, Eq)]
542pub struct NothingToInsert;
543
544impl std::fmt::Display for NothingToInsert {
545 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
546 f.write_str("an INSERT must have at least one row, but no rows were given")
547 }
548}
549impl std::error::Error for NothingToInsert {}
550
551fn render_values_clause<D: Dialect, R: InsertRow>(
552 rows: &[Vec<InsertValue>],
553 on_conflict: &Option<ConflictClause<R::Table>>,
554) -> QuerySink<D> {
555 let mut sink = QuerySink::<D>::new();
556 sink.text("INSERT INTO ");
557 render_ident::<D>(&mut sink, <R::Table as Table>::NAME);
558
559 // Header and values come from one chain, so a row has exactly one cell
560 // per column named — no reconciliation, nothing to drop.
561 let mut header = Vec::new();
562 <R::Values as InsertValues>::push_names(&mut header);
563
564 // A table whose every column is generated leaves nothing to name, and
565 // an empty column list is a syntax error in two of the three dialects.
566 // One such row is all SQL can express, which is why `values`/`values_all`
567 // take `Insertable`.
568 if header.is_empty() {
569 sink.text(D::INSERT_NO_COLUMNS);
570 if let Some(clause) = on_conflict {
571 render_conflict_clause::<D, _>(clause, &mut sink);
572 }
573 return sink;
574 }
575
576 sink.text(" (");
577 for (i, name) in header.iter().enumerate() {
578 if i > 0 {
579 sink.text(", ");
580 }
581 render_ident::<D>(&mut sink, name);
582 }
583 sink.text(") VALUES ");
584
585 for (row_i, row) in rows.iter().enumerate() {
586 if row_i > 0 {
587 sink.text(", ");
588 }
589 sink.ch('(');
590 for (i, v) in row.iter().enumerate() {
591 if i > 0 {
592 sink.text(", ");
593 }
594 match v {
595 InsertValue::Default => sink.text("DEFAULT"),
596 InsertValue::Value(v) => sink.bind(v),
597 }
598 }
599 sink.ch(')');
600 }
601
602 if let Some(clause) = on_conflict {
603 render_conflict_clause::<D, _>(clause, &mut sink);
604 }
605
606 sink
607}
608
609pub struct Insert<D, R: InsertRow> {
610 rows: Vec<Vec<InsertValue>>,
611 on_conflict: Option<ConflictClause<R::Table>>,
612 _marker: PhantomData<fn() -> (D, R)>,
613}
614
615impl<D, R: InsertRow + Insertable> Insert<D, R> {
616 /// Bulk insert: add another row to the same statement.
617 pub fn values(mut self, row: R) -> Self {
618 self.rows.push(collect_values(row));
619 self
620 }
621
622 /// The same for a collection. Infallible, unlike the seed's: this
623 /// statement already has a row, so an empty collection adds nothing
624 /// rather than describing an `INSERT` with nothing in it.
625 pub fn values_all(mut self, rows: impl IntoIterator<Item = R>) -> Self {
626 self.rows.extend(rows.into_iter().map(collect_values));
627 self
628 }
629}
630
631impl<D: Dialect, R: InsertRow> Insert<D, R> {
632 /// `ON CONFLICT (..) DO NOTHING`. Pass [`partial_index`] where the
633 /// index to infer is a partial one.
634 pub fn on_conflict_do_nothing(mut self, target: impl ConflictTarget<R::Table>) -> Self
635 where
636 D: SupportsOnConflict,
637 {
638 self.on_conflict = Some(ConflictClause {
639 target: target.into_target(),
640 action: ConflictAction::DoNothing,
641 });
642 self
643 }
644
645 /// `ON CONFLICT (..) DO UPDATE SET ..`, taking the same `Assignments`
646 /// an `UPDATE` sets. Pass [`partial_index`] where the index to infer is
647 /// a partial one.
648 pub fn on_conflict_do_update(
649 mut self,
650 target: impl ConflictTarget<R::Table>,
651 set: Assignments<R::Table>,
652 ) -> Self
653 where
654 D: SupportsOnConflict,
655 {
656 self.on_conflict = Some(ConflictClause {
657 target: target.into_target(),
658 action: ConflictAction::DoUpdate(set),
659 });
660 self
661 }
662}
663
664impl<D: Dialect, R: InsertRow> crate::statement::private::Sealed for Insert<D, R> {}
665
666impl<D: Dialect, R: InsertRow> Statement for Insert<D, R> {
667 type Dialect = D;
668 type Table = R::Table;
669 fn render(&self) -> QuerySink<D> {
670 render_values_clause::<D, R>(&self.rows, &self.on_conflict)
671 }
672}