Skip to main content

opensearch_dsl/search/params/
units.rs

1use std::fmt;
2
3use serde::{
4    de::{self, Unexpected, Visitor},
5    ser::{Serialize, Serializer},
6    Deserialize, Deserializer,
7};
8
9/// Whenever durations need to be specified, e.g. for a `timeout` parameter,
10/// the duration must specify the unit, like `2d` for 2 days.
11///
12/// <https://www.elastic.co/guide/en/opensearch/reference/current/common-options.html#time-units>
13#[derive(Debug, PartialEq, Eq, Clone, Copy)]
14#[allow(missing_docs)]
15pub enum Time {
16    Days(u64),
17    Hours(u64),
18    Minutes(u64),
19    Seconds(u64),
20    Milliseconds(u64),
21    Microseconds(u64),
22    Nanoseconds(u64),
23}
24
25impl Serialize for Time {
26    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27    where
28        S: Serializer,
29    {
30        match self {
31            Self::Days(u) => format!("{u}d"),
32            Self::Hours(u) => format!("{u}h"),
33            Self::Minutes(u) => format!("{u}m"),
34            Self::Seconds(u) => format!("{u}s"),
35            Self::Milliseconds(u) => format!("{u}ms"),
36            Self::Microseconds(u) => format!("{u}micros"),
37            Self::Nanoseconds(u) => format!("{u}nanos"),
38        }
39        .serialize(serializer)
40    }
41}
42
43impl<'de> Deserialize<'de> for Time {
44    fn deserialize<D>(deserializer: D) -> Result<Time, D::Error>
45    where
46        D: Deserializer<'de>,
47    {
48        struct TimeVisitor;
49
50        impl<'de> Visitor<'de> for TimeVisitor {
51            type Value = Time;
52
53            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
54                formatter.write_str("a string representing a duration")
55            }
56
57            fn visit_str<E>(self, value: &str) -> Result<Time, E>
58            where
59                E: de::Error,
60            {
61                let len = value.len();
62                let number = &value[..len - 1];
63                let unit = &value[len - 1..];
64
65                let number = number.parse::<u64>().map_err(E::custom)?;
66
67                match unit {
68                    "d" => Ok(Time::Days(number)),
69                    "h" => Ok(Time::Hours(number)),
70                    "m" => Ok(Time::Minutes(number)),
71                    "s" => Ok(Time::Seconds(number)),
72                    "ms" => Ok(Time::Milliseconds(number)),
73                    "micros" => Ok(Time::Microseconds(number)),
74                    "nanos" => Ok(Time::Nanoseconds(number)),
75                    _ => Err(E::custom(format!("unknown time unit: {}", unit))),
76                }
77            }
78        }
79
80        deserializer.deserialize_str(TimeVisitor)
81    }
82}
83/// Calendar-aware intervals are configured with the `calendar_interval`
84/// parameter. You can specify calendar intervals using the unit name, such as
85/// `month`, or as a single unit quantity, such as `1M`. For example,`day` and
86/// `1d` are equivalent. Multiple quantities, such as `2d`, are not supported.
87///
88/// <https://www.elastic.co/guide/en/opensearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html#calendar_intervals>
89#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Deserialize, Serialize)]
90#[serde(rename_all = "snake_case")]
91pub enum CalendarInterval {
92    /// All minutes begin at 00 seconds. One minute is the interval between 00
93    /// seconds of the first minute and 00 seconds of the following minute in
94    /// the specified time zone, compensating for any intervening leap seconds,
95    /// so that the number of minutes and seconds past the hour is the
96    /// same at the start and end.
97    Minute,
98    /// All hours begin at 00 minutes and 00 seconds. One hour (1h) is the
99    /// interval between 00:00 minutes of the first hour and 00:00 minutes of
100    /// the following hour in the specified time zone, compensating for any
101    /// intervening leap seconds, so that the number of minutes and seconds past
102    /// the hour is the same at the start and end.
103    Hour,
104    /// All days begin at the earliest possible time, which is usually 00:00:00
105    /// (midnight). One day (1d) is the interval between the start of the day
106    /// and the start of the following day in the specified time zone,
107    /// compensating for any intervening time changes.
108    Day,
109    /// One week is the interval between the start day_of_week:hour:minute:second
110    /// and the same day of the week and time of the following week in the
111    /// specified time zone.
112    Week,
113    /// One month is the interval between the start day of the month and time of
114    /// day and the same day of the month and time of the following month in the
115    /// specified time zone, so that the day of the month and time of day are
116    /// the same at the start and end.
117    Month,
118    /// One quarter is the interval between the start day of the month and time of
119    /// day and the same day of the month and time of day three months later, so
120    /// that the day of the month and time of day are the same at the start and
121    /// end.
122    Quarter,
123    /// One year is the interval between the start day of the month and time of
124    /// day and the same day of the month and time of day the following year in
125    /// the specified time zone, so that the date and time are the same at the
126    /// start and end.
127    Year,
128}
129
130/// Whenever the byte size of data needs to be specified, e.g. when setting a
131/// buffer size parameter, the value must specify the unit,
132/// like `10kb` for 10 kilobytes.
133/// Note that these units use powers of 1024, so `1kb` means 1024 bytes.
134///
135/// <https://www.elastic.co/guide/en/opensearch/reference/current/common-options.html#byte-units>
136#[derive(Debug, PartialEq, Eq, Clone, Copy)]
137#[allow(missing_docs)]
138pub enum Byte {
139    Bytes(u64),
140    Kilobytes(u64),
141    Megabytes(u64),
142    Gigabytes(u64),
143    Terabytes(u64),
144    Petabytes(u64),
145}
146
147impl Serialize for Byte {
148    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
149    where
150        S: Serializer,
151    {
152        match self {
153            Self::Bytes(u) => format!("{u}b"),
154            Self::Kilobytes(u) => format!("{u}kb"),
155            Self::Megabytes(u) => format!("{u}mb"),
156            Self::Gigabytes(u) => format!("{u}gb"),
157            Self::Terabytes(u) => format!("{u}tb"),
158            Self::Petabytes(u) => format!("{u}pb"),
159        }
160        .serialize(serializer)
161    }
162}
163
164impl<'de> Deserialize<'de> for Byte {
165    fn deserialize<D>(deserializer: D) -> Result<Byte, D::Error>
166    where
167        D: Deserializer<'de>,
168    {
169        struct ByteVisitor;
170
171        impl<'de> Visitor<'de> for ByteVisitor {
172            type Value = Byte;
173
174            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
175                formatter.write_str("a string representing a byte size")
176            }
177
178            fn visit_str<E>(self, value: &str) -> Result<Byte, E>
179            where
180                E: de::Error,
181            {
182                let len = value.len();
183                let number = &value[..len - 2];
184                let unit = &value[len - 2..];
185
186                let number = number.parse::<u64>().map_err(E::custom)?;
187
188                match unit {
189                    "b" => Ok(Byte::Bytes(number)),
190                    "kb" => Ok(Byte::Kilobytes(number)),
191                    "mb" => Ok(Byte::Megabytes(number)),
192                    "gb" => Ok(Byte::Gigabytes(number)),
193                    "tb" => Ok(Byte::Terabytes(number)),
194                    "pb" => Ok(Byte::Petabytes(number)),
195                    _ => Err(E::custom(format!("unknown byte unit: {}", unit))),
196                }
197            }
198        }
199
200        deserializer.deserialize_str(ByteVisitor)
201    }
202}
203
204/// Unit-less quantities means that they don’t have a "unit"
205/// like "bytes" or "Hertz" or "meter" or "long tonne".
206///
207/// If one of these quantities is large we’ll print it out like 10m for
208/// 10,000,000 or 7k for 7,000. We’ll still print 87 when we mean 87 though.
209///
210/// <https://www.elastic.co/guide/en/opensearch/reference/current/common-options.html#size-units>
211#[derive(Debug, PartialEq, Eq, Clone, Copy)]
212#[allow(missing_docs)]
213pub enum Size {
214    Kilo(u64),
215    Mega(u64),
216    Giga(u64),
217    Tera(u64),
218    Peta(u64),
219}
220
221impl Serialize for Size {
222    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
223    where
224        S: Serializer,
225    {
226        match self {
227            Self::Kilo(u) => format!("{u}k"),
228            Self::Mega(u) => format!("{u}m"),
229            Self::Giga(u) => format!("{u}g"),
230            Self::Tera(u) => format!("{u}t"),
231            Self::Peta(u) => format!("{u}p"),
232        }
233        .serialize(serializer)
234    }
235}
236
237impl<'de> Deserialize<'de> for Size {
238    fn deserialize<D>(deserializer: D) -> Result<Size, D::Error>
239    where
240        D: Deserializer<'de>,
241    {
242        struct SizeVisitor;
243
244        impl<'de> Visitor<'de> for SizeVisitor {
245            type Value = Size;
246
247            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
248                formatter.write_str("a string representing a size")
249            }
250
251            fn visit_str<E>(self, value: &str) -> Result<Size, E>
252            where
253                E: de::Error,
254            {
255                let len = value.len();
256                let number = &value[..len - 1];
257                let unit = &value[len - 1..];
258
259                let number = number.parse::<u64>().map_err(E::custom)?;
260
261                match unit {
262                    "k" => Ok(Size::Kilo(number)),
263                    "m" => Ok(Size::Mega(number)),
264                    "g" => Ok(Size::Giga(number)),
265                    "t" => Ok(Size::Tera(number)),
266                    "p" => Ok(Size::Peta(number)),
267                    _ => Err(E::custom(format!("unknown size unit: {}", unit))),
268                }
269            }
270        }
271
272        deserializer.deserialize_str(SizeVisitor)
273    }
274}
275
276/// Wherever distances need to be specified, such as the `distance` parameter
277/// in the
278/// [Geo-distance](https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-geo-distance-query.html)
279/// ), the default unit is meters if none is specified.
280/// Distances can be specified in other units,
281/// such as `"1km"` or `"2mi"` (2 miles).
282///
283/// <https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-geo-distance-query.html>
284#[derive(Debug, PartialEq, Eq, Clone, Copy)]
285#[allow(missing_docs)]
286pub enum Distance {
287    Miles(u64),
288    Yards(u64),
289    Feet(u64),
290    Inches(u64),
291    Kilometers(u64),
292    Meters(u64),
293    Centimeter(u64),
294    Millimeters(u64),
295    NauticalMiles(u64),
296}
297
298impl Default for Distance {
299    fn default() -> Self {
300        Self::Meters(100)
301    }
302}
303
304impl Serialize for Distance {
305    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
306    where
307        S: Serializer,
308    {
309        match self {
310            Self::Miles(u) => format!("{u}mi"),
311            Self::Yards(u) => format!("{u}yd"),
312            Self::Feet(u) => format!("{u}ft"),
313            Self::Inches(u) => format!("{u}in"),
314            Self::Kilometers(u) => format!("{u}km"),
315            Self::Meters(u) => format!("{u}m"),
316            Self::Centimeter(u) => format!("{u}cm"),
317            Self::Millimeters(u) => format!("{u}mm"),
318            Self::NauticalMiles(u) => format!("{u}nmi"),
319        }
320        .serialize(serializer)
321    }
322}
323
324impl<'de> Deserialize<'de> for Distance {
325    fn deserialize<D>(deserializer: D) -> Result<Distance, D::Error>
326    where
327        D: Deserializer<'de>,
328    {
329        struct DistanceVisitor;
330
331        impl<'de> Visitor<'de> for DistanceVisitor {
332            type Value = Distance;
333
334            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
335                formatter.write_str("a string representing a distance")
336            }
337
338            fn visit_str<E>(self, value: &str) -> Result<Distance, E>
339            where
340                E: de::Error,
341            {
342                let len = value.len();
343                let number = &value[..len - 2];
344                let unit = &value[len - 2..];
345
346                let number = number.parse::<u64>().map_err(E::custom)?;
347
348                match unit {
349                    "mi" => Ok(Distance::Miles(number)),
350                    "yd" => Ok(Distance::Yards(number)),
351                    "ft" => Ok(Distance::Feet(number)),
352                    "in" => Ok(Distance::Inches(number)),
353                    "km" => Ok(Distance::Kilometers(number)),
354                    "m" => Ok(Distance::Meters(number)),
355                    "cm" => Ok(Distance::Centimeter(number)),
356                    "mm" => Ok(Distance::Millimeters(number)),
357                    "nmi" => Ok(Distance::NauticalMiles(number)),
358                    _ => Err(E::custom(format!("unknown distance unit: {}", unit))),
359                }
360            }
361        }
362
363        deserializer.deserialize_str(DistanceVisitor)
364    }
365}
366
367/// Wherever distances need to be specified, such as the `distance` parameter
368/// in the
369/// [Geo-distance](https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-geo-distance-query.html)
370/// ), the default unit is meters if none is specified.
371/// Distances can be specified in other units,
372/// such as `"1km"` or `"2mi"` (2 miles).
373///
374/// <https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-geo-distance-query.html>
375#[derive(Debug, PartialEq, Eq, Clone, Copy)]
376#[allow(missing_docs)]
377pub enum DistanceUnit {
378    Miles,
379    Yards,
380    Feet,
381    Inches,
382    Kilometers,
383    Meters,
384    Centimeter,
385    Millimeters,
386    NauticalMiles,
387}
388
389impl Serialize for DistanceUnit {
390    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
391    where
392        S: Serializer,
393    {
394        match self {
395            Self::Miles => "mi",
396            Self::Yards => "yd",
397            Self::Feet => "ft",
398            Self::Inches => "in",
399            Self::Kilometers => "km",
400            Self::Meters => "m",
401            Self::Centimeter => "cm",
402            Self::Millimeters => "mm",
403            Self::NauticalMiles => "nmi",
404        }
405        .serialize(serializer)
406    }
407}
408
409impl<'de> Deserialize<'de> for DistanceUnit {
410    fn deserialize<D>(deserializer: D) -> Result<DistanceUnit, D::Error>
411    where
412        D: Deserializer<'de>,
413    {
414        struct DistanceUnitVisitor;
415
416        impl<'de> Visitor<'de> for DistanceUnitVisitor {
417            type Value = DistanceUnit;
418
419            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
420                formatter.write_str("a string representing a distance unit")
421            }
422
423            fn visit_str<E>(self, value: &str) -> Result<DistanceUnit, E>
424            where
425                E: de::Error,
426            {
427                match value {
428                    "mi" => Ok(DistanceUnit::Miles),
429                    "yd" => Ok(DistanceUnit::Yards),
430                    "ft" => Ok(DistanceUnit::Feet),
431                    "in" => Ok(DistanceUnit::Inches),
432                    "km" => Ok(DistanceUnit::Kilometers),
433                    "m" => Ok(DistanceUnit::Meters),
434                    "cm" => Ok(DistanceUnit::Centimeter),
435                    "mm" => Ok(DistanceUnit::Millimeters),
436                    "nmi" => Ok(DistanceUnit::NauticalMiles),
437                    _ => Err(E::invalid_value(Unexpected::Str(value), &self)),
438                }
439            }
440        }
441
442        deserializer.deserialize_str(DistanceUnitVisitor)
443    }
444}