1use crate::{search::*, util::*, Map, Set};
4
5#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq)]
9pub struct Search {
10 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
11 runtime_mappings: Map<String, RuntimeMapping>,
12
13 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
14 indices_boost: Vec<KeyValuePair<String, f32>>,
15
16 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
17 min_score: Option<f32>,
18
19 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
20 _source: Option<SourceFilter>,
21
22 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
23 stats: Vec<String>,
24
25 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
26 from: Option<u64>,
27
28 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
29 size: Option<u64>,
30
31 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
32 query: Option<Query>,
33
34 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
35 sort: SortCollection,
36
37 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
38 aggs: Aggregations,
39
40 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
41 track_total_hits: Option<TrackTotalHits>,
42
43 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
44 highlight: Option<Highlight>,
45
46 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
47 rescore: RescoreCollection,
48
49 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
50 suggest: Map<String, Suggester>,
51
52 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
53 stored_fields: StoredFields,
54
55 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
56 docvalue_fields: Set<String>,
57
58 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
59 script_fields: Map<String, ScriptField>,
60
61 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
62 post_filter: Option<Query>,
63
64 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
65 pit: Option<PointInTime>,
66
67 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
68 search_after: Terms,
69
70 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
71 timeout: Option<Time>,
72
73 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
74 knn: Vec<Knn>,
75
76 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
77 collapse: Option<Collapse>,
78
79 #[serde(flatten)]
80 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
81 extra: Map<String, serde_json::Value>,
82
83 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
84 track_scores: Option<bool>,
85}
86
87impl Search {
88 add_aggregate!();
89
90 pub fn new() -> Self {
92 Self::default()
93 }
94
95 pub fn runtime_mapping<S>(mut self, name: S, mapping: RuntimeMapping) -> Self
97 where
98 S: ToString,
99 {
100 let _ = self.runtime_mappings.insert(name.to_string(), mapping);
101 self
102 }
103
104 pub fn script_fields<S, T>(mut self, name: S, script: T) -> Self
106 where
107 S: ToString,
108 T: Into<ScriptField>,
109 {
110 let _ = self.script_fields.insert(name.to_string(), script.into());
111 self
112 }
113
114 pub fn indices_boost<T, U>(mut self, field: T, boost: U) -> Self
119 where
120 T: ToString,
121 U: num_traits::AsPrimitive<f32>,
122 {
123 self.indices_boost
124 .push(KeyValuePair::new(field.to_string(), boost.as_()));
125 self
126 }
127
128 pub fn min_score<F>(mut self, min_score: F) -> Self
134 where
135 F: Into<f32>,
136 {
137 self.min_score = Some(min_score.into());
138 self
139 }
140
141 pub fn source<S>(mut self, source: S) -> Self
143 where
144 S: Into<SourceFilter>,
145 {
146 self._source = Some(source.into());
147 self
148 }
149
150 pub fn stats<S>(mut self, stats: S) -> Self
152 where
153 S: ToString,
154 {
155 self.stats.push(stats.to_string());
156 self
157 }
158
159 pub fn from(mut self, from: u64) -> Self {
163 self.from = Some(from);
164 self
165 }
166
167 pub fn size(mut self, size: u64) -> Self {
171 self.size = Some(size);
172 self
173 }
174
175 pub fn query<Q>(mut self, query: Q) -> Self
178 where
179 Q: Into<Query>,
180 {
181 self.query = Some(query.into());
182 self
183 }
184
185 pub fn post_filter<Q>(mut self, post_filter: Q) -> Self
189 where
190 Q: Into<Query>,
191 {
192 self.post_filter = Some(post_filter.into());
193 self
194 }
195
196 pub fn sort<T>(mut self, sort: T) -> Self
198 where
199 T: IntoIterator,
200 T::Item: Into<Sort>,
201 {
202 self.sort.extend(sort);
203 self
204 }
205
206 pub fn track_total_hits<T>(mut self, track_total_hits: T) -> Self
208 where
209 T: Into<TrackTotalHits>,
210 {
211 self.track_total_hits = Some(track_total_hits.into());
212 self
213 }
214
215 pub fn track_scores(mut self, enabled: bool) -> Self {
218 self.track_scores = Some(enabled);
219 self
220 }
221
222 pub fn highlight<H>(mut self, highlight: H) -> Self
224 where
225 H: Into<Highlight>,
226 {
227 self.highlight = Some(highlight.into());
228 self
229 }
230
231 pub fn rescore<T>(mut self, rescore: T) -> Self
233 where
234 T: IntoIterator,
235 T::Item: Into<Rescore>,
236 {
237 self.rescore.extend(rescore);
238 self
239 }
240
241 pub fn suggest<T, U>(mut self, name: T, suggester: U) -> Self
243 where
244 T: ToString,
245 U: Into<Suggester>,
246 {
247 let _ = self.suggest.insert(name.to_string(), suggester.into());
248 self
249 }
250
251 pub fn stored_fields<T>(mut self, stored_fields: T) -> Self
253 where
254 T: Into<StoredFields>,
255 {
256 self.stored_fields = stored_fields.into();
257 self
258 }
259
260 pub fn docvalue_fields<T>(mut self, docvalue_fields: T) -> Self
262 where
263 T: IntoIterator,
264 T::Item: ToString,
265 {
266 self.docvalue_fields
267 .extend(docvalue_fields.into_iter().map(|x| x.to_string()));
268 self
269 }
270
271 pub fn pit(mut self, pit: PointInTime) -> Self {
273 self.pit = Some(pit);
274 self
275 }
276
277 pub fn search_after<T>(mut self, sort_values: T) -> Self
279 where
280 T: Into<Terms>,
281 {
282 self.search_after = sort_values.into();
283 self
284 }
285
286 pub fn timeout<T>(mut self, timeout: T) -> Self
291 where
292 T: Into<Time>,
293 {
294 self.timeout = Some(timeout.into());
295 self
296 }
297
298 pub fn knn(mut self, knn: Knn) -> Self {
302 self.knn.push(knn);
303 self
304 }
305
306 pub fn collapse<C>(mut self, collapse: C) -> Self
310 where
311 C: Into<Collapse>,
312 {
313 self.collapse = Some(collapse.into());
314 self
315 }
316
317 pub fn extra(mut self, extra: Map<String, serde_json::Value>) -> Self {
337 self.extra = extra;
338 self
339 }
340}
341
342#[cfg(test)]
343mod tests {
344 use super::*;
345
346 #[test]
347 fn serializes_to_empty_object_by_default() {
348 assert_serialize(Search::new(), json!({}));
349 assert_serialize(Search::default(), json!({}));
350 }
351
352 #[test]
353 fn serializes_extra_fields() {
354 assert_serialize(
355 Search::new().size(10).track_scores(false).extra(
356 [
357 ("knn".to_owned(), json!({ "field": "abc" })),
358 ("terminate_after".to_owned(), json!(42)),
359 ]
360 .into(),
361 ),
362 json!({
363 "size": 10,
364 "track_scores": false,
365 "knn": { "field": "abc" },
366 "terminate_after": 42,
367 }),
368 );
369 }
370}