mod select;
use super::*;
#[allow(missing_docs)]
impl<M: Model> QueryBuilder<M> {
fn build_condition_sql_for_db(
&self,
condition: &WhereCondition,
db_type: DatabaseType,
) -> Option<String> {
let spec = Self::condition_spec(condition)?;
if let ConditionSpec::Raw { column, raw_sql } = spec {
return Some(self.build_raw_condition_sql(db_type, column, raw_sql));
}
let column = self.format_column_for_db(db_type, &condition.column);
match spec {
ConditionSpec::Raw { .. } => None,
ConditionSpec::Compare { operator, value } => {
Some(self.build_compare_sql(db_type, &column, operator, value))
}
ConditionSpec::Pattern {
negated,
escaped,
value,
} => Some(self.build_pattern_sql(db_type, &column, negated, escaped, value)),
ConditionSpec::List { operator, values } => {
Some(self.build_list_sql(db_type, &column, operator, values))
}
ConditionSpec::NullCheck { negated } => {
Some(self.build_null_check_sql(&column, negated))
}
ConditionSpec::Between { low, high } => {
Some(self.build_between_sql(db_type, &column, low, high))
}
ConditionSpec::JsonValue { operator, value } => {
Some(self.build_json_value_sql(db_type, &condition.column, operator, value))
}
ConditionSpec::JsonString { operator, value } => {
Some(self.build_json_string_sql(db_type, &condition.column, operator, value))
}
ConditionSpec::Array { operator, values } => {
Some(self.build_array_sql(db_type, &condition.column, operator, values))
}
ConditionSpec::Subquery { negated, query_sql } => {
Some(self.build_subquery_sql(&column, negated, query_sql))
}
}
}
pub(super) fn render_array_values(&self, values: &[serde_json::Value]) -> Vec<String> {
values
.iter()
.map(|value| match value {
serde_json::Value::String(text) => format!("'{}'", text.replace("'", "''")),
serde_json::Value::Number(number) => number.to_string(),
serde_json::Value::Bool(boolean) => boolean.to_string(),
serde_json::Value::Null => "NULL".to_string(),
_ => format!("'{}'", value.to_string().replace("'", "''")),
})
.collect()
}
fn build_or_group_sql_for_db(&self, group: &OrGroup, db_type: DatabaseType) -> String {
let mut parts = Vec::new();
for condition in &group.conditions {
if let Some(expression) = self.build_condition_sql_for_db(condition, db_type) {
parts.push(expression);
}
}
for nested_group in &group.nested_groups {
let nested_sql = self.build_or_group_sql_for_db(nested_group, db_type);
if !nested_sql.is_empty() {
parts.push(format!("({})", nested_sql));
}
}
parts.join(&format!(" {} ", group.combine_with.as_sql()))
}
pub(crate) fn build_where_sql_for_db(&self, db_type: DatabaseType) -> String {
let mut clauses = Vec::new();
for condition in &self.conditions {
if let Some(expression) = self.build_condition_sql_for_db(condition, db_type) {
clauses.push(expression);
}
}
for group in &self.or_groups {
let group_sql = self.build_or_group_sql_for_db(group, db_type);
if !group_sql.is_empty() {
clauses.push(format!("({})", group_sql));
}
}
if M::soft_delete_enabled() {
let deleted_at = db_sql::quote_ident(db_type, M::deleted_at_column());
if self.only_trashed {
clauses.push(format!("{} IS NOT NULL", deleted_at));
} else if !self.include_trashed {
clauses.push(format!("{} IS NULL", deleted_at));
}
}
clauses.join(" AND ")
}
pub(crate) fn build_count_sql_with_params_for_db(
&self,
db_type: DatabaseType,
) -> (String, Vec<Value>) {
let mut count_query = self.clone();
count_query.order_by.clear();
count_query.limit_value = None;
count_query.offset_value = None;
if count_query.unions.is_empty()
&& count_query.ctes.is_empty()
&& count_query.group_by.is_empty()
&& count_query.having_conditions.is_empty()
&& count_query.raw_select_expressions.is_empty()
{
let (where_sql, params) = count_query.build_where_clause_with_condition_for_db(db_type);
let mut sql = String::from("SELECT COUNT(*) AS count ");
count_query.append_from_and_join_sql(&mut sql, db_type);
if !where_sql.is_empty() {
sql.push_str(&format!("WHERE {}", where_sql));
} else {
sql.truncate(sql.trim_end().len());
}
return (sql, params);
}
let (inner_sql, params) = count_query.build_select_sql_with_params_for_db(db_type);
(
format!(
"SELECT COUNT(*) AS count FROM ({}) AS {}",
inner_sql,
db_sql::quote_ident(db_type, "tideorm_count_subquery")
),
params,
)
}
pub(super) fn build_count_sql_with_params(&self) -> (String, Vec<Value>) {
self.build_count_sql_with_params_for_db(self.db_type_for_sql())
}
pub(crate) fn build_exists_sql_with_params_for_db(
&self,
db_type: DatabaseType,
) -> (String, Vec<Value>) {
let mut exists_query = self.clone();
exists_query.order_by.clear();
exists_query.limit_value = None;
exists_query.offset_value = None;
if exists_query.unions.is_empty() {
exists_query.select_columns = None;
exists_query.raw_select_expressions = vec!["1".to_string()];
exists_query.subquery_select_expressions.clear();
exists_query.window_functions.clear();
if exists_query.ctes.is_empty() {
let (inner_sql, params) =
exists_query.build_base_select_sql_with_params_for_db(db_type);
return (
format!(
"SELECT EXISTS({} LIMIT 1) AS {}",
inner_sql,
db_sql::quote_ident(db_type, "exists_result")
),
params,
);
}
}
let (inner_sql, params) = exists_query.build_select_sql_with_params_for_db(db_type);
(
format!(
"SELECT 1 FROM ({}) AS {} LIMIT 1",
inner_sql,
db_sql::quote_ident(db_type, "tideorm_exists_subquery")
),
params,
)
}
pub(super) fn build_exists_sql_with_params(&self) -> (String, Vec<Value>) {
self.build_exists_sql_with_params_for_db(self.db_type_for_sql())
}
}