diff --git a/src/executor/limiter.rs b/src/executor/limiter.rs new file mode 100644 index 000000000..2644d3b20 --- /dev/null +++ b/src/executor/limiter.rs @@ -0,0 +1,62 @@ +use crate::{ + ConnectionTrait, DbErr, EntityTrait, FromQueryResult, Paginator, PaginatorTrait, QuerySelect, + Select, SelectModel, Selector, SelectorTrait, +}; +use std::num::NonZeroU64; + +#[derive(Debug)] +pub struct Limiter<'db, C, S> +where + C: ConnectionTrait, + S: SelectorTrait + 'db, +{ + db: &'db C, + selector: Selector, + paginator: Paginator<'db, C, S>, +} + +impl<'db, C, S> Limiter<'db, C, S> +where + C: ConnectionTrait, + S: SelectorTrait + 'db, +{ + pub async fn fetch(self) -> Result, DbErr> { + self.selector.all(self.db).await + } + + pub async fn total(&self) -> Result { + self.paginator.num_items().await + } +} + +pub trait LimiterTrait<'db, C> +where + C: ConnectionTrait, +{ + type Selector: SelectorTrait + 'db; + + fn limiting(self, db: &'db C, offset: u64, limit: u64) -> Limiter<'db, C, Self::Selector>; +} + +impl<'db, C, M, E> LimiterTrait<'db, C> for Select +where + C: ConnectionTrait, + E: EntityTrait, + M: FromQueryResult + Sized + Send + Sync + 'db, +{ + type Selector = SelectModel; + + fn limiting(self, db: &'db C, offset: u64, limit: u64) -> Limiter<'db, C, Self::Selector> { + let selector = self + .clone() + .limit(NonZeroU64::new(limit).map(|limit| limit.get())) + .offset(NonZeroU64::new(limit).map(|limit| limit.get())) + .into_model(); + + Limiter { + db, + paginator: self.clone().paginate(db, 1), + selector, + } + } +} diff --git a/src/executor/mod.rs b/src/executor/mod.rs index 34f8695fe..b3046d6f5 100644 --- a/src/executor/mod.rs +++ b/src/executor/mod.rs @@ -2,6 +2,7 @@ mod cursor; mod delete; mod execute; mod insert; +mod limiter; mod paginator; mod query; mod select; @@ -11,6 +12,7 @@ pub use cursor::*; pub use delete::*; pub use execute::*; pub use insert::*; +pub use limiter::*; pub use paginator::*; pub use query::*; pub use select::*;