Skip to main content

qbrs_core/
statement.rs

1//! What `INSERT`, `UPDATE` and `DELETE` have in common: they write to one
2//! table, and any of them can be asked for the rows it touched.
3
4use std::marker::PhantomData;
5
6use crate::dialect::{Dialect, SupportsReturning};
7use crate::expr::Value;
8use crate::render::{QuerySink, SelectItem, Sink, render_select_list};
9use crate::scope::{Cons, Nil, NotNull, Table, TableSlot};
10use crate::select::Selection;
11
12/// A statement that writes to a single table. Sealed: the three writing
13/// statements are the whole set, and `Returning` is defined against this
14/// rather than against each of them.
15pub trait Statement: private::Sealed {
16    type Dialect: Dialect;
17    type Table: Table;
18
19    #[doc(hidden)]
20    fn render(&self) -> QuerySink<Self::Dialect>;
21
22    /// The dialect is an argument for the reason `Select::to_sql`'s is.
23    fn to_sql(&self, _dialect: Self::Dialect) -> (String, Vec<Value>) {
24        self.render().finish()
25    }
26
27    /// `RETURNING`, on whichever of the three this is — the clause is the
28    /// same clause. A distinct type rather than `Self` with a flag set: the
29    /// execution layer needs `Sel`'s concrete type to know what to decode a
30    /// returned row into, and an optional field would erase it.
31    fn returning<Sel, Idx>(self, sel: Sel) -> Returning<Self, Sel>
32    where
33        Self: Sized,
34        Self::Dialect: SupportsReturning,
35        Sel: Selection<WrittenTable<Self::Table>, Idx>,
36    {
37        Returning {
38            returning: sel.items(),
39            statement: self,
40            _marker: PhantomData,
41        }
42    }
43}
44
45pub(crate) mod private {
46    pub trait Sealed {}
47}
48
49/// The scope a `RETURNING` clause is checked against: the table being
50/// written to, and nothing else.
51pub type WrittenTable<T> = Cons<TableSlot<T, NotNull>, Nil>;
52
53/// `<statement> RETURNING <selection>`. A distinct type rather than a flag
54/// on the statement, because `Sel` has to survive to the point rows are
55/// decoded — and one type rather than three, because the clause is the same
56/// clause whichever statement it follows.
57pub struct Returning<S, Sel> {
58    pub(crate) statement: S,
59    pub(crate) returning: Vec<SelectItem>,
60    pub(crate) _marker: PhantomData<fn() -> Sel>,
61}
62
63impl<S: Statement, Sel> Returning<S, Sel> {
64    pub fn to_sql(&self, _dialect: S::Dialect) -> (String, Vec<Value>) {
65        let mut sink = self.statement.render();
66        sink.text(" RETURNING ");
67        render_select_list::<S::Dialect>(&self.returning, &mut sink);
68        sink.finish()
69    }
70}