json_api/query/
sort.rs

1use std::fmt::{self, Display, Formatter};
2use std::ops::Neg;
3use std::str::FromStr;
4
5use serde::de::{Deserialize, Deserializer};
6use serde::ser::{Serialize, Serializer};
7
8use error::Error;
9use query::Path;
10use sealed::Sealed;
11use value::Stringify;
12
13/// A single sort instruction containing a direction and field path.
14#[derive(Clone, Debug, Eq, Hash, PartialEq)]
15pub struct Sort {
16    /// The direction to sort by.
17    pub direction: Direction,
18
19    /// The name of the field to sort by.
20    pub field: Path,
21
22    /// Private field for backwards compatibility.
23    _ext: (),
24}
25
26impl Sort {
27    /// Returns a new `Sort`.
28    pub fn new(field: Path, direction: Direction) -> Self {
29        Sort {
30            direction,
31            field,
32            _ext: (),
33        }
34    }
35
36    /// Returns a cloned inverse of `self`.
37    ///
38    /// # Example
39    ///
40    /// ```
41    /// # extern crate json_api;
42    /// #
43    /// # use json_api::Error;
44    /// #
45    /// # fn example() -> Result<(), Error> {
46    /// use json_api::query::{Direction, Sort};
47    ///
48    /// let chrono = Sort::new("created-at".parse()?, Direction::Asc);
49    /// let latest = chrono.reverse();
50    ///
51    /// assert_eq!(chrono.field, latest.field);
52    /// assert_eq!(chrono.direction, Direction::Asc);
53    /// assert_eq!(latest.direction, Direction::Desc);
54    /// #
55    /// # Ok(())
56    /// # }
57    /// #
58    /// # fn main() {
59    /// #     example().unwrap();
60    /// # }
61    /// ```
62    pub fn reverse(&self) -> Self {
63        -self.clone()
64    }
65}
66
67impl Display for Sort {
68    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
69        f.write_str(&self.stringify())
70    }
71}
72
73impl FromStr for Sort {
74    type Err = Error;
75
76    fn from_str(value: &str) -> Result<Self, Self::Err> {
77        if value.starts_with('-') {
78            let field = (&value[1..]).parse()?;
79            Ok(Sort::new(field, Direction::Desc))
80        } else {
81            let field = value.parse()?;
82            Ok(Sort::new(field, Direction::Asc))
83        }
84    }
85}
86
87impl Neg for Sort {
88    type Output = Self;
89
90    fn neg(self) -> Self::Output {
91        Sort::new(self.field, -self.direction)
92    }
93}
94
95impl<'de> Deserialize<'de> for Sort {
96    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
97    where
98        D: Deserializer<'de>,
99    {
100        use serde::de::{Error, Visitor};
101
102        struct SortVisitor;
103
104        impl<'de> Visitor<'de> for SortVisitor {
105            type Value = Sort;
106
107            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
108                write!(f, "a valid json api member name, optionally ")?;
109                write!(f, r#"prefixed with "-" to denote descending order"#)
110            }
111
112            fn visit_str<E: Error>(self, value: &str) -> Result<Self::Value, E> {
113                value.parse().map_err(Error::custom)
114            }
115        }
116
117        deserializer.deserialize_str(SortVisitor)
118    }
119}
120
121impl Serialize for Sort {
122    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
123    where
124        S: Serializer,
125    {
126        self.stringify().serialize(serializer)
127    }
128}
129
130impl Sealed for Sort {}
131
132impl Stringify for Sort {
133    fn to_bytes(&self) -> Vec<u8> {
134        let mut field = self.field.to_bytes();
135        let mut bytes = Vec::with_capacity(field.len() + 1);
136
137        if self.direction.is_desc() {
138            bytes.push(b'-');
139        }
140
141        bytes.append(&mut field);
142        bytes
143    }
144}
145
146/// The direction of a sort instruction.
147#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
148pub enum Direction {
149    /// Ascending
150    Asc,
151
152    /// Descending
153    Desc,
154}
155
156impl Direction {
157    /// Returns `true` if the direction is [`Asc`].
158    ///
159    /// # Example
160    ///
161    /// ```
162    /// # extern crate json_api;
163    /// #
164    /// # fn main() {
165    /// use json_api::query::Direction;
166    ///
167    /// let direction = Direction::Desc;
168    /// assert_eq!(direction.is_asc(), false);
169    ///
170    /// let direction = Direction::Asc;
171    /// assert_eq!(direction.is_asc(), true);
172    /// # }
173    /// ```
174    ///
175    /// [`Asc`]: #variant.Asc
176    pub fn is_asc(&self) -> bool {
177        *self == Direction::Asc
178    }
179
180    /// Returns `true` if the direction is [`Desc`].
181    ///
182    /// # Example
183    ///
184    /// ```
185    /// # extern crate json_api;
186    /// #
187    /// # fn main() {
188    /// use json_api::query::Direction;
189    ///
190    /// let direction = Direction::Asc;
191    /// assert_eq!(direction.is_desc(), false);
192    ///
193    /// let direction = Direction::Desc;
194    /// assert_eq!(direction.is_desc(), true);
195    /// # }
196    /// ```
197    ///
198    /// [`Desc`]: #variant.Desc
199    pub fn is_desc(&self) -> bool {
200        *self == Direction::Desc
201    }
202
203    /// Returns a cloned inverse of `self`.
204    ///
205    /// # Example
206    ///
207    /// ```
208    /// # extern crate json_api;
209    /// #
210    /// # fn main() {
211    /// use json_api::query::Direction;
212    ///
213    /// let asc = Direction::Asc;
214    /// let desc = Direction::Desc;
215    ///
216    /// assert_eq!(asc.reverse(), desc);
217    /// assert_eq!(desc.reverse(), asc);
218    /// # }
219    /// ```
220    pub fn reverse(&self) -> Self {
221        -*self
222    }
223}
224
225impl Neg for Direction {
226    type Output = Self;
227
228    fn neg(self) -> Self::Output {
229        match self {
230            Direction::Asc => Direction::Desc,
231            Direction::Desc => Direction::Asc,
232        }
233    }
234}
235
236#[cfg(test)]
237mod tests {
238    use super::{Direction, Sort};
239    use value::Path;
240
241    #[test]
242    fn direction_is_asc() {
243        assert_eq!(Direction::Asc.is_asc(), true);
244        assert_eq!(Direction::Desc.is_asc(), false);
245    }
246
247    #[test]
248    fn direction_is_desc() {
249        assert_eq!(Direction::Desc.is_desc(), true);
250        assert_eq!(Direction::Asc.is_desc(), false);
251    }
252
253    #[test]
254    fn direction_reverse() {
255        let asc = Direction::Asc;
256        let desc = Direction::Desc;
257
258        assert_eq!(asc.reverse(), desc);
259        assert_eq!(desc.reverse(), asc);
260    }
261
262    #[test]
263    fn sort_from_str() {
264        let field = "created-at".parse::<Path>().unwrap();
265        let mut sort = "created-at".parse::<Sort>().unwrap();
266
267        assert_eq!(sort.field, field);
268        assert_eq!(sort.direction, Direction::Asc);
269
270        sort = "-created-at".parse().unwrap();
271
272        assert_eq!(sort.field, field);
273        assert_eq!(sort.direction, Direction::Desc);
274    }
275
276    #[test]
277    fn sort_reverse() {
278        let field = "created-at".parse().unwrap();
279        let chrono = Sort::new(field, Direction::Asc);
280        let latest = chrono.reverse();
281
282        assert_eq!(chrono.field, latest.field);
283        assert_eq!(chrono.direction, Direction::Asc);
284        assert_eq!(latest.direction, Direction::Desc);
285    }
286
287    #[test]
288    fn sort_to_string() {
289        let sort = Sort::new("created-at".parse().unwrap(), Direction::Asc);
290
291        assert_eq!(sort.to_string(), "created-at");
292        assert_eq!(sort.reverse().to_string(), "-created-at");
293    }
294}