mod compact;
mod indexed;
mod ordering;
#[cfg(test)]
mod tests;
use chrono::{NaiveDate, NaiveDateTime};
use compact::CompactOrdering;
use indexed::IndexedOrdering;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub use ordering::OrderBy;
#[derive(Debug, Clone, PartialEq)]
pub enum OrderingFormat {
None,
Indexed,
Compact,
}
#[derive(Deserialize, Serialize, Clone, Default)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema, utoipa::IntoParams))]
pub struct QueryParams {
pub search: Option<String>,
pub limit: Option<i64>,
pub page: Option<i64>,
pub per_page: Option<i64>,
pub status: Option<String>,
pub stage: Option<String>,
pub order: Option<String>,
#[serde(flatten)]
pub extra: HashMap<String, String>,
pub start_date: Option<NaiveDate>,
pub end_date: Option<NaiveDate>,
pub start_datetime: Option<NaiveDateTime>,
pub end_datetime: Option<NaiveDateTime>,
}
impl QueryParams {
pub fn search(&self) -> Option<String> {
self.search.clone()
}
pub fn search_query(&self) -> String {
self.search.clone().unwrap_or(String::from(""))
}
pub fn search_query_like(&self) -> String {
format!("%{}%", self.search_query())
}
pub fn limit(&self) -> i64 {
self.limit.unwrap_or(10).min(150)
}
pub fn curr_page(&self) -> i64 {
self.page.unwrap_or(1)
}
pub fn per_page(&self) -> i64 {
self.per_page.unwrap_or(10).min(150)
}
pub fn parse_indexed_ordering(&self) -> Vec<OrderBy> {
self.parse_indexed_orders()
}
pub fn parse_compact_ordering(&self) -> Vec<OrderBy> {
self.parse_compact_orders()
}
pub fn parse_ordering(&self) -> Vec<OrderBy> {
let indexed_orders = self.parse_indexed_ordering();
if !indexed_orders.is_empty() {
return indexed_orders;
}
let compact_orders = self.parse_compact_ordering();
if !compact_orders.is_empty() {
return compact_orders;
}
Vec::new()
}
pub fn has_ordering(&self) -> bool {
self.has_indexed_ordering() || self.has_compact_ordering()
}
pub fn has_indexed_ordering(&self) -> bool {
!self.parse_indexed_ordering().is_empty()
}
pub fn has_compact_ordering(&self) -> bool {
self.order.is_some() && !self.parse_compact_ordering().is_empty()
}
pub fn ordering_format(&self) -> OrderingFormat {
if self.has_indexed_ordering() {
OrderingFormat::Indexed
} else if self.has_compact_ordering() {
OrderingFormat::Compact
} else {
OrderingFormat::None
}
}
pub fn ordering_description(&self) -> String {
let orders = self.parse_ordering();
if orders.is_empty() {
"No ordering specified".to_string()
} else {
orders
.iter()
.map(|o| format!("{} {}", o.column, o.direction.to_uppercase()))
.collect::<Vec<_>>()
.join(", ")
}
}
}