use std::collections::HashMap;
use tosho_macros::EnumName;
#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumName)]
pub enum SortOrder {
ASC,
DESC,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SortBy {
Id,
Title,
FullTitle,
Name,
DisplayName,
IssueNumber,
BookIndex,
IssuesCount,
EditionPriceMin,
MarketplacePrice,
ReleaseDate,
PublicationDate,
Any(String),
}
impl SortBy {
pub fn as_str(&self) -> &str {
match self {
SortBy::Id => "id",
SortBy::Title => "title",
SortBy::Name => "name",
SortBy::DisplayName => "display_name",
SortBy::FullTitle => "full_title",
SortBy::IssueNumber => "issue_number",
SortBy::BookIndex => "book_index",
SortBy::IssuesCount => "issues_count",
SortBy::ReleaseDate => "release_date",
SortBy::PublicationDate => "original_publication_date",
SortBy::EditionPriceMin => "edition_price_min",
SortBy::MarketplacePrice => "marketplace_price",
SortBy::Any(field) => field.as_ref(),
}
}
pub fn from_string(s: impl AsRef<str>) -> Self {
let s = s.as_ref();
match s {
"id" => SortBy::Id,
"title" => SortBy::Title,
"name" => SortBy::Name,
"display_name" => SortBy::DisplayName,
"full_title" => SortBy::FullTitle,
"issue_number" => SortBy::IssueNumber,
"book_index" => SortBy::BookIndex,
"issues_count" => SortBy::IssuesCount,
"release_date" => SortBy::ReleaseDate,
"publication_date" | "original_publication_date" => SortBy::PublicationDate,
"edition_price_min" => SortBy::EditionPriceMin,
"marketplace_price" => SortBy::MarketplacePrice,
other => SortBy::Any(other.to_string()),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FilterType {
Id,
Uuid,
Format,
Title,
SeriesRunId,
ReleaseDateStart,
ReleaseDateEnd,
GenreId,
ImprintId,
CreatorId,
PublisherId,
PublisherSlug,
SeriesStatus,
SeriesCategory,
HasRemarques,
Any(String),
}
impl FilterType {
pub fn as_str(&self) -> &str {
match self {
FilterType::Id => "id",
FilterType::Uuid => "uuid",
FilterType::Format => "format",
FilterType::Title => "title",
FilterType::SeriesRunId => "series_run_id",
FilterType::ReleaseDateStart => "release_date_start",
FilterType::ReleaseDateEnd => "release_date_end",
FilterType::GenreId => "genre_id",
FilterType::ImprintId => "publisher_imprint_id",
FilterType::CreatorId => "creator_id",
FilterType::PublisherId => "publisher_id",
FilterType::PublisherSlug => "publisher_slug",
FilterType::SeriesStatus => "series_status",
FilterType::SeriesCategory => "series_category",
FilterType::HasRemarques => "remarqued",
FilterType::Any(key) => key.as_ref(),
}
}
pub fn from_string(s: impl AsRef<str>) -> Self {
let s = s.as_ref();
match s {
"id" => FilterType::Id,
"uuid" => FilterType::Uuid,
"format" => FilterType::Format,
"title" => FilterType::Title,
"series_run_id" => FilterType::SeriesRunId,
"release_date_start" => FilterType::ReleaseDateStart,
"release_date_end" => FilterType::ReleaseDateEnd,
"genre_id" => FilterType::GenreId,
"imprint_id" | "publisher_imprint_id" => FilterType::ImprintId,
"creator_id" => FilterType::CreatorId,
"publisher_id" => FilterType::PublisherId,
"publisher_slug" => FilterType::PublisherSlug,
"status" | "series_status" => FilterType::SeriesStatus,
"category" | "series_category" => FilterType::SeriesCategory,
"remarqued" | "remarque" | "has_remarque" | "has_remarques" | "is_remarqued" => {
FilterType::HasRemarques
}
other => FilterType::Any(other.to_string()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FilterScope {
Frontlist,
Backlist,
OnSale,
BestSelling,
NewReleases,
}
impl FilterScope {
pub fn as_str(&self) -> &'static str {
match self {
FilterScope::Frontlist => "frontlist",
FilterScope::Backlist => "backlist",
FilterScope::OnSale => "on_sale",
FilterScope::BestSelling => "best_selling",
FilterScope::NewReleases => "new_releases",
}
}
}
#[derive(Clone)]
pub struct Filter {
filters: Vec<(FilterType, String)>,
direction: Option<SortOrder>,
order_by: Option<SortBy>,
page: Option<u32>,
per_page: Option<u32>,
scope: Option<FilterScope>,
}
impl Filter {
pub fn new() -> Self {
Self {
filters: Vec::new(),
direction: None,
order_by: None,
page: Some(1), per_page: Some(20), scope: None,
}
}
pub fn has_filter(&self, filter_type: &FilterType) -> bool {
self.filters.iter().any(|(ft, _)| ft == filter_type)
}
pub fn add_filter(mut self, filter_type: FilterType, value: impl ToString) -> Self {
self.filters.push((filter_type, value.to_string()));
self
}
pub fn add_filter_mut(&mut self, filter_type: FilterType, value: impl ToString) -> &mut Self {
self.filters.push((filter_type, value.to_string()));
self
}
pub fn with_order(mut self, order_by: SortBy, direction: SortOrder) -> Self {
self.order_by = Some(order_by);
self.direction = Some(direction);
self
}
pub fn set_order(&mut self, order_by: SortBy, direction: SortOrder) -> &mut Self {
self.order_by = Some(order_by);
self.direction = Some(direction);
self
}
pub fn with_page(mut self, page: u32) -> Self {
self.page = Some(page);
self
}
pub fn set_page(&mut self, page: u32) -> &mut Self {
self.page = Some(page);
self
}
pub fn with_per_page(mut self, per_page: u32) -> Self {
self.per_page = Some(per_page);
self
}
pub fn set_per_page(&mut self, per_page: u32) -> &mut Self {
self.per_page = Some(per_page);
self
}
pub fn clear_filters(mut self) -> Self {
self.filters.clear();
self.per_page = None;
self.page = None;
self.direction = None;
self.order_by = None;
self.scope = None;
self
}
pub fn clear_filters_mut(&mut self) -> &mut Self {
self.filters.clear();
self.per_page = None;
self.page = None;
self.direction = None;
self.order_by = None;
self.scope = None;
self
}
pub fn with_scope(mut self, scope: FilterScope) -> Self {
self.scope = Some(scope);
self
}
pub fn set_scope(&mut self, scope: FilterScope) -> &mut Self {
self.scope = Some(scope);
self
}
pub(crate) fn to_params(&self) -> HashMap<String, String> {
let mut query = HashMap::new();
for (filter_type, value) in &self.filters {
let filter_key = format!("filter[{}]", filter_type.as_str());
query.insert(filter_key, value.clone());
}
if let Some(direction) = self.direction {
query.insert("direction".to_string(), direction.to_name().to_string());
}
if let Some(order_by) = &self.order_by {
query.insert("order_by".to_string(), order_by.as_str().to_string());
}
if let Some(page) = self.page {
query.insert("page".to_string(), page.to_string());
}
if let Some(per_page) = self.per_page {
query.insert("per_page".to_string(), per_page.to_string());
}
if let Some(scope) = self.scope {
query.insert("scope".to_string(), scope.as_str().to_string());
}
query
}
}
impl Default for Filter {
fn default() -> Self {
Self::new()
}
}