#[derive(Debug, Clone)]
pub struct Pagination {
pub page: u32,
pub size: u32,
}
impl Pagination {
pub fn new(page: u32, size: u32) -> Self {
Self { page, size }
}
pub fn offset(&self) -> i64 {
(self.page.saturating_sub(1)) as i64 * self.size as i64
}
pub fn limit(&self) -> i64 {
self.size as i64
}
}
impl Default for Pagination {
fn default() -> Self {
Self { page: 1, size: 20 }
}
}
#[derive(Debug)]
pub struct Page<T> {
pub items: Vec<T>,
pub page: u32,
pub size: u32,
pub total: i64,
}
impl<T> Page<T> {
pub fn new(items: Vec<T>, page: u32, size: u32, total: i64) -> Self {
Self {
items,
page,
size,
total,
}
}
pub fn has_next(&self) -> bool {
(self.page as i64) * (self.size as i64) < self.total
}
pub fn has_prev(&self) -> bool {
self.page > 1
}
pub fn total_pages(&self) -> u32 {
((self.total as f64) / (self.size as f64)).ceil() as u32
}
}
#[derive(Debug, Clone)]
pub enum SortDirection {
Asc,
Desc,
}
#[derive(Debug, Clone)]
pub struct Sort {
pub field: String,
pub direction: SortDirection,
}
impl Sort {
pub fn asc(field: &str) -> Self {
Self {
field: field.to_string(),
direction: SortDirection::Asc,
}
}
pub fn desc(field: &str) -> Self {
Self {
field: field.to_string(),
direction: SortDirection::Desc,
}
}
pub fn to_sql(&self) -> String {
let dir = match self.direction {
SortDirection::Asc => "ASC",
SortDirection::Desc => "DESC",
};
format!("{} {}", self.field, dir)
}
}
pub struct QueryBuilder {
table: String,
conditions: Vec<String>,
order_by: Option<Sort>,
limit_val: Option<i64>,
offset_val: Option<i64>,
}
impl QueryBuilder {
pub fn new(table: &str) -> Self {
Self {
table: table.to_string(),
conditions: Vec::new(),
order_by: None,
limit_val: None,
offset_val: None,
}
}
pub fn where_clause(mut self, condition: &str) -> Self {
self.conditions.push(condition.to_string());
self
}
pub fn order_by(mut self, sort: Sort) -> Self {
self.order_by = Some(sort);
self
}
pub fn limit(mut self, limit: i64) -> Self {
self.limit_val = Some(limit);
self
}
pub fn offset(mut self, offset: i64) -> Self {
self.offset_val = Some(offset);
self
}
pub fn build_select(&self) -> String {
let mut sql = format!("SELECT * FROM {}", self.table);
if !self.conditions.is_empty() {
sql.push_str(" WHERE ");
sql.push_str(&self.conditions.join(" AND "));
}
if let Some(ref sort) = self.order_by {
sql.push_str(" ORDER BY ");
sql.push_str(&sort.to_sql());
}
if let Some(limit) = self.limit_val {
sql.push_str(&format!(" LIMIT {}", limit));
}
if let Some(offset) = self.offset_val {
sql.push_str(&format!(" OFFSET {}", offset));
}
sql
}
pub fn build_count(&self) -> String {
let mut sql = format!("SELECT COUNT(*) FROM {}", self.table);
if !self.conditions.is_empty() {
sql.push_str(" WHERE ");
sql.push_str(&self.conditions.join(" AND "));
}
sql
}
}