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