use sea_orm::{
ActiveModelBehavior, ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, Iterable,
PaginatorTrait, QueryFilter, QueryOrder, QuerySelect,
};
use super::connection::Db;
pub struct Query<'db, E>
where
E: EntityTrait,
{
db: &'db Db,
select: sea_orm::Select<E>,
}
impl<'db, E> Query<'db, E>
where
E: EntityTrait,
{
#[must_use]
pub fn new(db: &'db Db) -> Self {
Self {
db,
select: E::find(),
}
}
#[must_use]
pub fn filter<C>(mut self, condition: C) -> Self
where
C: sea_orm::sea_query::IntoCondition,
{
self.select = self.select.filter(condition);
self
}
#[must_use]
pub fn where_eq<C, V>(self, column: C, value: V) -> Self
where
C: ColumnTrait,
V: Into<sea_orm::sea_query::Value>,
{
self.filter(column.eq(value))
}
#[must_use]
pub fn where_ne<C, V>(self, column: C, value: V) -> Self
where
C: ColumnTrait,
V: Into<sea_orm::sea_query::Value>,
{
self.filter(column.ne(value))
}
#[must_use]
pub fn where_gt<C, V>(self, column: C, value: V) -> Self
where
C: ColumnTrait,
V: Into<sea_orm::sea_query::Value>,
{
self.filter(column.gt(value))
}
#[must_use]
pub fn where_lt<C, V>(self, column: C, value: V) -> Self
where
C: ColumnTrait,
V: Into<sea_orm::sea_query::Value>,
{
self.filter(column.lt(value))
}
#[must_use]
pub fn where_in<C, V, I>(self, column: C, values: I) -> Self
where
C: ColumnTrait,
V: Into<sea_orm::sea_query::Value>,
I: IntoIterator<Item = V>,
{
self.filter(column.is_in(values.into_iter().map(Into::into).collect::<Vec<_>>()))
}
#[must_use]
pub fn where_null<C>(self, column: C) -> Self
where
C: ColumnTrait,
{
self.filter(column.is_null())
}
#[must_use]
pub fn where_not_null<C>(self, column: C) -> Self
where
C: ColumnTrait,
{
self.filter(column.is_not_null())
}
#[must_use]
pub fn latest(mut self) -> Self
where
E::Column: Iterable,
{
if let Some(col) = E::Column::iter().next() {
self.select = self.select.order_by_desc(col);
}
self
}
#[must_use]
pub fn latest_by<C>(mut self, column: C) -> Self
where
C: sea_orm::IntoSimpleExpr,
{
self.select = self.select.order_by_desc(column);
self
}
#[must_use]
pub fn oldest(mut self) -> Self
where
E::Column: Iterable,
{
if let Some(col) = E::Column::iter().next() {
self.select = self.select.order_by_asc(col);
}
self
}
#[must_use]
pub fn order_by_asc<C>(mut self, column: C) -> Self
where
C: sea_orm::IntoSimpleExpr,
{
self.select = self.select.order_by_asc(column);
self
}
#[must_use]
pub fn order_by_desc<C>(mut self, column: C) -> Self
where
C: sea_orm::IntoSimpleExpr,
{
self.select = self.select.order_by_desc(column);
self
}
#[must_use]
pub fn limit(mut self, n: u64) -> Self {
self.select = self.select.limit(n);
self
}
#[must_use]
pub fn offset(mut self, n: u64) -> Self {
self.select = self.select.offset(n);
self
}
#[must_use]
pub fn paginate(self, per_page: u64) -> Paginated<'db, E> {
Paginated {
query: self,
per_page,
}
}
pub async fn count(self) -> Result<u64, crate::Error>
where
E: Send + Sync,
E::Model: Send + Sync,
{
self.select
.paginate(self.db.orm(), 1)
.num_items()
.await
.map_err(crate::Error::from)
}
pub async fn all(self) -> Result<Vec<E::Model>, crate::Error> {
self.select
.all(self.db.orm())
.await
.map_err(crate::Error::from)
}
pub async fn one(self) -> Result<Option<E::Model>, crate::Error> {
self.select
.one(self.db.orm())
.await
.map_err(crate::Error::from)
}
}
pub struct Paginated<'db, E>
where
E: EntityTrait,
{
query: Query<'db, E>,
per_page: u64,
}
impl<'db, E> Paginated<'db, E>
where
E: EntityTrait,
{
#[must_use]
pub fn per_page(&self) -> u64 {
self.per_page
}
pub async fn page(self, n: u64) -> Result<Vec<E::Model>, crate::Error> {
if self.per_page == 0 {
return Ok(Vec::new());
}
let offset = n.saturating_sub(1) * self.per_page;
self.query.offset(offset).limit(self.per_page).all().await
}
pub async fn page_with_count(self, n: u64) -> Result<(Vec<E::Model>, u64), crate::Error>
where
E: Send + Sync,
E::Model: Send + Sync,
{
let select_for_count = self.query.select.clone();
let db = self.query.db;
let total = select_for_count
.paginate(db.orm(), 1)
.num_items()
.await
.map_err(crate::Error::from)?;
let rows = self.page(n).await?;
Ok((rows, total))
}
}
pub trait QueryModel: EntityTrait {
#[must_use]
fn query(db: &Db) -> Query<'_, Self> {
Query::new(db)
}
}
impl<E: EntityTrait> QueryModel for E {}
pub async fn insert<A>(
db: &Db,
active: A,
) -> Result<<A::Entity as EntityTrait>::Model, crate::Error>
where
A: ActiveModelTrait + ActiveModelBehavior + Send,
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
{
active.insert(db.orm()).await.map_err(crate::Error::from)
}
pub async fn update<A>(
db: &Db,
active: A,
) -> Result<<A::Entity as EntityTrait>::Model, crate::Error>
where
A: ActiveModelTrait + ActiveModelBehavior + Send,
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
{
active.update(db.orm()).await.map_err(crate::Error::from)
}
pub async fn delete<A>(db: &Db, active: A) -> Result<sea_orm::DeleteResult, crate::Error>
where
A: ActiveModelTrait + ActiveModelBehavior + Send,
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
{
active.delete(db.orm()).await.map_err(crate::Error::from)
}
pub async fn find_by_pk<E, P>(db: &Db, pk: P) -> Result<Option<E::Model>, crate::Error>
where
E: EntityTrait,
P: Into<<E::PrimaryKey as sea_orm::PrimaryKeyTrait>::ValueType> + Send,
{
E::find_by_id(pk)
.one(db.orm())
.await
.map_err(crate::Error::from)
}