use super::{List, Statement};
use std::marker::PhantomData;
use toasty_core::stmt;
pub trait IntoStatement {
type Returning;
fn into_statement(self) -> Statement<Self::Returning>;
}
macro_rules! impl_into_statement_for_tuple {
( $( $Q:ident ),+ ; $n:tt ; $( $idx:tt ),+ ) => {
impl< $( $Q: IntoStatement ),+ > IntoStatement for ( $( $Q, )+ ) {
type Returning = ( $( $Q::Returning, )+ );
fn into_statement(self) -> Statement<Self::Returning> {
let exprs: Vec<stmt::Expr> = vec![
$( {
let mut untyped = self.$idx.into_statement().untyped;
ensure_batch_returning(&mut untyped);
stmt::Expr::stmt(untyped)
}, )+
];
let query = stmt::Query::new_single(
stmt::Values::from(stmt::Expr::record(exprs)),
);
Statement {
untyped: query.into(),
_p: PhantomData,
}
}
}
};
}
impl_into_statement_for_tuple!(Q1, Q2; 2; 0, 1);
impl_into_statement_for_tuple!(Q1, Q2, Q3; 3; 0, 1, 2);
impl_into_statement_for_tuple!(Q1, Q2, Q3, Q4; 4; 0, 1, 2, 3);
impl_into_statement_for_tuple!(Q1, Q2, Q3, Q4, Q5; 5; 0, 1, 2, 3, 4);
impl_into_statement_for_tuple!(Q1, Q2, Q3, Q4, Q5, Q6; 6; 0, 1, 2, 3, 4, 5);
impl_into_statement_for_tuple!(Q1, Q2, Q3, Q4, Q5, Q6, Q7; 7; 0, 1, 2, 3, 4, 5, 6);
impl_into_statement_for_tuple!(Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8; 8; 0, 1, 2, 3, 4, 5, 6, 7);
fn ensure_batch_returning(stmt: &mut stmt::Statement) {
if !stmt.is_query() && stmt.returning().is_none() {
stmt.set_returning(stmt::Returning::Value(stmt::Expr::record::<stmt::Expr>([])));
}
}
fn batch_from_iter<Q: IntoStatement>(
iter: impl Iterator<Item = Q>,
) -> Statement<List<Q::Returning>> {
let exprs: Vec<stmt::Expr> = iter
.map(|q| {
let mut untyped = q.into_statement().untyped;
ensure_batch_returning(&mut untyped);
stmt::Expr::stmt(untyped)
})
.collect();
let query = stmt::Query::new_single(stmt::Values::from(stmt::Expr::record(exprs)));
Statement {
untyped: query.into(),
_p: PhantomData,
}
}
impl<Q: IntoStatement> IntoStatement for Vec<Q> {
type Returning = List<Q::Returning>;
fn into_statement(self) -> Statement<Self::Returning> {
batch_from_iter(self.into_iter())
}
}
impl<Q: IntoStatement, const N: usize> IntoStatement for [Q; N] {
type Returning = List<Q::Returning>;
fn into_statement(self) -> Statement<Self::Returning> {
batch_from_iter(self.into_iter())
}
}