Skip to main content

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}