Skip to main content

opensearch_dsl/search/sort/
field_sort.rs

1use serde::{Deserialize, Deserializer, Serialize};
2
3use super::{SortMode, SortOrder};
4use crate::{util::ShouldSkip, Term};
5
6/// Sorts search hits by other field values
7///
8/// <https://www.elastic.co/guide/en/opensearch/reference/current/sort-search-results.html#sort-search-results>
9#[derive(Default, Debug, Clone, PartialEq, Deserialize, Serialize)]
10#[serde(remote = "Self")]
11pub struct FieldSort {
12    #[serde(skip)]
13    field: String,
14
15    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
16    order: Option<SortOrder>,
17
18    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
19    mode: Option<SortMode>,
20
21    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
22    unmapped_type: Option<String>,
23
24    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
25    format: Option<String>,
26
27    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
28    missing: Option<Term>,
29}
30
31impl FieldSort {
32    /// Creates an instance of [FieldSort]
33    pub fn new<T>(field: T) -> Self
34    where
35        T: ToString,
36    {
37        Self {
38            field: field.to_string(),
39            order: None,
40            mode: None,
41            unmapped_type: None,
42            format: None,
43            missing: None,
44        }
45    }
46
47    /// Creates an instance of [FieldSort] by ascending order
48    pub fn ascending<T>(field: T) -> Self
49    where
50        T: ToString,
51    {
52        Self::new(field).order(SortOrder::Asc)
53    }
54
55    /// Creates an instance of [FieldSort] by descending order
56    pub fn descending<T>(field: T) -> Self
57    where
58        T: ToString,
59    {
60        Self::new(field).order(SortOrder::Desc)
61    }
62
63    /// Explicit order
64    ///
65    /// <https://www.elastic.co/guide/en/opensearch/reference/current/sort-search-results.html#_sort_order>
66    pub fn order(mut self, order: SortOrder) -> Self {
67        self.order = Some(order);
68        self
69    }
70
71    /// Sort mode for numeric fields
72    ///
73    /// <https://www.elastic.co/guide/en/opensearch/reference/current/sort-search-results.html#_sort_mode_option>
74    pub fn mode(mut self, mode: SortMode) -> Self {
75        self.mode = Some(mode);
76        self
77    }
78
79    /// Fallback type if mapping is not defined
80    ///
81    /// <https://www.elastic.co/guide/en/opensearch/reference/current/sort-search-results.html#_ignoring_unmapped_fields>
82    pub fn unmapped_type<T>(mut self, unmapped_type: T) -> Self
83    where
84        T: ToString,
85    {
86        self.unmapped_type = Some(unmapped_type.to_string());
87        self
88    }
89
90    /// Optional format for datetime sorts
91    ///
92    /// <https://www.elastic.co/guide/en/opensearch/reference/current/sort-search-results.html#_ignoring_unmapped_fields>
93    pub fn format<T>(mut self, format: T) -> Self
94    where
95        T: ToString,
96    {
97        self.format = Some(format.to_string());
98        self
99    }
100
101    /// The missing parameter specifies how docs which are missing the sort field
102    /// should be treated
103    ///
104    /// <https://www.elastic.co/guide/en/opensearch/reference/current/sort-search-results.html#_missing_values>
105    pub fn missing<T>(mut self, missing: T) -> Self
106    where
107        T: Serialize,
108    {
109        self.missing = Term::new(missing);
110        self
111    }
112}
113
114impl IntoIterator for FieldSort {
115    type IntoIter = std::option::IntoIter<Self::Item>;
116    type Item = Self;
117
118    fn into_iter(self) -> Self::IntoIter {
119        Some(self).into_iter()
120    }
121}
122
123serialize_keyed!(FieldSort: field);
124impl<'de> Deserialize<'de> for FieldSort {
125    fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
126    where
127        D: Deserializer<'de>,
128    {
129        use std::fmt;
130        struct WrapperVisitor;
131
132        impl<'de> serde::de::Visitor<'de> for WrapperVisitor {
133            type Value = FieldSort;
134
135            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
136                formatter.write_str("struct fieldsort")
137            }
138
139            fn visit_map<A>(self, mut map: A) -> Result<FieldSort, A::Error>
140            where
141                A: serde::de::MapAccess<'de>,
142            {
143                let mut sorter: FieldSort = FieldSort::default();
144
145                while let Some(key) = map.next_key::<String>()? {
146                    let inner_map =
147                        map.next_value::<serde_json::Map<String, serde_json::Value>>()?;
148                    sorter.field = key.to_owned();
149                    for (k, v) in inner_map.iter() {
150                        match k.as_str() {
151                            "unmapped_type" => match v.as_str() {
152                                Some(value) => {
153                                    sorter.unmapped_type = Some(value.to_string());
154                                }
155                                None => {
156                                    return Err(serde::de::Error::invalid_type(
157                                        serde::de::Unexpected::Other("not a string"),
158                                        &"a string",
159                                    ));
160                                }
161                            },
162                            "format" => match v.as_str() {
163                                Some(value) => {
164                                    sorter.format = Some(value.to_string());
165                                }
166                                None => {
167                                    return Err(serde::de::Error::invalid_type(
168                                        serde::de::Unexpected::Other("not a string"),
169                                        &"a string",
170                                    ));
171                                }
172                            },
173                            "order" => {
174                                let value = serde_json::from_value::<SortOrder>(v.clone());
175                                match value {
176                                    Ok(value) => {
177                                        sorter.order = Some(value);
178                                    }
179                                    Err(e) => {
180                                        return Err(serde::de::Error::custom(format!(
181                                            "error parsing {}: {}",
182                                            k, e
183                                        )));
184                                    }
185                                }
186                            }
187                            "mode" => {
188                                let value = serde_json::from_value::<SortMode>(v.clone());
189                                match value {
190                                    Ok(value) => {
191                                        sorter.mode = Some(value);
192                                    }
193                                    Err(e) => {
194                                        return Err(serde::de::Error::custom(format!(
195                                            "error parsing {}: {}",
196                                            k, e
197                                        )));
198                                    }
199                                }
200                            }
201                            "missing" => {
202                                let value = serde_json::from_value::<Term>(v.clone());
203                                match value {
204                                    Ok(value) => {
205                                        sorter.missing = Some(value);
206                                    }
207                                    Err(e) => {
208                                        return Err(serde::de::Error::custom(format!(
209                                            "error parsing {}: {}",
210                                            k, e
211                                        )));
212                                    }
213                                }
214                            }
215                            _ => {
216                                return Err(serde::de::Error::custom(format!(
217                                    "fielderror: error parsing {}",
218                                    k
219                                )));
220                            }
221                        }
222                    }
223                }
224                if !sorter.field.is_empty() {
225                    Ok(sorter)
226                } else {
227                    Err(serde::de::Error::missing_field("required field"))
228                }
229            }
230        }
231
232        deserializer.deserialize_map(WrapperVisitor)
233    }
234}
235
236#[cfg(test)]
237mod tests {
238    use super::*;
239    use crate::{util::assert_serialize, SortSpecialField};
240
241    #[test]
242    fn serialization() {
243        assert_serialize(FieldSort::new("test"), json!({"test": {}}));
244
245        assert_serialize(
246            FieldSort::new(SortSpecialField::Score),
247            json!({"_score": {}}),
248        );
249
250        assert_serialize(
251            FieldSort::ascending("field"),
252            json!({ "field": { "order": "asc" } }),
253        );
254
255        assert_serialize(
256            FieldSort::descending("field"),
257            json!({ "field": { "order": "desc" } }),
258        );
259
260        assert_serialize(
261            FieldSort::ascending("test")
262                .order(SortOrder::Asc)
263                .mode(SortMode::Max)
264                .unmapped_type("long")
265                .missing("miss"),
266            json!({
267                "test": {
268                    "order": "asc",
269                    "mode": "max",
270                    "unmapped_type": "long",
271                    "missing": "miss",
272                }
273            }),
274        );
275    }
276}