nyaa_si/
query.rs

1use std::{fmt::Display, str::FromStr};
2
3use crate::category::Category;
4
5#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Default)]
6pub enum SortOrder {
7    Asecending,
8    #[default]
9    Descending,
10}
11
12impl FromStr for SortOrder {
13    type Err = String;
14    fn from_str(s: &str) -> Result<Self, Self::Err> {
15        match s {
16            "asc" => Ok(SortOrder::Asecending),
17            "desc" => Ok(SortOrder::Descending),
18            _ => Err("Invalid sort order".into()),
19        }
20    }
21}
22
23impl Display for SortOrder {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        match self {
26            SortOrder::Asecending => write!(f, "asc"),
27            SortOrder::Descending => write!(f, "desc"),
28        }
29    }
30}
31
32#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Default)]
33pub enum Sort {
34    Comments,
35    Size,
36    Date,
37    #[default]
38    Seeders,
39    Leechers,
40    Downloads,
41}
42
43impl FromStr for Sort {
44    type Err = String;
45    fn from_str(s: &str) -> Result<Self, Self::Err> {
46        match s {
47            "comments" => Ok(Sort::Comments),
48            "size" => Ok(Sort::Size),
49            "date" => Ok(Sort::Date),
50            "seeders" => Ok(Sort::Seeders),
51            "leechers" => Ok(Sort::Leechers),
52            "downloads" => Ok(Sort::Downloads),
53            _ => Err("Invalid sort".into()),
54        }
55    }
56}
57
58impl Display for Sort {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        match self {
61            Sort::Comments => write!(f, "comments"),
62            Sort::Size => write!(f, "size"),
63            Sort::Date => write!(f, "id"),
64            Sort::Seeders => write!(f, "seeders"),
65            Sort::Leechers => write!(f, "leechers"),
66            Sort::Downloads => write!(f, "downloads"),
67        }
68    }
69}
70
71#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Default)]
72pub enum Filter {
73    #[default]
74    NoFilter,
75    NoRemakes,
76    TrustedOnly,
77}
78
79impl From<u8> for Filter {
80    fn from(i: u8) -> Self {
81        match i {
82            0 => Filter::NoFilter,
83            1 => Filter::NoRemakes,
84            2 => Filter::TrustedOnly,
85            _ => Filter::NoFilter,
86        }
87    }
88}
89
90#[allow(clippy::from_over_into)]
91impl Into<u8> for Filter {
92    fn into(self) -> u8 {
93        match self {
94            Filter::NoFilter => 0,
95            Filter::NoRemakes => 1,
96            Filter::TrustedOnly => 2,
97        }
98    }
99}
100
101impl Display for Filter {
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        match self {
104            Filter::NoFilter => write!(f, "0"),
105            Filter::NoRemakes => write!(f, "1"),
106            Filter::TrustedOnly => write!(f, "2"),
107        }
108    }
109}
110
111#[derive(Debug, PartialEq, Clone, Hash)]
112pub struct Query<C> {
113    search: String,
114    page: u32,
115    sort: Sort,
116    sort_order: SortOrder,
117    filter: Filter,
118    category: C,
119}
120
121impl<C> Display for Query<C>
122where
123    C: Category,
124{
125    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126        write!(
127            f,
128            "q={}&p={}&s={}&o={}&f={}&c={}",
129            self.search,
130            self.page,
131            self.sort,
132            self.sort_order,
133            self.filter,
134            self.category
135        )
136    }
137}
138
139impl<C> Default for Query<C>
140where
141    C: Category,
142{
143    fn default() -> Self {
144        Query {
145            search: String::new(),
146            page: 1,
147            sort: Sort::default(),
148            sort_order: SortOrder::default(),
149            filter: Filter::default(),
150            category: C::default(),
151        }
152    }
153}
154
155#[derive(Debug, Clone, PartialEq)]
156pub struct QueryBuilder<C> {
157    search: String,
158    page: u32,
159    sort: Sort,
160    sort_order: SortOrder,
161    filter: Filter,
162    category: C,
163}
164
165impl<C: Category> Default for QueryBuilder<C> {
166    fn default() -> Self {
167        QueryBuilder {
168            search: String::new(),
169            page: 1,
170            sort: Sort::default(),
171            sort_order: SortOrder::default(),
172            filter: Filter::default(),
173            category: C::default(),
174        }
175    }
176}
177
178impl<C: Category> QueryBuilder<C> {
179    pub fn new() -> QueryBuilder<C> {
180        QueryBuilder::default()
181    }
182
183    pub fn build(self) -> Query<C> {
184        Query {
185            search: self.search,
186            page: self.page,
187            sort: self.sort,
188            sort_order: self.sort_order,
189            filter: self.filter,
190            category: self.category,
191        }
192    }
193
194    pub fn search<S: Into<String>>(mut self, search: S) -> QueryBuilder<C> {
195        self.search = search.into();
196        self
197    }
198
199    pub fn page(mut self, page: u32) -> QueryBuilder<C> {
200        self.page = page;
201        self
202    }
203
204    pub fn sort(mut self, sort: Sort) -> QueryBuilder<C> {
205        self.sort = sort;
206        self
207    }
208
209    pub fn sort_order(mut self, sort_order: SortOrder) -> QueryBuilder<C> {
210        self.sort_order = sort_order;
211        self
212    }
213
214    pub fn filter(mut self, filter: Filter) -> QueryBuilder<C> {
215        self.filter = filter;
216        self
217    }
218
219    pub fn category(mut self, category: C) -> QueryBuilder<C> {
220        self.category = category;
221        self
222    }
223}
224
225#[cfg(test)]
226mod tests {
227    use super::*;
228    use crate::NyaaCategory;
229
230    #[test]
231    fn test_build() {
232        let query = QueryBuilder::new()
233            .search("frieren")
234            .sort(Sort::Date)
235            .category(NyaaCategory::Anime)
236            .build();
237        assert_eq!(query.to_string(), format!("q={}&p={}&s={}&o={}&f={}&c={}", "frieren", 1, "id", "desc", 0, "1_0"))
238    }
239}