elasticsearch_dsl/search/runtime_mappings/
mod.rs

1//! You can specify a `runtime_mappings` section in a search request to create
2//! runtime fields that exist only as part of the query. You specify a script
3//! as part of the `runtime_mappings` section, just as you would if
4//! [adding a runtime field to the mappings](https://www.elastic.co/guide/en/elasticsearch/reference/master/runtime-mapping-fields.html).
5//!
6//! Defining a runtime field in a search request uses the same format as
7//! defining a runtime field in the index mapping. Just copy the field
8//! definition from the `runtime_mappings` in the search request to the
9//! `runtime` section of the index mapping.
10//!
11//! <https://www.elastic.co/guide/en/elasticsearch/reference/master/runtime-search-request.html>
12
13use serde::ser::{Serialize, SerializeStruct, Serializer};
14
15/// A runtime data type that is used in a search request.
16#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
17pub enum RuntimeDataType {
18    /// Boolean
19    Boolean,
20
21    /// Composite
22    Composite,
23
24    /// Date with optional `format`
25    Date(Option<String>),
26
27    /// Double
28    Double,
29
30    /// Geo point
31    GeoPoint,
32
33    /// IP address
34    Ip,
35
36    /// Keyword
37    Keyword,
38
39    /// Long
40    Long,
41}
42
43impl Serialize for RuntimeDataType {
44    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
45    where
46        S: Serializer,
47    {
48        match self {
49            Self::Boolean => {
50                let mut state = serializer.serialize_struct("RuntimeDataType_Boolean", 1)?;
51                state.serialize_field("type", "boolean")?;
52                state.end()
53            }
54            Self::Composite => {
55                let mut state = serializer.serialize_struct("RuntimeDataType_Boolean", 1)?;
56                state.serialize_field("type", "composite")?;
57                state.end()
58            }
59            Self::Date(format) => match format {
60                Some(format) => {
61                    let mut state = serializer.serialize_struct("RuntimeDataType_Boolean", 2)?;
62                    state.serialize_field("type", "date")?;
63                    state.serialize_field("format", format)?;
64                    state.end()
65                }
66                None => {
67                    let mut state = serializer.serialize_struct("RuntimeDataType_Boolean", 1)?;
68                    state.serialize_field("type", "date")?;
69                    state.end()
70                }
71            },
72            Self::Double => {
73                let mut state = serializer.serialize_struct("RuntimeDataType_Boolean", 1)?;
74                state.serialize_field("type", "double")?;
75                state.end()
76            }
77            Self::GeoPoint => {
78                let mut state = serializer.serialize_struct("RuntimeDataType_Boolean", 1)?;
79                state.serialize_field("type", "geo_point")?;
80                state.end()
81            }
82            Self::Ip => {
83                let mut state = serializer.serialize_struct("RuntimeDataType_Boolean", 1)?;
84                state.serialize_field("type", "ip")?;
85                state.end()
86            }
87            Self::Keyword => {
88                let mut state = serializer.serialize_struct("RuntimeDataType_Boolean", 1)?;
89                state.serialize_field("type", "keyword")?;
90                state.end()
91            }
92            Self::Long => {
93                let mut state = serializer.serialize_struct("RuntimeDataType_Boolean", 1)?;
94                state.serialize_field("type", "long")?;
95                state.end()
96            }
97        }
98    }
99}
100
101/// A runtime field that is used in a search request.
102#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
103pub struct RuntimeMapping {
104    #[serde(flatten)]
105    r#type: RuntimeDataType,
106    script: RuntimeScript,
107}
108
109#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
110struct RuntimeScript {
111    source: String,
112}
113
114impl RuntimeMapping {
115    /// Creates a new instance of [RuntimeMapping]
116    pub fn new<T>(r#type: RuntimeDataType, source: T) -> Self
117    where
118        T: ToString,
119    {
120        RuntimeMapping {
121            r#type,
122            script: RuntimeScript {
123                source: source.to_string(),
124            },
125        }
126    }
127
128    /// Creates a new instance of [RuntimeDataType::Boolean] [RuntimeMapping]
129    pub fn boolean<T>(source: T) -> Self
130    where
131        T: ToString,
132    {
133        Self::new(RuntimeDataType::Boolean, source)
134    }
135
136    /// Creates a new instance of [RuntimeDataType::Composite] [RuntimeMapping]
137    pub fn composite<T>(source: T) -> Self
138    where
139        T: ToString,
140    {
141        Self::new(RuntimeDataType::Composite, source)
142    }
143
144    /// Creates a new instance of [RuntimeDataType::Date] [RuntimeMapping] without format
145    pub fn date<T>(source: T) -> Self
146    where
147        T: ToString,
148    {
149        Self::new(RuntimeDataType::Date(None), source)
150    }
151
152    /// Creates a new instance of [RuntimeDataType::Date] [RuntimeMapping] with format
153    pub fn date_format<F, T>(format: F, source: T) -> Self
154    where
155        F: ToString,
156        T: ToString,
157    {
158        Self::new(RuntimeDataType::Date(Some(format.to_string())), source)
159    }
160
161    /// Creates a new instance of [RuntimeDataType::Double] [RuntimeMapping]
162    pub fn double<T>(source: T) -> Self
163    where
164        T: ToString,
165    {
166        Self::new(RuntimeDataType::Double, source)
167    }
168
169    /// Creates a new instance of [RuntimeDataType::GeoPoint] [RuntimeMapping]
170    pub fn geo_point<T>(source: T) -> Self
171    where
172        T: ToString,
173    {
174        Self::new(RuntimeDataType::GeoPoint, source)
175    }
176
177    /// Creates a new instance of [RuntimeDataType::Ip] [RuntimeMapping]
178    pub fn ip<T>(source: T) -> Self
179    where
180        T: ToString,
181    {
182        Self::new(RuntimeDataType::Ip, source)
183    }
184
185    /// Creates a new instance of [RuntimeDataType::Keyword] [RuntimeMapping]
186    pub fn keyword<T>(source: T) -> Self
187    where
188        T: ToString,
189    {
190        Self::new(RuntimeDataType::Keyword, source)
191    }
192
193    /// Creates a new instance of [RuntimeDataType::Long] [RuntimeMapping]
194    pub fn long<T>(source: T) -> Self
195    where
196        T: ToString,
197    {
198        Self::new(RuntimeDataType::Long, source)
199    }
200}
201
202#[cfg(test)]
203mod tests {
204    use super::*;
205    use crate::util::*;
206
207    #[test]
208    fn serialization() {
209        assert_serialize(
210            RuntimeMapping::boolean("doc['field'].value"),
211            json!({
212                "type": "boolean",
213                "script": { "source": "doc['field'].value" }
214            }),
215        );
216
217        assert_serialize(
218            RuntimeMapping::composite("doc['field'].value"),
219            json!({
220                "type": "composite",
221                "script": { "source": "doc['field'].value" }
222            }),
223        );
224
225        assert_serialize(
226            RuntimeMapping::date("doc['field'].value"),
227            json!({
228                "type": "date",
229                "script": { "source": "doc['field'].value" }
230            }),
231        );
232
233        assert_serialize(
234            RuntimeMapping::date_format("YYYY-mm-dd", "doc['field'].value"),
235            json!({
236                "type": "date",
237                "format": "YYYY-mm-dd",
238                "script": { "source": "doc['field'].value" }
239            }),
240        );
241
242        assert_serialize(
243            RuntimeMapping::double("doc['field'].value"),
244            json!({
245                "type": "double",
246                "script": { "source": "doc['field'].value" }
247            }),
248        );
249
250        assert_serialize(
251            RuntimeMapping::geo_point("doc['field'].value"),
252            json!({
253                "type": "geo_point",
254                "script": { "source": "doc['field'].value" }
255            }),
256        );
257
258        assert_serialize(
259            RuntimeMapping::ip("doc['field'].value"),
260            json!({
261                "type": "ip",
262                "script": { "source": "doc['field'].value" }
263            }),
264        );
265
266        assert_serialize(
267            RuntimeMapping::keyword("doc['field'].value"),
268            json!({
269                "type": "keyword",
270                "script": { "source": "doc['field'].value" }
271            }),
272        );
273
274        assert_serialize(
275            RuntimeMapping::long("doc['field'].value"),
276            json!({
277                "type": "long",
278                "script": { "source": "doc['field'].value" }
279            }),
280        );
281    }
282}