use super::common::{IntoCondition, QueryBuilder, WhereCondition, WhereConnector};
use crate::{Error, Result, Value};
#[derive(Debug, Clone)]
pub struct DeleteBuilderInitial {
table_name: String,
}
#[derive(Debug, Clone)]
pub struct DeleteBuilderComplete {
table_name: String,
where_conditions: Vec<WhereCondition>,
parameters: Vec<Value>,
}
impl DeleteBuilderInitial {
pub fn new(table: &str) -> Self {
Self {
table_name: table.to_string(),
}
}
pub fn where_<C>(self, condition: C) -> DeleteBuilderComplete
where
C: IntoCondition,
{
let (column, operator, value) = condition.into_condition();
let mut where_conditions = Vec::new();
let mut parameters = Vec::new();
where_conditions.push(WhereCondition {
column,
operator,
value: value.clone(),
connector: WhereConnector::And,
});
parameters.push(value);
DeleteBuilderComplete {
table_name: self.table_name,
where_conditions,
parameters,
}
}
}
impl DeleteBuilderComplete {
pub fn where_<C>(mut self, condition: C) -> Self
where
C: IntoCondition,
{
let (column, operator, value) = condition.into_condition();
self.where_conditions.push(WhereCondition {
column,
operator,
value: value.clone(),
connector: WhereConnector::And,
});
self.parameters.push(value);
self
}
pub fn or_where<C>(mut self, condition: C) -> Self
where
C: IntoCondition,
{
let (column, operator, value) = condition.into_condition();
self.where_conditions.push(WhereCondition {
column,
operator,
value: value.clone(),
connector: WhereConnector::Or,
});
self.parameters.push(value);
self
}
pub fn and_where<C>(self, condition: C) -> Self
where
C: IntoCondition,
{
self.where_(condition)
}
}
impl QueryBuilder for DeleteBuilderInitial {
fn to_sql(&self) -> Result<String> {
Err(Error::invalid_query(
"DELETE requires WHERE condition for safety",
))
}
fn parameters(&self) -> &[Value] {
&[]
}
fn clone_builder(&self) -> Self {
self.clone()
}
}
impl QueryBuilder for DeleteBuilderComplete {
fn to_sql(&self) -> Result<String> {
for condition in &self.where_conditions {
condition.operator.validate()?;
}
let mut sql = String::new();
sql.push_str("DELETE FROM ");
sql.push_str(&self.table_name);
if !self.where_conditions.is_empty() {
sql.push_str(" WHERE ");
for (i, condition) in self.where_conditions.iter().enumerate() {
if i > 0 {
match condition.connector {
WhereConnector::And => sql.push_str(" AND "),
WhereConnector::Or => sql.push_str(" OR "),
}
}
sql.push_str(&condition.column);
sql.push(' ');
sql.push_str(condition.operator.as_str());
sql.push_str(" ?");
}
}
Ok(sql)
}
fn parameters(&self) -> &[Value] {
&self.parameters
}
fn clone_builder(&self) -> Self {
self.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::delete;
use crate::operator::op;
#[test]
fn test_delete_builder() {
let query = delete("users").where_(("age", op::LT, 18));
let sql = query.to_sql().unwrap();
assert_eq!(sql, "DELETE FROM users WHERE age < ?");
}
#[test]
fn test_delete_with_where_required() {
let query = delete("users").where_(("id", 1));
let sql = query.to_sql().unwrap();
assert_eq!(sql, "DELETE FROM users WHERE id = ?");
}
#[test]
fn test_delete_multiple_conditions() {
let query = delete("users")
.where_(("age", op::LT, 18))
.or_where(("status", "inactive"));
let sql = query.to_sql().unwrap();
assert_eq!(sql, "DELETE FROM users WHERE age < ? OR status = ?");
}
#[test]
fn test_delete_without_where_fails() {
let query = delete("users");
let result = query.to_sql();
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("DELETE requires WHERE condition for safety"));
}
}