use crate::clause::{Limit, Offset, OrderBy, Where};
use crate::expr::Dialect;
use crate::join::Join;
use sqlmodel_core::Value;
#[derive(Debug, Clone)]
#[doc(hidden)]
pub struct SelectQuery {
pub table: String,
pub columns: Vec<String>,
pub where_clause: Option<Where>,
pub order_by: Vec<OrderBy>,
pub joins: Vec<Join>,
pub limit: Option<Limit>,
pub offset: Option<Offset>,
pub group_by: Vec<String>,
pub having: Option<Where>,
pub distinct: bool,
pub for_update: bool,
}
impl SelectQuery {
pub fn build_with_dialect(&self, dialect: Dialect) -> (String, Vec<Value>) {
let mut sql = String::new();
let mut params = Vec::new();
sql.push_str("SELECT ");
if self.distinct {
sql.push_str("DISTINCT ");
}
if self.columns.is_empty() {
sql.push('*');
} else {
sql.push_str(&self.columns.join(", "));
}
sql.push_str(" FROM ");
sql.push_str(&self.table);
for join in &self.joins {
sql.push_str(&join.build_with_dialect(dialect, &mut params, 0));
}
if let Some(where_clause) = &self.where_clause {
let (where_sql, where_params) = where_clause.build_with_dialect(dialect, params.len());
sql.push_str(" WHERE ");
sql.push_str(&where_sql);
params.extend(where_params);
}
if !self.group_by.is_empty() {
sql.push_str(" GROUP BY ");
sql.push_str(&self.group_by.join(", "));
}
if let Some(having) = &self.having {
let (having_sql, having_params) = having.build_with_dialect(dialect, params.len());
sql.push_str(" HAVING ");
sql.push_str(&having_sql);
params.extend(having_params);
}
if !self.order_by.is_empty() {
sql.push_str(" ORDER BY ");
let order_strs: Vec<_> = self
.order_by
.iter()
.map(|o| o.build(dialect, &mut params, 0))
.collect();
sql.push_str(&order_strs.join(", "));
}
if let Some(Limit(n)) = self.limit {
sql.push_str(&format!(" LIMIT {}", n));
}
if let Some(Offset(n)) = self.offset {
sql.push_str(&format!(" OFFSET {}", n));
}
if self.for_update {
sql.push_str(" FOR UPDATE");
}
(sql, params)
}
pub fn build_exists_subquery_with_dialect(&self, dialect: Dialect) -> (String, Vec<Value>) {
let mut sql = String::new();
let mut params = Vec::new();
sql.push_str("SELECT 1 FROM ");
sql.push_str(&self.table);
for join in &self.joins {
sql.push_str(&join.build_with_dialect(dialect, &mut params, 0));
}
if let Some(where_clause) = &self.where_clause {
let (where_sql, where_params) = where_clause.build_with_dialect(dialect, params.len());
sql.push_str(" WHERE ");
sql.push_str(&where_sql);
params.extend(where_params);
}
if !self.group_by.is_empty() {
sql.push_str(" GROUP BY ");
sql.push_str(&self.group_by.join(", "));
}
if let Some(having) = &self.having {
let (having_sql, having_params) = having.build_with_dialect(dialect, params.len());
sql.push_str(" HAVING ");
sql.push_str(&having_sql);
params.extend(having_params);
}
(sql, params)
}
}