elasticsearch_dsl/search/sort/
field_sort.rs

1use super::{NestedFieldSort, SortMode, SortOrder};
2use crate::util::ShouldSkip;
3use crate::Term;
4use serde::Serialize;
5
6/// Sorts search hits by other field values
7///
8/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#sort-search-results>
9#[derive(Debug, Clone, PartialEq, Serialize)]
10#[serde(remote = "Self")]
11pub struct FieldSort {
12    #[serde(skip)]
13    field: String,
14
15    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
16    order: Option<SortOrder>,
17
18    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
19    mode: Option<SortMode>,
20
21    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
22    unmapped_type: Option<String>,
23
24    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
25    format: Option<String>,
26
27    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
28    missing: Option<Term>,
29
30    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
31    nested: Option<NestedFieldSort>,
32}
33
34impl FieldSort {
35    /// Creates an instance of [FieldSort]
36    pub fn new<T>(field: T) -> Self
37    where
38        T: ToString,
39    {
40        Self {
41            field: field.to_string(),
42            order: None,
43            mode: None,
44            unmapped_type: None,
45            format: None,
46            missing: None,
47            nested: None,
48        }
49    }
50
51    /// Creates an instance of [FieldSort] by ascending order
52    pub fn ascending<T>(field: T) -> Self
53    where
54        T: ToString,
55    {
56        Self::new(field).order(SortOrder::Asc)
57    }
58
59    /// Creates an instance of [FieldSort] by descending order
60    pub fn descending<T>(field: T) -> Self
61    where
62        T: ToString,
63    {
64        Self::new(field).order(SortOrder::Desc)
65    }
66
67    /// Explicit order
68    ///
69    /// <https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_sort_order>
70    pub fn order(mut self, order: SortOrder) -> Self {
71        self.order = Some(order);
72        self
73    }
74
75    /// Sort mode for numeric fields
76    ///
77    /// <https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_sort_mode_option>
78    pub fn mode(mut self, mode: SortMode) -> Self {
79        self.mode = Some(mode);
80        self
81    }
82
83    /// Fallback type if mapping is not defined
84    ///
85    /// <https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_ignoring_unmapped_fields>
86    pub fn unmapped_type<T>(mut self, unmapped_type: T) -> Self
87    where
88        T: ToString,
89    {
90        self.unmapped_type = Some(unmapped_type.to_string());
91        self
92    }
93
94    /// Optional format for datetime sorts
95    ///
96    /// <https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_ignoring_unmapped_fields>
97    pub fn format<T>(mut self, format: T) -> Self
98    where
99        T: ToString,
100    {
101        self.format = Some(format.to_string());
102        self
103    }
104
105    /// The missing parameter specifies how docs which are missing the sort field should be treated
106    ///
107    /// <https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_missing_values>
108    pub fn missing<T>(mut self, missing: T) -> Self
109    where
110        T: Serialize,
111    {
112        self.missing = Term::new(missing);
113        self
114    }
115
116    /// Sorts search hits by fields that are inside one or more nested objects.
117    ///
118    /// <https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#nested-sorting>
119    pub fn nested(mut self, nested: NestedFieldSort) -> Self {
120        self.nested = Some(nested);
121        self
122    }
123}
124
125impl IntoIterator for FieldSort {
126    type Item = Self;
127
128    type IntoIter = std::option::IntoIter<Self::Item>;
129
130    fn into_iter(self) -> Self::IntoIter {
131        Some(self).into_iter()
132    }
133}
134
135serialize_keyed!(FieldSort: field);
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140    use crate::util::assert_serialize;
141    use crate::{Query, SortSpecialField};
142
143    #[test]
144    fn serialization() {
145        assert_serialize(FieldSort::new("test"), json!({"test": {}}));
146
147        assert_serialize(
148            FieldSort::new(SortSpecialField::Score),
149            json!({"_score": {}}),
150        );
151
152        assert_serialize(
153            FieldSort::ascending("field"),
154            json!({ "field": { "order": "asc" } }),
155        );
156
157        assert_serialize(
158            FieldSort::descending("field"),
159            json!({ "field": { "order": "desc" } }),
160        );
161
162        assert_serialize(
163            FieldSort::ascending("test")
164                .order(SortOrder::Asc)
165                .mode(SortMode::Max)
166                .unmapped_type("long")
167                .missing("miss"),
168            json!({
169                "test": {
170                    "order": "asc",
171                    "mode": "max",
172                    "unmapped_type": "long",
173                    "missing": "miss",
174                }
175            }),
176        );
177
178        assert_serialize(
179            FieldSort::ascending("offer.price")
180                .order(SortOrder::Asc)
181                .mode(SortMode::Avg)
182                .nested(NestedFieldSort::path("offer").filter(Query::term("offer.color", "blue"))),
183            json!({
184                "offer.price": {
185                    "mode": "avg",
186                    "order": "asc",
187                    "nested": {
188                        "path": "offer",
189                        "filter": {
190                            "term": {
191                                "offer.color": {
192                                    "value": "blue"
193                                }
194                            }
195                        }
196                    }
197                }
198            }),
199        );
200    }
201}