use crate::Syntax;
use crate::model_traits::Column;
use crate::model_traits::TableIdent;
use crate::query::clause::ClauseAdder;
use crate::query::clause::OrderBy;
use crate::query::clause::ParamArgs;
use crate::query::clause::exists::ExistIn;
use crate::query::helpers::{build_where, join_sql_parts};
use crate::query::tail;
use crate::writers::ColumnWriter;
use crate::writers::CountWriter;
use crate::writers::NextParam;
use crate::writers::TableWriter;
use crate::writers::alias::TableAlias;
use std::sync::Arc;
pub struct SelectWriter {
syntax: Syntax,
table_ident: TableIdent,
tablealias: String,
}
impl SelectWriter {
pub fn new(syntax: Syntax, table_ident: &TableIdent) -> Self {
let ta = TableAlias::new();
Self {
syntax,
table_ident: table_ident.clone(),
tablealias: ta.next(),
}
}
pub fn new_with_alias(
syntax: Syntax,
table_ident: &TableIdent,
alias: impl Into<String>,
) -> Self {
Self {
syntax,
table_ident: table_ident.clone(),
tablealias: alias.into(),
}
}
pub fn sql_count<'lam, 'exist, 'args, 'p>(
&self,
wheres: &'lam [Arc<Box<dyn ClauseAdder>>],
exist_ins: &'exist [ExistIn],
limit: &Option<i64>,
offset: &Option<i64>,
orders: &[OrderBy],
args: &'args mut Option<ParamArgs<'p>>,
) -> String
where
'lam: 'p,
'exist: 'p,
{
let next_params = NextParam::new(self.syntax);
join_sql_parts(&[
build_head_count(&self.table_ident, &self.tablealias, self.syntax),
build_where(
self.syntax,
&next_params,
&self.tablealias,
wheres,
args,
exist_ins,
),
tail::write(self.syntax, limit, offset, orders, &self.tablealias),
])
}
pub fn sql<'col, 'lam, 'exist, 'args, 'p>(
&self,
columns: &'col [Column],
wheres: &'lam [Arc<Box<dyn ClauseAdder>>],
exist_ins: &'exist [ExistIn],
limit: &Option<i64>,
offset: &Option<i64>,
orders: &[OrderBy],
args: &'args mut Option<ParamArgs<'p>>,
) -> String
where
'lam: 'p,
'exist: 'p,
{
let next_params = NextParam::new(self.syntax);
join_sql_parts(&[
build_head_select(self.syntax, &self.table_ident, &self.tablealias, columns),
build_where(
self.syntax,
&next_params,
&self.tablealias,
wheres,
args,
exist_ins,
),
tail::write(self.syntax, limit, offset, orders, &self.tablealias),
])
}
}
fn build_head_count(table: &TableIdent, tablealias: &str, syntax: Syntax) -> Option<String> {
let tn = TableWriter::new(syntax).write(table);
let identifier = format!("{} {}", tn, &tablealias);
let cw = CountWriter::new(syntax);
let count_star = cw.count(Some(tablealias), Some("*"));
Some(format!("SELECT {} FROM {}", count_star, identifier))
}
fn build_head_select(
syntax: Syntax,
table: &TableIdent,
tablealias: &str,
cols_info: &[Column],
) -> Option<String> {
let writer = ColumnWriter::new(syntax);
let mut head: Vec<&str> = Vec::default();
head.push("SELECT");
let cols: Vec<_> = cols_info
.iter()
.map(|col| writer.write(tablealias, col))
.collect();
let cols = cols.join(", ");
head.push(&cols);
head.push("FROM");
let tn = TableWriter::new(syntax).write(table);
let identifier = format!("{} {}", tn, tablealias);
head.push(&identifier);
Some(head.join(" "))
}