use crate::prelude::Database;
use crate::traits::{Model, Repository};
use crate::types::Query;
use crate::utils::{BatchOperator, DEFAULT_BATCH_SIZE};
use sqlx::Executor;
#[diagnostic::on_unimplemented(
note = "Type `{Self}` does not implement the `UpdatableRepository<{M}>` trait",
label = "this type does not implement `UpdatableRepository` for model type `{M}`",
message = "`{Self}` must implement `UpdatableRepository<{M}>` to update `{M}` records"
)]
#[async_trait::async_trait]
pub trait UpdatableRepository<M: Model>: Repository<M> {
fn update_query(model: &M) -> Query<'_>;
#[inline(always)]
#[cfg_attr(feature = "log_err", tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "update", err))]
#[cfg_attr(not(feature = "log_err"), tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "update"))]
async fn update_with_executor<'c, E>(&self, tx: E, model: M) -> crate::Result<M>
where
M: 'async_trait,
E: Executor<'c, Database = Database> + Send,
{
Self::update_query(&model).execute(tx).await?;
Ok(model)
}
#[inline(always)]
#[cfg_attr(feature = "log_err", tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "update", err))]
#[cfg_attr(not(feature = "log_err"), tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "update"))]
async fn update_ref_with_executor<'c, E>(&self, tx: E, model: &M) -> crate::Result<()>
where
M: 'async_trait,
E: Executor<'c, Database = Database> + Send,
{
Self::update_query(model).execute(tx).await?;
Ok(())
}
#[inline(always)]
async fn update(&self, model: M) -> crate::Result<M>
where
M: 'async_trait,
{
self.update_with_executor(self.pool(), model).await
}
#[inline(always)]
async fn update_ref(&self, model: &M) -> crate::Result<()>
where
M: 'async_trait,
{
self.update_ref_with_executor(self.pool(), model).await
}
#[inline(always)]
async fn update_many<I>(&self, models: I) -> crate::Result<()>
where
I: IntoIterator<Item = M> + Send + 'async_trait,
I::IntoIter: Send,
{
self.update_batch::<DEFAULT_BATCH_SIZE, I>(models).await
}
#[inline(always)]
#[cfg_attr(feature = "log_err", tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "update_batch", err))]
#[cfg_attr(not(feature = "log_err"), tracing::instrument(skip_all, level = "debug", parent = &(Self::repository_span()), name = "update_batch"))]
async fn update_batch<const N: usize, I>(&self, models: I) -> crate::Result<()>
where
I: IntoIterator<Item = M> + Send + 'async_trait,
I::IntoIter: Send,
{
let span = tracing::Span::current();
span.record("BATCH_SIZE", N);
BatchOperator::<M, N>::execute_query(models, self.pool(), Self::update_query).await
}
}