1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use super::{FieldSort, Sort};
use crate::util::ShouldSkip;

/// A sorting criteria
#[derive(Default, Clone, PartialEq, Serialize)]
pub struct SortCollection(Vec<Sort>);

impl std::fmt::Debug for SortCollection {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

impl IntoIterator for SortCollection {
    type Item = Sort;

    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl ShouldSkip for SortCollection {
    fn should_skip(&self) -> bool {
        self.0.should_skip()
    }
}

impl SortCollection {
    /// Creates a new instance of [SortCollection]
    pub fn new() -> Self {
        Default::default()
    }

    /// Extends sorting collection
    pub fn extend<T>(&mut self, sort: T)
    where
        T: IntoIterator,
        T::Item: Into<Sort>,
    {
        self.0.extend(sort.into_iter().map(Into::into))
    }

    /// Add a field to sort by ascending order
    pub fn ascending<T>(mut self, field: T) -> Self
    where
        T: ToString,
    {
        self.0.push(Sort::FieldSort(FieldSort::ascending(field)));
        self
    }

    /// Add a field to sort by descending order
    pub fn descending<T>(mut self, field: T) -> Self
    where
        T: ToString,
    {
        self.0.push(Sort::FieldSort(FieldSort::descending(field)));
        self
    }

    /// Add a field sort
    pub fn field(mut self, field_sort: FieldSort) -> Self {
        self.0.push(Sort::FieldSort(field_sort));
        self
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::util::assert_serialize_sort;
    use crate::SortSpecialField;

    #[test]
    fn serializes_correctly() {
        assert_serialize_sort(["abc", "def"], json!(["abc", "def"]));

        assert_serialize_sort(
            [
                FieldSort::ascending("field1"),
                FieldSort::descending("field2"),
            ],
            json!([
                { "field1": { "order": "asc" } },
                { "field2": { "order": "desc" } },
            ]),
        );

        assert_serialize_sort(
            [
                Sort::FieldSort(
                    FieldSort::ascending("post_date").format("strict_date_optional_time_nanos"),
                ),
                Sort::Field("user".to_string()),
                Sort::FieldSort(FieldSort::descending("name")),
                Sort::FieldSort(FieldSort::descending("age")),
                Sort::SpecialField(SortSpecialField::Score),
            ],
            json!([
                { "post_date" : {"order" : "asc", "format": "strict_date_optional_time_nanos" } },
                "user",
                { "name" : { "order": "desc" } },
                { "age" : { "order": "desc" } },
                "_score"
            ]),
        );

        assert_serialize_sort(
            SortCollection::new()
                .ascending("name")
                .descending("age")
                .field(FieldSort::ascending("post_date").format("strict_date_optional_time_nanos")),
            json!([
                { "name" : { "order": "asc" } },
                { "age" : { "order": "desc" } },
                { "post_date" : {"order" : "asc", "format": "strict_date_optional_time_nanos" } },
            ]),
        );
    }
}