use super::ClauseAdder;
use crate::Syntax;
use crate::query::builder::QueryBuilder;
use crate::query::clause::OrderBy;
use crate::query::clause::ParamArgs;
use crate::writers::ColumnWriter;
use crate::writers::NextParam;
use crate::writers::TableWriter;
use crate::writers::alias::TableAlias;
use std::sync::Arc;
#[derive(Clone)]
pub struct ExistIn {
outer_column: String,
inner_column: String,
inner_tablename: &'static [&'static str],
pub(crate) inner_tablealias: String,
wheres: Vec<Arc<Box<dyn ClauseAdder>>>,
inner_exists_ins: Vec<Self>,
limit: Option<i64>,
offset: Option<i64>,
orderby: Vec<OrderBy>,
}
impl ExistIn {
pub(crate) fn new<T>(
sb: &QueryBuilder<T>,
outer_column: String,
inner_tablename: &'static [&'static str],
inner_column: String,
) -> Self {
ExistIn {
outer_column,
inner_column,
inner_tablename,
inner_tablealias: sb.alias.clone(),
wheres: sb.wheres.clone(),
inner_exists_ins: sb.exist_ins.clone(),
limit: sb.limit,
offset: sb.offset,
orderby: sb.orderby.clone(),
}
}
pub(crate) fn set_aliases(&mut self, alias_asigner: &Arc<TableAlias>) {
self.inner_tablealias = alias_asigner.next();
for sub in &mut self.inner_exists_ins {
sub.set_aliases(alias_asigner);
}
}
fn inner_fk_equal(&self, syntax: Syntax, tablealias: &str) -> String {
let col_writer = ColumnWriter::new(syntax);
format!(
"{}.{} = {}.{}",
self.inner_tablealias,
col_writer.excape(&self.inner_column),
tablealias,
col_writer.excape(&self.outer_column)
)
}
fn tails(&self, syntax: Syntax, tablealias: &str) -> String {
use crate::query::tail;
tail::write(syntax, &self.limit, &self.offset, &self.orderby, tablealias)
.unwrap_or_default()
}
fn exists_clause(&self, syntax: Syntax, _tablealias: &str, inner_clauses: &str) -> String {
let tails = self.tails(syntax, &self.inner_tablealias);
let inner_tablename = TableWriter::new(syntax).write2(self.inner_tablename);
let col_writer = ColumnWriter::new(syntax);
format!(
"EXISTS ( SELECT {} FROM {} {} WHERE {} {})",
col_writer.excape(&self.inner_column),
inner_tablename,
&self.inner_tablealias,
inner_clauses,
tails
)
}
fn in_clause(&self, syntax: Syntax, tablealias: &str, inner_clauses: &str) -> String {
let col_writer = ColumnWriter::new(syntax);
let outcol = format!("{}.{}", tablealias, col_writer.excape(&self.outer_column));
let innercol = format!(
"{}.{}",
self.inner_tablealias,
col_writer.excape(&self.inner_column)
);
let inner_tablename = TableWriter::new(syntax).write2(self.inner_tablename);
let tails = self.tails(syntax, &self.inner_tablealias);
let mut wheres = "".to_string();
if !inner_clauses.is_empty() {
wheres = format!("WHERE {}", inner_clauses);
}
format!(
" {} IN (SELECT {} FROM {} {} {} {}) ",
outcol, innercol, inner_tablename, self.inner_tablealias, wheres, tails
)
}
}
impl ClauseAdder for ExistIn {
fn bind<'lam, 'args, 'p>(&'lam self, args: &'args mut ParamArgs<'p>)
where
'lam: 'p,
{
for w in &self.wheres {
w.bind(args);
}
for w in &self.inner_exists_ins {
w.bind(args);
}
}
fn clause(&self, syntax: Syntax, alias: &str, next_params: &NextParam) -> Option<String> {
let using_in = self.limit.is_some();
let self_tablealias = alias;
let mut inner_wheres: Vec<String> = self
.wheres
.iter()
.filter_map(|w| w.clause(syntax, &self.inner_tablealias, next_params))
.collect();
if !using_in {
inner_wheres.push(self.inner_fk_equal(syntax, self_tablealias));
}
for ins in &self.inner_exists_ins {
if let Some(more) = ins.clause(syntax, &self.inner_tablealias, next_params) {
inner_wheres.push(more);
}
}
let inner_clauses = inner_wheres.join(" AND ");
if using_in {
Some(self.in_clause(syntax, self_tablealias, &inner_clauses))
} else {
Some(self.exists_clause(syntax, self_tablealias, &inner_clauses))
}
}
}