use super::{ReturningSelector, SelectModel};
use crate::{
ColumnTrait, ConnectionTrait, DeleteMany, DeleteOne, EntityTrait, Iterable, ValidatedDeleteOne,
error::*,
};
use sea_query::{DeleteStatement, Query};
#[derive(Clone, Debug)]
pub struct Deleter {
query: DeleteStatement,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DeleteResult {
pub rows_affected: u64,
}
impl<E> ValidatedDeleteOne<E>
where
E: EntityTrait,
{
pub fn exec<C>(self, db: &C) -> Result<DeleteResult, DbErr>
where
C: ConnectionTrait,
{
exec_delete_only(self.query, db)
}
pub fn exec_with_returning<C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
where
C: ConnectionTrait,
{
exec_delete_with_returning_one::<E, _>(self.query, db)
}
}
impl<E> DeleteOne<E>
where
E: EntityTrait,
{
pub fn exec<C>(self, db: &C) -> Result<DeleteResult, DbErr>
where
C: ConnectionTrait,
{
self.0?.exec(db)
}
pub fn exec_with_returning<C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
where
C: ConnectionTrait,
{
self.0?.exec_with_returning(db)
}
}
impl<'a, E> DeleteMany<E>
where
E: EntityTrait,
{
pub fn exec<C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
where
C: ConnectionTrait,
{
exec_delete_only(self.query, db)
}
pub fn exec_with_returning<C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
where
E: EntityTrait,
C: ConnectionTrait,
{
exec_delete_with_returning_many::<E, _>(self.query, db)
}
}
impl Deleter {
pub fn new(query: DeleteStatement) -> Self {
Self { query }
}
pub fn exec<C>(self, db: &C) -> Result<DeleteResult, DbErr>
where
C: ConnectionTrait,
{
exec_delete(self.query, db)
}
pub fn exec_with_returning<E, C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
where
E: EntityTrait,
C: ConnectionTrait,
{
exec_delete_with_returning_many::<E, _>(self.query, db)
}
}
impl DeleteResult {
#[doc(hidden)]
pub fn empty() -> Self {
Self { rows_affected: 0 }
}
#[doc(hidden)]
pub fn merge(&mut self, other: DeleteResult) {
self.rows_affected += other.rows_affected;
}
}
fn exec_delete_only<C>(query: DeleteStatement, db: &C) -> Result<DeleteResult, DbErr>
where
C: ConnectionTrait,
{
Deleter::new(query).exec(db)
}
fn exec_delete<C>(query: DeleteStatement, db: &C) -> Result<DeleteResult, DbErr>
where
C: ConnectionTrait,
{
let result = db.execute(&query)?;
Ok(DeleteResult {
rows_affected: result.rows_affected(),
})
}
fn exec_delete_with_returning_one<E, C>(
mut query: DeleteStatement,
db: &C,
) -> Result<Option<E::Model>, DbErr>
where
E: EntityTrait,
C: ConnectionTrait,
{
let db_backend = db.get_database_backend();
match db.support_returning() {
true => {
let returning = Query::returning().exprs(
E::Column::iter().map(|c| c.select_enum_as(c.into_returning_expr(db_backend))),
);
query.returning(returning);
ReturningSelector::<SelectModel<<E>::Model>, _>::from_query(query).one(db)
}
false => Err(DbErr::BackendNotSupported {
db: db_backend.as_str(),
ctx: "DELETE RETURNING",
}),
}
}
fn exec_delete_with_returning_many<E, C>(
mut query: DeleteStatement,
db: &C,
) -> Result<Vec<E::Model>, DbErr>
where
E: EntityTrait,
C: ConnectionTrait,
{
let db_backend = db.get_database_backend();
match db.support_returning() {
true => {
let returning = Query::returning().exprs(
E::Column::iter().map(|c| c.select_enum_as(c.into_returning_expr(db_backend))),
);
query.returning(returning);
ReturningSelector::<SelectModel<<E>::Model>, _>::from_query(query).all(db)
}
false => Err(DbErr::BackendNotSupported {
db: db_backend.as_str(),
ctx: "DELETE RETURNING",
}),
}
}
#[cfg(test)]
mod tests {
use crate::tests_cfg::cake;
#[test]
fn delete_error() {
use crate::{DbBackend, DbErr, Delete, EntityTrait, MockDatabase};
let db = MockDatabase::new(DbBackend::MySql).into_connection();
assert!(matches!(
Delete::one(cake::ActiveModel {
..Default::default()
})
.exec(&db),
Err(DbErr::PrimaryKeyNotSet { .. })
));
assert!(matches!(
cake::Entity::delete(cake::ActiveModel::default()).exec(&db),
Err(DbErr::PrimaryKeyNotSet { .. })
));
}
}