use crate::prelude::{Database, SqlFilter};
use crate::traits::{Model, Repository};
use crate::types::Query;
use crate::utils::{BatchOperator, DEFAULT_BATCH_SIZE};
use sqlx::{Executor, QueryBuilder};
#[diagnostic::on_unimplemented(
note = "Type `{Self}` does not implement the `DeleteRepository<{M}>` trait",
label = "this type does not implement `DeleteRepository` for model type `{M}`",
message = "`{Self}` must implement `DeleteRepository<{M}>` to delete `{M}` records"
)]
#[async_trait::async_trait]
pub trait DeleteRepository<M: Model>: Repository<M> {
fn delete_by_id_query(id: &M::Id) -> Query<'_>;
fn delete_by_filter_query<'args>(
filter: impl SqlFilter<'args>,
) -> QueryBuilder<'args, Database>;
#[inline(always)]
#[cfg_attr(feature = "log_err", tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "delete_by_id", err))]
#[cfg_attr(not(feature = "log_err"), tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "delete_by_id"))]
async fn delete_by_id_with_executor<'c, E>(
&self,
tx: E,
id: impl Into<M::Id> + Send,
) -> crate::Result<()>
where
'c: 'async_trait,
E: Executor<'c, Database = Database> + Send,
{
Self::delete_by_id_query(&id.into()).execute(tx).await?;
Ok(())
}
#[inline(always)]
async fn delete_by_id(&self, id: impl Into<M::Id> + Send) -> crate::Result<()> {
self.delete_by_id_with_executor(self.pool(), id).await
}
#[inline(always)]
async fn delete_many_by_id<I>(&self, ids: I) -> crate::Result<()>
where
I: IntoIterator<Item = M::Id> + Send,
I::IntoIter: Send,
{
<Self as DeleteRepository<M>>::delete_batch_by_id::<DEFAULT_BATCH_SIZE, I>(self, ids).await
}
#[inline(always)]
#[cfg_attr(feature = "log_err", tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "delete_batch_by_id", err))]
#[cfg_attr(not(feature = "log_err"), tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "delete_batch_by_id"))]
async fn delete_batch_by_id<const N: usize, I>(&self, ids: I) -> crate::Result<()>
where
I: IntoIterator<Item = M::Id> + Send,
I::IntoIter: Send,
{
let span = tracing::Span::current();
span.record("BATCH_SIZE", N);
BatchOperator::<M::Id, N>::execute_query(ids, self.pool(), Self::delete_by_id_query).await
}
#[inline(always)]
#[cfg_attr(feature = "log_err", tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "delete_by_filter", err))]
#[cfg_attr(not(feature = "log_err"), tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "delete_by_filter"))]
async fn delete_by_filter_with_executor<'c, E>(
&self,
tx: E,
filter: impl SqlFilter<'_> + Send,
) -> crate::Result<()>
where
E: Executor<'c, Database = Database> + Send,
{
if !filter.should_apply_filter() {
return Err(crate::Error::Repository {
message: "Can not Delete from table with a empty filter.".into(),
});
}
Self::delete_by_filter_query(filter)
.build()
.execute(tx)
.await?;
Ok(())
}
#[inline(always)]
async fn delete_by_filter(&self, filter: impl SqlFilter<'_> + Send) -> crate::Result<()> {
self.delete_by_filter_with_executor(self.pool(), filter)
.await
}
}