use std::fmt::Display;
use crate::postgres::general::{Expression, TableName};
use crate::postgres::statements::{
delete_from_with, insert_into_with, select_with, update_with, BareInsertInto, BareUpdate,
DeleteFrom, InsertInto, Select, Update, Values,
};
use crate::tools::{joined, IntoIteratorOfSameType};
use super::Column;
pub fn with(name: impl Into<TableName>) -> WithQueryBuilder {
WithQueryBuilder {
clause: WithClause::new(),
name: name.into(),
columns: Vec::new(),
}
}
#[derive(Debug, Clone, Default)]
pub struct WithClause {
queries: Vec<WithQuery>,
}
impl WithClause {
fn new() -> WithClause {
WithClause {
queries: Vec::new(),
}
}
pub fn and_with(self, name: impl Into<TableName>) -> WithQueryBuilder {
WithQueryBuilder {
clause: self,
name: name.into(),
columns: Vec::new(),
}
}
pub fn select(self, expressions: impl IntoIteratorOfSameType<Expression>) -> Select {
select_with(expressions.into_some_iter().collect(), self)
}
pub fn delete_from(self, table_name: impl Into<TableName>) -> DeleteFrom {
delete_from_with(table_name.into(), self)
}
pub fn update(self, table_name: impl Into<TableName>) -> BareUpdate {
update_with(table_name.into(), self)
}
pub fn insert_into(self, table_name: impl Into<TableName>) -> BareInsertInto {
insert_into_with(table_name.into(), self)
}
}
impl Display for WithClause {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "WITH {}", joined(&self.queries, ", "))
}
}
#[derive(Debug, Clone)]
pub struct WithQuery {
name: TableName,
columns: Vec<Column>,
as_: String,
}
impl Display for WithQuery {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)?;
if !self.columns.is_empty() {
write!(f, "({})", joined(&self.columns, ", "))?;
}
write!(f, " AS ({})", self.as_)?;
Ok(())
}
}
#[derive(Debug)]
pub struct WithQueryBuilder {
clause: WithClause,
name: TableName,
columns: Vec<Column>,
}
impl WithQueryBuilder {
pub fn columns(mut self, columns: impl IntoIteratorOfSameType<Column>) -> WithQueryBuilder {
self.columns.extend(columns.into_some_iter());
self
}
pub fn as_(mut self, target: impl UsableInWithQuery) -> WithClause {
self.clause.queries.push(WithQuery {
name: self.name,
columns: self.columns,
as_: target.to_string(),
});
self.clause
}
}
pub trait UsableInWithQuery: Display {}
impl UsableInWithQuery for Select {}
impl<V: Values> UsableInWithQuery for InsertInto<V> {}
impl UsableInWithQuery for Update {}
impl UsableInWithQuery for DeleteFrom {}