refactor: replace hand-written SortKey impls with define_sort_key! macro
Add define_sort_key! macro to listing.rs and convert all 8 SortKey enum + impl blocks to use it, eliminating ~270 lines of repetitive boilerplate across roasters, roasts, bags, brews, cups, cafes, gear, and timeline.
This commit is contained in:
parent
de49f7c3b1
commit
bd4cb023fb
9 changed files with 125 additions and 319 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::define_sort_key;
|
||||||
use crate::domain::entity_type::EntityType;
|
use crate::domain::entity_type::EntityType;
|
||||||
use crate::domain::ids::{BagId, GearId, TimelineEventId};
|
use crate::domain::ids::{BagId, GearId, TimelineEventId};
|
||||||
use crate::domain::listing::{SortDirection, SortKey};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct TimelineEventDetail {
|
pub struct TimelineEventDetail {
|
||||||
|
|
@ -54,32 +54,7 @@ pub struct NewTimelineEvent {
|
||||||
pub brew_data: Option<TimelineBrewData>,
|
pub brew_data: Option<TimelineBrewData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
define_sort_key!(pub TimelineSortKey {
|
||||||
pub enum TimelineSortKey {
|
#[default]
|
||||||
OccurredAt,
|
OccurredAt("occurred-at", Desc),
|
||||||
}
|
});
|
||||||
|
|
||||||
impl SortKey for TimelineSortKey {
|
|
||||||
fn default() -> Self {
|
|
||||||
TimelineSortKey::OccurredAt
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query(value: &str) -> Option<Self> {
|
|
||||||
match value {
|
|
||||||
"occurred-at" => Some(TimelineSortKey::OccurredAt),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_value(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
TimelineSortKey::OccurredAt => "occurred-at",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_direction(self) -> SortDirection {
|
|
||||||
match self {
|
|
||||||
TimelineSortKey::OccurredAt => SortDirection::Desc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use chrono::{DateTime, NaiveDate, Utc};
|
use chrono::{DateTime, NaiveDate, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::define_sort_key;
|
||||||
use crate::domain::entity_type::EntityType;
|
use crate::domain::entity_type::EntityType;
|
||||||
use crate::domain::ids::{BagId, RoastId};
|
use crate::domain::ids::{BagId, RoastId};
|
||||||
use crate::domain::listing::{SortDirection, SortKey};
|
|
||||||
use crate::domain::roasters::Roaster;
|
use crate::domain::roasters::Roaster;
|
||||||
use crate::domain::roasts::Roast;
|
use crate::domain::roasts::Roast;
|
||||||
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
||||||
|
|
@ -93,54 +93,16 @@ impl BagFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
define_sort_key!(pub BagSortKey {
|
||||||
pub enum BagSortKey {
|
#[default]
|
||||||
RoastDate,
|
CreatedAt("created-at", Desc),
|
||||||
CreatedAt,
|
RoastDate("roast-date", Desc),
|
||||||
UpdatedAt,
|
UpdatedAt("updated-at", Desc),
|
||||||
Roaster,
|
Roaster("roaster", Asc),
|
||||||
Roast,
|
Roast("roast", Asc),
|
||||||
Status,
|
Status("status", Asc),
|
||||||
FinishedAt,
|
FinishedAt("finished-at", Desc),
|
||||||
}
|
});
|
||||||
|
|
||||||
impl SortKey for BagSortKey {
|
|
||||||
fn default() -> Self {
|
|
||||||
BagSortKey::CreatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query(value: &str) -> Option<Self> {
|
|
||||||
match value {
|
|
||||||
"roast-date" => Some(BagSortKey::RoastDate),
|
|
||||||
"created-at" => Some(BagSortKey::CreatedAt),
|
|
||||||
"updated-at" => Some(BagSortKey::UpdatedAt),
|
|
||||||
"roaster" => Some(BagSortKey::Roaster),
|
|
||||||
"roast" => Some(BagSortKey::Roast),
|
|
||||||
"status" => Some(BagSortKey::Status),
|
|
||||||
"finished-at" => Some(BagSortKey::FinishedAt),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_value(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
BagSortKey::RoastDate => "roast-date",
|
|
||||||
BagSortKey::CreatedAt => "created-at",
|
|
||||||
BagSortKey::UpdatedAt => "updated-at",
|
|
||||||
BagSortKey::Roaster => "roaster",
|
|
||||||
BagSortKey::Roast => "roast",
|
|
||||||
BagSortKey::Status => "status",
|
|
||||||
BagSortKey::FinishedAt => "finished-at",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_direction(self) -> SortDirection {
|
|
||||||
match self {
|
|
||||||
BagSortKey::Roaster | BagSortKey::Roast | BagSortKey::Status => SortDirection::Asc,
|
|
||||||
_ => SortDirection::Desc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bag_timeline_event(
|
pub fn bag_timeline_event(
|
||||||
bag: &Bag,
|
bag: &Bag,
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ use std::str::FromStr;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::define_sort_key;
|
||||||
use crate::domain::entity_type::EntityType;
|
use crate::domain::entity_type::EntityType;
|
||||||
use crate::domain::ids::{BagId, BrewId, GearId};
|
use crate::domain::ids::{BagId, BrewId, GearId};
|
||||||
use crate::domain::listing::{SortDirection, SortKey};
|
|
||||||
use crate::domain::timeline::{NewTimelineEvent, TimelineBrewData, TimelineEventDetail};
|
use crate::domain::timeline::{NewTimelineEvent, TimelineBrewData, TimelineEventDetail};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
|
@ -272,36 +272,9 @@ impl BrewFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
define_sort_key!(pub BrewSortKey {
|
||||||
pub enum BrewSortKey {
|
#[default]
|
||||||
CreatedAt,
|
CreatedAt("created-at", Desc),
|
||||||
CoffeeWeight,
|
CoffeeWeight("coffee-weight", Desc),
|
||||||
WaterVolume,
|
WaterVolume("water-volume", Desc),
|
||||||
}
|
});
|
||||||
|
|
||||||
impl SortKey for BrewSortKey {
|
|
||||||
fn default() -> Self {
|
|
||||||
BrewSortKey::CreatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query(value: &str) -> Option<Self> {
|
|
||||||
match value {
|
|
||||||
"created-at" => Some(BrewSortKey::CreatedAt),
|
|
||||||
"coffee-weight" => Some(BrewSortKey::CoffeeWeight),
|
|
||||||
"water-volume" => Some(BrewSortKey::WaterVolume),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_value(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
BrewSortKey::CreatedAt => "created-at",
|
|
||||||
BrewSortKey::CoffeeWeight => "coffee-weight",
|
|
||||||
BrewSortKey::WaterVolume => "water-volume",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_direction(self) -> SortDirection {
|
|
||||||
SortDirection::Desc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::normalize_optional_field;
|
use super::normalize_optional_field;
|
||||||
|
use crate::define_sort_key;
|
||||||
use crate::domain::entity_type::EntityType;
|
use crate::domain::entity_type::EntityType;
|
||||||
use crate::domain::ids::CafeId;
|
use crate::domain::ids::CafeId;
|
||||||
use crate::domain::listing::{SortDirection, SortKey};
|
|
||||||
use crate::domain::roasters::is_valid_url_scheme;
|
use crate::domain::roasters::is_valid_url_scheme;
|
||||||
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
||||||
|
|
||||||
|
|
@ -95,42 +95,10 @@ impl UpdateCafe {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
define_sort_key!(pub CafeSortKey {
|
||||||
pub enum CafeSortKey {
|
#[default]
|
||||||
CreatedAt,
|
CreatedAt("created-at", Desc),
|
||||||
Name,
|
Name("name", Asc),
|
||||||
City,
|
City("city", Asc),
|
||||||
Country,
|
Country("country", Asc),
|
||||||
}
|
});
|
||||||
|
|
||||||
impl SortKey for CafeSortKey {
|
|
||||||
fn default() -> Self {
|
|
||||||
CafeSortKey::CreatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query(value: &str) -> Option<Self> {
|
|
||||||
match value {
|
|
||||||
"created-at" => Some(CafeSortKey::CreatedAt),
|
|
||||||
"name" => Some(CafeSortKey::Name),
|
|
||||||
"city" => Some(CafeSortKey::City),
|
|
||||||
"country" => Some(CafeSortKey::Country),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_value(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
CafeSortKey::CreatedAt => "created-at",
|
|
||||||
CafeSortKey::Name => "name",
|
|
||||||
CafeSortKey::City => "city",
|
|
||||||
CafeSortKey::Country => "country",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_direction(self) -> SortDirection {
|
|
||||||
match self {
|
|
||||||
CafeSortKey::CreatedAt => SortDirection::Desc,
|
|
||||||
_ => SortDirection::Asc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::define_sort_key;
|
||||||
use crate::domain::entity_type::EntityType;
|
use crate::domain::entity_type::EntityType;
|
||||||
use crate::domain::ids::{CafeId, CupId, RoastId};
|
use crate::domain::ids::{CafeId, CupId, RoastId};
|
||||||
use crate::domain::listing::{SortDirection, SortKey};
|
|
||||||
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
@ -106,45 +106,11 @@ impl CupFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
define_sort_key!(pub CupSortKey {
|
||||||
pub enum CupSortKey {
|
#[default]
|
||||||
CreatedAt,
|
CreatedAt("created-at", Desc),
|
||||||
CafeName,
|
CafeName("cafe", Asc),
|
||||||
CafeCity,
|
CafeCity("city", Asc),
|
||||||
RoastName,
|
RoastName("roast", Asc),
|
||||||
RoasterName,
|
RoasterName("roaster", Asc),
|
||||||
}
|
});
|
||||||
|
|
||||||
impl SortKey for CupSortKey {
|
|
||||||
fn default() -> Self {
|
|
||||||
CupSortKey::CreatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query(value: &str) -> Option<Self> {
|
|
||||||
match value {
|
|
||||||
"created-at" => Some(CupSortKey::CreatedAt),
|
|
||||||
"cafe" => Some(CupSortKey::CafeName),
|
|
||||||
"city" => Some(CupSortKey::CafeCity),
|
|
||||||
"roast" => Some(CupSortKey::RoastName),
|
|
||||||
"roaster" => Some(CupSortKey::RoasterName),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_value(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
CupSortKey::CreatedAt => "created-at",
|
|
||||||
CupSortKey::CafeName => "cafe",
|
|
||||||
CupSortKey::CafeCity => "city",
|
|
||||||
CupSortKey::RoastName => "roast",
|
|
||||||
CupSortKey::RoasterName => "roaster",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_direction(self) -> SortDirection {
|
|
||||||
match self {
|
|
||||||
CupSortKey::CreatedAt => SortDirection::Desc,
|
|
||||||
_ => SortDirection::Asc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ use std::str::FromStr;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::define_sort_key;
|
||||||
use crate::domain::entity_type::EntityType;
|
use crate::domain::entity_type::EntityType;
|
||||||
use crate::domain::ids::GearId;
|
use crate::domain::ids::GearId;
|
||||||
use crate::domain::listing::{SortDirection, SortKey};
|
|
||||||
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
|
@ -122,42 +122,10 @@ impl GearFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
define_sort_key!(pub GearSortKey {
|
||||||
pub enum GearSortKey {
|
#[default]
|
||||||
Make,
|
CreatedAt("created-at", Desc),
|
||||||
Model,
|
Make("make", Asc),
|
||||||
Category,
|
Model("model", Asc),
|
||||||
CreatedAt,
|
Category("category", Asc),
|
||||||
}
|
});
|
||||||
|
|
||||||
impl SortKey for GearSortKey {
|
|
||||||
fn default() -> Self {
|
|
||||||
GearSortKey::CreatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query(value: &str) -> Option<Self> {
|
|
||||||
match value {
|
|
||||||
"make" => Some(GearSortKey::Make),
|
|
||||||
"model" => Some(GearSortKey::Model),
|
|
||||||
"category" => Some(GearSortKey::Category),
|
|
||||||
"created-at" => Some(GearSortKey::CreatedAt),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_value(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
GearSortKey::Make => "make",
|
|
||||||
GearSortKey::Model => "model",
|
|
||||||
GearSortKey::Category => "category",
|
|
||||||
GearSortKey::CreatedAt => "created-at",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_direction(self) -> SortDirection {
|
|
||||||
match self {
|
|
||||||
GearSortKey::Make | GearSortKey::Model | GearSortKey::Category => SortDirection::Asc,
|
|
||||||
GearSortKey::CreatedAt => SortDirection::Desc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::normalize_optional_field;
|
use super::normalize_optional_field;
|
||||||
|
use crate::define_sort_key;
|
||||||
use crate::domain::entity_type::EntityType;
|
use crate::domain::entity_type::EntityType;
|
||||||
use crate::domain::ids::RoasterId;
|
use crate::domain::ids::RoasterId;
|
||||||
use crate::domain::listing::{SortDirection, SortKey};
|
|
||||||
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
@ -99,42 +99,10 @@ impl UpdateRoaster {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
define_sort_key!(pub RoasterSortKey {
|
||||||
pub enum RoasterSortKey {
|
#[default]
|
||||||
CreatedAt,
|
CreatedAt("created-at", Desc),
|
||||||
Name,
|
Name("name", Asc),
|
||||||
Country,
|
Country("country", Asc),
|
||||||
City,
|
City("city", Asc),
|
||||||
}
|
});
|
||||||
|
|
||||||
impl SortKey for RoasterSortKey {
|
|
||||||
fn default() -> Self {
|
|
||||||
RoasterSortKey::CreatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query(value: &str) -> Option<Self> {
|
|
||||||
match value {
|
|
||||||
"created-at" => Some(RoasterSortKey::CreatedAt),
|
|
||||||
"name" => Some(RoasterSortKey::Name),
|
|
||||||
"country" => Some(RoasterSortKey::Country),
|
|
||||||
"city" => Some(RoasterSortKey::City),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_value(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
RoasterSortKey::CreatedAt => "created-at",
|
|
||||||
RoasterSortKey::Name => "name",
|
|
||||||
RoasterSortKey::Country => "country",
|
|
||||||
RoasterSortKey::City => "city",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_direction(self) -> SortDirection {
|
|
||||||
match self {
|
|
||||||
RoasterSortKey::CreatedAt => SortDirection::Desc,
|
|
||||||
_ => SortDirection::Asc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::define_sort_key;
|
||||||
use crate::domain::entity_type::EntityType;
|
use crate::domain::entity_type::EntityType;
|
||||||
use crate::domain::ids::{RoastId, RoasterId};
|
use crate::domain::ids::{RoastId, RoasterId};
|
||||||
use crate::domain::listing::{SortDirection, SortKey};
|
|
||||||
use crate::domain::roasters::Roaster;
|
use crate::domain::roasters::Roaster;
|
||||||
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
use crate::domain::timeline::{NewTimelineEvent, TimelineEventDetail};
|
||||||
|
|
||||||
|
|
@ -61,48 +61,14 @@ pub struct UpdateRoast {
|
||||||
pub created_at: Option<DateTime<Utc>>,
|
pub created_at: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
define_sort_key!(pub RoastSortKey {
|
||||||
pub enum RoastSortKey {
|
#[default]
|
||||||
CreatedAt,
|
CreatedAt("created-at", Desc),
|
||||||
Name,
|
Name("name", Asc),
|
||||||
Roaster,
|
Roaster("roaster", Asc),
|
||||||
Origin,
|
Origin("origin", Asc),
|
||||||
Producer,
|
Producer("producer", Asc),
|
||||||
}
|
});
|
||||||
|
|
||||||
impl SortKey for RoastSortKey {
|
|
||||||
fn default() -> Self {
|
|
||||||
RoastSortKey::CreatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query(value: &str) -> Option<Self> {
|
|
||||||
match value {
|
|
||||||
"created-at" => Some(RoastSortKey::CreatedAt),
|
|
||||||
"name" => Some(RoastSortKey::Name),
|
|
||||||
"roaster" => Some(RoastSortKey::Roaster),
|
|
||||||
"origin" => Some(RoastSortKey::Origin),
|
|
||||||
"producer" => Some(RoastSortKey::Producer),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_value(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
RoastSortKey::CreatedAt => "created-at",
|
|
||||||
RoastSortKey::Name => "name",
|
|
||||||
RoastSortKey::Roaster => "roaster",
|
|
||||||
RoastSortKey::Origin => "origin",
|
|
||||||
RoastSortKey::Producer => "producer",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_direction(self) -> SortDirection {
|
|
||||||
match self {
|
|
||||||
RoastSortKey::CreatedAt => SortDirection::Desc,
|
|
||||||
_ => SortDirection::Asc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn roast_timeline_event(roast: &Roast, roaster: &Roaster) -> NewTimelineEvent {
|
pub fn roast_timeline_event(roast: &Roast, roaster: &Roaster) -> NewTimelineEvent {
|
||||||
let mut details = vec![TimelineEventDetail {
|
let mut details = vec![TimelineEventDetail {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,66 @@ pub trait SortKey: Copy + Eq {
|
||||||
fn default_direction(self) -> SortDirection;
|
fn default_direction(self) -> SortDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates a sort key enum and its `SortKey` trait implementation.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// define_sort_key!(RoasterSortKey {
|
||||||
|
/// #[default]
|
||||||
|
/// CreatedAt("created-at", Desc),
|
||||||
|
/// Name("name", Asc),
|
||||||
|
/// Country("country", Asc),
|
||||||
|
/// City("city", Asc),
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! define_sort_key {
|
||||||
|
(
|
||||||
|
$vis:vis $name:ident {
|
||||||
|
$(#[default] $default_variant:ident($default_query:literal, $default_dir:ident),)?
|
||||||
|
$($variant:ident($query:literal, $dir:ident)),*
|
||||||
|
$(,)?
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
|
$vis enum $name {
|
||||||
|
$($default_variant,)?
|
||||||
|
$($variant),*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::domain::listing::SortKey for $name {
|
||||||
|
fn default() -> Self {
|
||||||
|
// The first arm expands for the #[default] variant
|
||||||
|
$( return $name::$default_variant; )?
|
||||||
|
// If no #[default], this won't compile — every invocation needs one
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_query(value: &str) -> Option<Self> {
|
||||||
|
match value {
|
||||||
|
$($default_query => Some($name::$default_variant),)?
|
||||||
|
$($query => Some($name::$variant),)*
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_value(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
$($name::$default_variant => $default_query,)?
|
||||||
|
$($name::$variant => $query,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_direction(self) -> $crate::domain::listing::SortDirection {
|
||||||
|
match self {
|
||||||
|
$($name::$default_variant => $crate::domain::listing::SortDirection::$default_dir,)?
|
||||||
|
$($name::$variant => $crate::domain::listing::SortDirection::$dir,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum PageSize {
|
pub enum PageSize {
|
||||||
Limited(u32),
|
Limited(u32),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue