use std::{fmt::Debug, marker::PhantomData, sync::Arc};
#[cfg(feature = "mysql")]
use sqlx::MySqlPool;
#[cfg(feature = "postgres")]
use sqlx::PgPool;
#[cfg(feature = "sqlite")]
use sqlx::SqlitePool;
use crate::{
database::error::DatabaseError,
filter::Filtered,
schema::{Schema, Value},
};
use crate::helpers::{StartingSql, bind_value, build_filter_expr, get_starting_sql};
pub struct Delete<T> {
table: PhantomData<T>,
filters: Vec<Box<dyn Filtered>>,
#[cfg(feature = "mysql")]
conn: Arc<MySqlPool>,
#[cfg(feature = "postgres")]
conn: Arc<PgPool>,
#[cfg(feature = "sqlite")]
conn: Arc<SqlitePool>,
}
impl<T: Schema + Debug> Delete<T> {
#[cfg(feature = "mysql")]
pub fn new(conn: Arc<MySqlPool>) -> Self {
Self {
table: PhantomData,
conn,
filters: Vec::new(),
}
}
#[cfg(feature = "postgres")]
pub fn new(conn: Arc<PgPool>) -> Self {
Self {
table: PhantomData,
conn,
filters: Vec::new(),
}
}
#[cfg(feature = "sqlite")]
pub fn new(conn: Arc<SqlitePool>) -> Self {
Self {
table: PhantomData,
conn,
filters: Vec::new(),
}
}
pub fn filter<F>(mut self, filter: F) -> Self
where
F: Filtered + 'static,
{
self.filters.push(Box::new(filter));
self
}
pub async fn execute(self) -> Result<(), DatabaseError> {
let sql = get_starting_sql(StartingSql::Delete, T::table_name());
let mut params: Vec<Value> = Vec::new();
let sql = Self::filter_sql(sql, self.filters, &mut params);
let mut conn = self
.conn
.acquire()
.await
.map_err(|e| DatabaseError::ConnectionError(e))?;
let mut query = sqlx::query(&sql);
for v in params {
query = bind_value(query, v);
}
query
.execute(&mut *conn)
.await
.map_err(|e| DatabaseError::ExecutionError(e.to_string()))?;
Ok(())
}
pub(crate) fn filter_sql(
mut sql: String,
filters: Vec<Box<dyn Filtered>>,
params: &mut Vec<Value>,
) -> String {
if filters.is_empty() {
return sql;
}
sql.push_str(" WHERE ");
let mut parts: Vec<String> = Vec::with_capacity(filters.len());
for filter in &filters {
parts.push(build_filter_expr(filter.as_ref(), params));
}
sql.push_str(&parts.join(" AND "));
sql
}
}