Skip to main content

diesel/query_builder/returning/
returning_query_source.rs

1//! The `ReturningQuerySource<StmtKind, T>` wrapper used to type-check `RETURNING`
2//! clauses, the statement-kind markers it is parameterized over, and the
3//! [`InsertStmtKind`] dispatch trait.
4//!
5//! This module holds the items needed to type-check `RETURNING` clauses that are not specific
6//! to a particular backend.
7
8use crate::expression::{AppearsOnTable, BoxableExpression, Expression, SelectableExpression};
9use crate::query_source::joins::ToInnerJoin;
10use crate::query_source::{AppearsInFromClause, Never, QueryRelation, QuerySource, TableNotEqual};
11use alloc::boxed::Box;
12use core::marker::PhantomData;
13
14/// Statement-kind marker
15#[derive(#[automatically_derived]
impl ::core::fmt::Debug for InsertStmtWithoutOnConflictDoUpdate {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            "InsertStmtWithoutOnConflictDoUpdate")
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for InsertStmtWithoutOnConflictDoUpdate { }Copy, #[automatically_derived]
impl ::core::clone::Clone for InsertStmtWithoutOnConflictDoUpdate {
    #[inline]
    fn clone(&self) -> InsertStmtWithoutOnConflictDoUpdate { *self }
}Clone)]
16pub struct InsertStmtWithoutOnConflictDoUpdate;
17
18/// Statement-kind marker
19#[derive(#[automatically_derived]
impl ::core::fmt::Debug for UpdateStmt {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "UpdateStmt")
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for UpdateStmt { }Copy, #[automatically_derived]
impl ::core::clone::Clone for UpdateStmt {
    #[inline]
    fn clone(&self) -> UpdateStmt { *self }
}Clone)]
20pub struct UpdateStmt;
21
22/// Statement-kind marker
23#[derive(#[automatically_derived]
impl ::core::fmt::Debug for DeleteStmt {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "DeleteStmt")
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for DeleteStmt { }Copy, #[automatically_derived]
impl ::core::clone::Clone for DeleteStmt {
    #[inline]
    fn clone(&self) -> DeleteStmt { *self }
}Clone)]
24pub struct DeleteStmt;
25
26/// Statement-kind marker
27#[derive(#[automatically_derived]
impl ::core::fmt::Debug for InsertStmtWithOnConflictDoUpdate {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            "InsertStmtWithOnConflictDoUpdate")
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for InsertStmtWithOnConflictDoUpdate { }Copy, #[automatically_derived]
impl ::core::clone::Clone for InsertStmtWithOnConflictDoUpdate {
    #[inline]
    fn clone(&self) -> InsertStmtWithOnConflictDoUpdate { *self }
}Clone)]
28pub struct InsertStmtWithOnConflictDoUpdate;
29
30/// Synthetic query source used as the `QS` parameter of
31/// [`SelectableExpression`](crate::expression::SelectableExpression) /
32/// [`AppearsOnTable`](crate::expression::AppearsOnTable) when type-checking
33/// `RETURNING` clauses.
34///
35/// `StmtKind` is one of the marker structs above; `T` is the table that the
36/// `INSERT`/`UPDATE`/`DELETE` is acting on.
37#[derive(#[automatically_derived]
impl<StmtKind: ::core::fmt::Debug, T: ::core::fmt::Debug> ::core::fmt::Debug
    for ReturningQuerySource<StmtKind, T> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "ReturningQuerySource", &&self.0)
    }
}Debug, #[automatically_derived]
impl<StmtKind: ::core::clone::Clone, T: ::core::clone::Clone>
    ::core::clone::Clone for ReturningQuerySource<StmtKind, T> {
    #[inline]
    fn clone(&self) -> ReturningQuerySource<StmtKind, T> {
        ReturningQuerySource(::core::clone::Clone::clone(&self.0))
    }
}Clone, #[automatically_derived]
impl<StmtKind: ::core::marker::Copy, T: ::core::marker::Copy>
    ::core::marker::Copy for ReturningQuerySource<StmtKind, T> {
}Copy)]
38pub struct ReturningQuerySource<StmtKind, T>(PhantomData<(StmtKind, T)>);
39
40impl<StmtKind, T> QuerySource for ReturningQuerySource<StmtKind, T>
41where
42    T: QuerySource + Default,
43    T::DefaultSelection: SelectableExpression<Self>,
44{
45    type FromClause = T::FromClause;
46    type DefaultSelection = T::DefaultSelection;
47
48    fn from_clause(&self) -> Self::FromClause {
49        T::default().from_clause()
50    }
51
52    fn default_selection(&self) -> Self::DefaultSelection {
53        T::default().default_selection()
54    }
55}
56
57impl<StmtKind, T1, T2> AppearsInFromClause<T1> for ReturningQuerySource<StmtKind, T2>
58where
59    T1: TableNotEqual<T2> + QueryRelation,
60    T2: QueryRelation,
61{
62    type Count = Never;
63}
64// For typechecking of `old(column).nullable()`
65
66impl<T> ToInnerJoin for ReturningQuerySource<UpdateStmt, T> {
67    type InnerJoin = Self;
68}
69
70impl<T> ToInnerJoin for ReturningQuerySource<DeleteStmt, T> {
71    type InnerJoin = Self;
72}
73
74impl<T> ToInnerJoin for ReturningQuerySource<InsertStmtWithoutOnConflictDoUpdate, T> {
75    type InnerJoin = Self;
76}
77
78// `InsertStmtWithOnConflictDoUpdate` maps to `UpdateStmt`. This is what makes
79// `Nullable<Old<C>>: SelectableExpression<ReturningQuerySource<InsertStmtWithOnConflictDoUpdate, _>>`
80// resolve through the existing
81// `impl<T, QS> SelectableExpression<QS> for Nullable<T>
82//     where QS: ToInnerJoin, T: SelectableExpression<QS::InnerJoin>` impl
83// (see `crate::expression::nullable::Nullable`): that bound reduces to
84// `Old<C>: SelectableExpression<ReturningQuerySource<UpdateStmt, _>>`, which
85// holds, while the bare `Old<C>: SelectableExpression<ReturningQuerySource<InsertStmtWithOnConflictDoUpdate, _>>`
86// is intentionally *not* implemented — forcing users to write
87// `old(col).nullable()` in `ON CONFLICT ... DO UPDATE` for type safety.
88impl<T> ToInnerJoin for ReturningQuerySource<InsertStmtWithOnConflictDoUpdate, T> {
89    type InnerJoin = ReturningQuerySource<UpdateStmt, T>;
90}
91
92/// Maps an `InsertStatement` `Values` shape to the statement-kind marker that
93/// should be used when type-checking that statement's `RETURNING` clause.
94///
95/// This is what makes `RETURNING old(col)` accept `INSERT ... ON CONFLICT
96/// ... DO UPDATE` (where the marker is [`InsertStmtWithOnConflictDoUpdate`], for
97/// which `Nullable<Old<C>>` is a valid `RETURNING` element) but reject plain
98/// `INSERT` (where the marker is [`InsertStmtWithoutOnConflictDoUpdate`], for which `Old<C>` does not
99/// implement `SelectableExpression`).
100///
101/// The trait is sealed in spirit — it only has impls for the values shapes
102/// `diesel` itself produces — but it is exposed publicly under the
103/// `i-implement-a-third-party-backend-and-opt-into-breaking-changes` feature
104/// so third-party backends that introduce new values shapes can add their own
105/// impls.
106pub trait InsertStmtKind {
107    /// The statement-kind marker (see e.g. [`InsertStmtWithoutOnConflictDoUpdate`],
108    /// [`InsertStmtWithOnConflictDoUpdate`]) used as the `StmtKind` parameter of
109    /// [`ReturningQuerySource`] for `INSERT` statements with this `Values`
110    /// shape.
111    type StmtKind;
112}
113
114impl<T, Tab> InsertStmtKind for crate::query_builder::ValuesClause<T, Tab> {
115    type StmtKind = InsertStmtWithoutOnConflictDoUpdate;
116}
117
118impl<V, Tab, QId, const STABLE_QUERY_ID: bool> InsertStmtKind
119    for crate::query_builder::BatchInsert<V, Tab, QId, STABLE_QUERY_ID>
120{
121    type StmtKind = InsertStmtWithoutOnConflictDoUpdate;
122}
123
124impl InsertStmtKind for crate::query_builder::insert_statement::DefaultValues {
125    type StmtKind = InsertStmtWithoutOnConflictDoUpdate;
126}
127
128impl<S, C> InsertStmtKind for crate::query_builder::insert_statement::InsertFromSelect<S, C> {
129    type StmtKind = InsertStmtWithoutOnConflictDoUpdate;
130}
131
132impl<V, Target, T, WhereClause> InsertStmtKind
133    for crate::query_builder::upsert::on_conflict_clause::OnConflictValues<
134        V,
135        Target,
136        crate::query_builder::upsert::on_conflict_actions::DoNothing<T>,
137        WhereClause,
138    >
139{
140    // ON CONFLICT DO NOTHING does not return the lines that conflicted if using RETURNING
141    // so it's unnecessary (and would even be misleading) to allow RETURNING old.xxx
142    // in this case.
143    type StmtKind = InsertStmtWithoutOnConflictDoUpdate;
144}
145
146impl<V, Target, Changeset, Tab, WhereClause> InsertStmtKind
147    for crate::query_builder::upsert::on_conflict_clause::OnConflictValues<
148        V,
149        Target,
150        crate::query_builder::upsert::on_conflict_actions::DoUpdate<Changeset, Tab>,
151        WhereClause,
152    >
153{
154    type StmtKind = InsertStmtWithOnConflictDoUpdate;
155}
156
157/// Make `Box<dyn BoxableExpression<table>>` be `SelectableExpression` in returning clauses.
158/// This is necessary for backwards-compatibility.
159///
160/// Unfortunately we cannot implement this directly for `dyn BoxableExpression`
161/// (and rely on our existing generic impls for `Box<T>`) because the compiler
162/// complains that there is already an automatic implementation of `SelectableExpression` for
163/// `dyn BoxableExpression`, even though the `QS` type is different.
164/// As a workaround, we implement it for `Box<dyn BoxableExpression<table>>`, which should
165/// cover for most users.
166impl<'a, QS, ST, DB, GB, IsAggregate, StmtKind>
167    SelectableExpression<ReturningQuerySource<StmtKind, QS>>
168    for Box<dyn BoxableExpression<QS, DB, GB, IsAggregate, SqlType = ST> + 'a>
169where
170    Box<dyn BoxableExpression<QS, DB, GB, IsAggregate, SqlType = ST> + 'a>: Expression,
171{
172}
173/// See comment on `SelectableExpression` impl above.
174impl<'a, QS, ST, DB, GB, IsAggregate, StmtKind> AppearsOnTable<ReturningQuerySource<StmtKind, QS>>
175    for Box<dyn BoxableExpression<QS, DB, GB, IsAggregate, SqlType = ST> + 'a>
176where
177    Box<dyn BoxableExpression<QS, DB, GB, IsAggregate, SqlType = ST> + 'a>: Expression,
178{
179}