use std::marker::PhantomData;
use crate::dialect::{Dialect, SupportsDataModifyingCte};
use crate::render::{Fragment, FragmentSink, Sink};
use crate::row::{Row, SameShape};
use crate::scope::Table;
use crate::select::{Select, Selection};
use crate::statement::{Returning, Statement, WrittenTable};
#[diagnostic::on_unimplemented(
message = "`{Self}` isn't a `with!{{}}` pseudo-table",
label = "only a `with!{{}}`-declared name can be bound as a CTE",
note = "a schema table is already a table — it is selected from directly, with no `WITH` clause to bind"
)]
pub trait CteShape: Table + crate::select::SelectableSealed {
type Row: crate::row::ColumnNames;
}
pub struct Cte<D, Marker> {
body: Fragment,
_marker: PhantomData<fn() -> (D, Marker)>,
}
impl<D, Marker> Cte<D, Marker> {
pub(crate) fn into_body(self) -> Fragment {
self.body
}
}
impl<D, Marker> Clone for Cte<D, Marker> {
fn clone(&self) -> Self {
Cte {
body: self.body.clone(),
_marker: PhantomData,
}
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` isn't something a `WITH` clause can bind",
label = "a `SELECT`, or a write statement with `.returning(..)` on a dialect that has data-modifying CTEs",
note = "an `INSERT`/`UPDATE`/`DELETE` body is Postgres's alone, and needs the `RETURNING` that gives the CTE its columns"
)]
pub trait CteBody<D, Idx>: cte_body::Sealed<D, Idx> {
type Output;
#[doc(hidden)]
fn render_body(&self, sink: &mut dyn Sink);
}
mod cte_body {
pub trait Sealed<D, Idx> {}
}
impl<D: Dialect, Scope, Sel: Selection<Scope, Idx>, Idx> cte_body::Sealed<D, Idx>
for Select<D, Scope, Sel>
{
}
impl<D: Dialect, Scope, Sel: Selection<Scope, Idx>, Idx> CteBody<D, Idx> for Select<D, Scope, Sel> {
type Output = Sel::Output;
fn render_body(&self, sink: &mut dyn Sink) {
Select::render_body_into::<Idx>(self, sink);
}
}
impl<D, S, Sel, Idx> cte_body::Sealed<D, Idx> for Returning<S, Sel>
where
D: SupportsDataModifyingCte,
S: Statement<Dialect = D>,
Sel: Selection<WrittenTable<S::Table>, Idx>,
{
}
impl<D, S, Sel, Idx> CteBody<D, Idx> for Returning<S, Sel>
where
D: SupportsDataModifyingCte,
S: Statement<Dialect = D>,
Sel: Selection<WrittenTable<S::Table>, Idx>,
{
type Output = Sel::Output;
fn render_body(&self, sink: &mut dyn Sink) {
Returning::render_into(self, sink);
}
}
pub fn with<D: Dialect, Marker: CteShape, Body, Idx>(_marker: Marker, body: &Body) -> Cte<D, Marker>
where
Body: CteBody<D, Idx>,
Body::Output: SameShape<Row<Marker::Row>>,
{
let mut sink = FragmentSink::new();
body.render_body(&mut sink);
Cte {
body: sink.finish(),
_marker: PhantomData,
}
}