use crate::core::condition::SqlValue;
use crate::orm::eager::EagerLoadable;
use crate::orm::model_query::ModelQuery;
use crate::orm::pagination::{CursorPage, Page, SimplePage};
use crate::orm::postgres::model::PgModel;
#[derive(Debug, Clone)]
pub struct CrudService<M> {
pool: sqlx::PgPool,
_marker: std::marker::PhantomData<M>,
}
impl<M> CrudService<M>
where
M: PgModel + Sync + Clone + serde::Serialize,
{
pub fn new(pool: sqlx::PgPool) -> Self {
Self {
pool,
_marker: std::marker::PhantomData,
}
}
pub async fn all(&self) -> Result<Vec<M>, sqlx::Error> {
M::all(&self.pool).await
}
pub async fn all_with(&self, relations: &[&str]) -> Result<Vec<M>, sqlx::Error>
where
M: EagerLoadable,
{
let mut results = M::all(&self.pool).await?;
for rel in relations {
results = M::load_eager(rel, results).await?;
}
Ok(results)
}
pub async fn find(&self, id: impl Into<SqlValue> + Send) -> Result<Option<M>, sqlx::Error> {
M::find_by_pk(&self.pool, id.into()).await
}
pub async fn find_or_fail(&self, id: impl Into<SqlValue> + Send) -> Result<M, sqlx::Error> {
M::find_or_fail(&self.pool, id.into()).await
}
pub async fn count(&self) -> Result<i64, sqlx::Error> {
M::count(&self.pool).await
}
pub async fn exists(&self, id: impl Into<SqlValue> + Send) -> Result<bool, sqlx::Error> {
let pool = self.pool.clone();
crate::orm::postgres::pool::with_pool(pool, M::find_query(id.into()).exists()).await
}
pub fn query(&self) -> ModelQuery<M> {
M::all_query()
}
pub fn filter(&self, col: &str, val: impl Into<SqlValue>) -> ModelQuery<M> {
M::filter(col, val)
}
pub async fn paginate(&self, page: u32, per_page: u32) -> Result<Page<M>, sqlx::Error> {
let pool = self.pool.clone();
crate::orm::postgres::pool::with_pool(pool, M::all_query().paginate(per_page, page)).await
}
pub async fn paginate_with(
&self,
page: u32,
per_page: u32,
relations: &[&str],
) -> Result<Page<M>, sqlx::Error>
where
M: EagerLoadable + Clone,
{
let mut page = self.paginate(page, per_page).await?;
for rel in relations {
page.data = M::load_eager(rel, page.data).await?;
}
Ok(page)
}
pub async fn simple_paginate(
&self,
page: u32,
per_page: u32,
) -> Result<SimplePage<M>, sqlx::Error> {
let pool = self.pool.clone();
crate::orm::postgres::pool::with_pool(pool, M::all_query().simple_paginate(per_page, page))
.await
}
pub async fn cursor_paginate(
&self,
cursor_col: &str,
cursor: Option<&str>,
per_page: u32,
) -> Result<CursorPage<M>, sqlx::Error> {
let pool = self.pool.clone();
let col = cursor_col.to_owned();
let cur = cursor.map(str::to_owned);
crate::orm::postgres::pool::with_pool(
pool,
M::all_query().cursor_paginate(per_page, &col, cur.as_deref()),
)
.await
}
pub async fn create(&self, data: &[(&str, SqlValue)]) -> Result<M, sqlx::Error> {
M::create_returning(&self.pool, data).await
}
pub async fn update(
&self,
id: impl Into<SqlValue> + Send,
data: &[(&str, SqlValue)],
) -> Result<u64, sqlx::Error> {
M::update_by_pk(&self.pool, id.into(), data).await
}
pub async fn delete(&self, id: impl Into<SqlValue> + Send) -> Result<u64, sqlx::Error> {
M::delete_by_pk(&self.pool, id.into()).await
}
pub async fn soft_delete(&self, id: impl Into<SqlValue> + Send) -> Result<u64, sqlx::Error> {
M::soft_delete_by_pk(&self.pool, id.into()).await
}
pub async fn restore(&self, id: impl Into<SqlValue> + Send) -> Result<u64, sqlx::Error> {
M::restore_by_pk(&self.pool, id.into()).await
}
pub async fn bulk_create(&self, rows: &[Vec<(&str, SqlValue)>]) -> Result<u64, sqlx::Error> {
M::bulk_create(&self.pool, rows).await
}
pub async fn delete_where(&self, conditions: &[(&str, SqlValue)]) -> Result<u64, sqlx::Error> {
let mut builder = M::query();
for (col, val) in conditions {
builder = builder.where_eq(col, val.clone());
}
M::delete_where(&self.pool, builder).await
}
pub async fn upsert_by(
&self,
unique_col: &str,
data: &[(&str, SqlValue)],
) -> Result<M, sqlx::Error> {
M::upsert_returning(&self.pool, data, &[unique_col]).await
}
pub async fn search(&self, term: &str, cols: &[&str]) -> Result<Vec<M>, sqlx::Error> {
super::search::SearchService::<M>::search(term, cols, &self.pool).await
}
pub async fn search_paginated(
&self,
term: &str,
cols: &[&str],
page: u32,
per_page: u32,
) -> Result<Page<M>, sqlx::Error> {
super::search::SearchService::<M>::search_paginated(term, cols, page, per_page, &self.pool)
.await
}
}