1use std::collections::BTreeMap;
44
45use serde::ser::{SerializeMap, Serializer};
46use serde::Serialize;
47
48use crate::{json::ShouldSkip, util::StrJoin};
49
50#[macro_use]
51mod common;
52
53pub mod compound;
54pub mod full_text;
55pub mod functions;
56pub mod geo;
57pub mod joining;
58pub mod specialized;
59pub mod term;
60
61#[derive(Debug)]
68pub struct CombinationMinimumShouldMatch {
69 first: MinimumShouldMatch,
70 second: MinimumShouldMatch,
71}
72
73impl CombinationMinimumShouldMatch {
74 pub fn new<A, B>(first: A, second: B) -> CombinationMinimumShouldMatch
75 where
76 A: Into<MinimumShouldMatch>,
77 B: Into<MinimumShouldMatch>,
78 {
79 CombinationMinimumShouldMatch {
80 first: first.into(),
81 second: second.into(),
82 }
83 }
84}
85
86impl ToString for CombinationMinimumShouldMatch {
87 fn to_string(&self) -> String {
88 format!("{}<{}", self.first.to_string(), self.second.to_string())
89 }
90}
91
92impl Serialize for CombinationMinimumShouldMatch {
93 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
94 where
95 S: Serializer,
96 {
97 self.to_string().serialize(serializer)
98 }
99}
100
101#[derive(Debug)]
102pub enum MinimumShouldMatch {
103 Integer(i64),
104 Percentage(f64),
105 Combination(Box<CombinationMinimumShouldMatch>),
106 MultipleCombination(Vec<CombinationMinimumShouldMatch>),
107 LowHigh(i64, i64),
108}
109
110from!(i64, MinimumShouldMatch, Integer);
111from!(f64, MinimumShouldMatch, Percentage);
112from_exp!(
113 CombinationMinimumShouldMatch,
114 MinimumShouldMatch,
115 from,
116 MinimumShouldMatch::Combination(Box::new(from))
117);
118from!(
119 Vec<CombinationMinimumShouldMatch>,
120 MinimumShouldMatch,
121 MultipleCombination
122);
123from_exp!(
124 (i64, i64),
125 MinimumShouldMatch,
126 from,
127 MinimumShouldMatch::LowHigh(from.0, from.1)
128);
129
130impl ToString for MinimumShouldMatch {
131 fn to_string(&self) -> String {
132 match self {
133 MinimumShouldMatch::Integer(val) => val.to_string(),
134 MinimumShouldMatch::Percentage(val) => format!("{}%", val),
135 _ => panic!("Can't convert {:?} to String", self),
136 }
137 }
138}
139
140impl Serialize for MinimumShouldMatch {
141 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
142 where
143 S: Serializer,
144 {
145 match self {
146 MinimumShouldMatch::Integer(val) => val.serialize(serializer),
147 MinimumShouldMatch::Percentage(_) => self.to_string().serialize(serializer),
148 MinimumShouldMatch::Combination(ref comb) => comb.serialize(serializer),
149 MinimumShouldMatch::MultipleCombination(ref combs) => combs
150 .iter()
151 .map(ToString::to_string)
152 .join(" ")
153 .serialize(serializer),
154 MinimumShouldMatch::LowHigh(low, high) => {
155 let mut d = BTreeMap::new();
156 d.insert("low_freq", low);
157 d.insert("high_freq", high);
158 d.serialize(serializer)
159 }
160 }
161 }
162}
163
164#[derive(Debug)]
166pub enum Fuzziness {
167 Auto,
168 LevenshteinDistance(i64),
169 Proportionate(f64),
170}
171
172from!(i64, Fuzziness, LevenshteinDistance);
173from!(f64, Fuzziness, Proportionate);
174
175impl Serialize for Fuzziness {
176 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
177 where
178 S: Serializer,
179 {
180 use self::Fuzziness::*;
181 match self {
182 Auto => "auto".serialize(serializer),
183 LevenshteinDistance(dist) => dist.serialize(serializer),
184 Proportionate(p) => p.serialize(serializer),
185 }
186 }
187}
188
189#[derive(Debug)]
195pub struct Flags<A>(Vec<A>)
196where
197 A: AsRef<str>;
198
199impl<A> Serialize for Flags<A>
200where
201 A: AsRef<str>,
202{
203 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
204 where
205 S: Serializer,
206 {
207 self.0.iter().join("|").serialize(serializer)
208 }
209}
210
211impl<A> From<Vec<A>> for Flags<A>
212where
213 A: AsRef<str>,
214{
215 fn from(from: Vec<A>) -> Self {
216 Flags(from)
217 }
218}
219
220#[derive(Debug)]
222pub enum ScoreMode {
223 Multiply,
224 Sum,
225 Avg,
226 First,
227 Max,
228 Min,
229}
230
231impl Serialize for ScoreMode {
232 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
233 where
234 S: Serializer,
235 {
236 match self {
237 ScoreMode::Multiply => "multiply".serialize(serializer),
238 ScoreMode::Sum => "sum".serialize(serializer),
239 ScoreMode::Avg => "avg".serialize(serializer),
240 ScoreMode::First => "first".serialize(serializer),
241 ScoreMode::Max => "max".serialize(serializer),
242 ScoreMode::Min => "min".serialize(serializer),
243 }
244 }
245}
246
247#[derive(Debug)]
254pub enum Query {
255 MatchAll(Box<MatchAllQuery>),
256
257 Match(Box<full_text::MatchQuery>),
259 MultiMatch(Box<full_text::MultiMatchQuery>),
260 Common(Box<full_text::CommonQuery>),
261 QueryString(Box<full_text::QueryStringQuery>),
262 SimpleQueryString(Box<full_text::SimpleQueryStringQuery>),
263
264 Term(Box<term::TermQuery>),
266 Terms(Box<term::TermsQuery>),
267 Range(Box<term::RangeQuery>),
268 Exists(Box<term::ExistsQuery>),
269 Prefix(Box<term::PrefixQuery>),
272 Wildcard(Box<term::WildcardQuery>),
273 Regexp(Box<term::RegexpQuery>),
274 Fuzzy(Box<term::FuzzyQuery>),
275 Type(Box<term::TypeQuery>),
276 Ids(Box<term::IdsQuery>),
277
278 ConstantScore(Box<compound::ConstantScoreQuery>),
280 Bool(Box<compound::BoolQuery>),
281 DisMax(Box<compound::DisMaxQuery>),
282 FunctionScore(Box<compound::FunctionScoreQuery>),
283 Boosting(Box<compound::BoostingQuery>),
284 Indices(Box<compound::IndicesQuery>),
285 Nested(Box<joining::NestedQuery>),
293 HasChild(Box<joining::HasChildQuery>),
294 HasParent(Box<joining::HasParentQuery>),
295
296 GeoShape(Box<geo::GeoShapeQuery>),
298 GeoBoundingBox(Box<geo::GeoBoundingBoxQuery>),
299 GeoDistance(Box<geo::GeoDistanceQuery>),
300 GeoPolygon(Box<geo::GeoPolygonQuery>),
303 GeohashCell(Box<geo::GeohashCellQuery>),
304
305 MoreLikeThis(Box<specialized::MoreLikeThisQuery>),
307 }
320
321impl Default for Query {
322 fn default() -> Query {
323 Query::MatchAll(Default::default())
324 }
325}
326
327impl Serialize for Query {
328 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
329 where
330 S: Serializer,
331 {
332 use self::Query::*;
333
334 let mut map_ser = serializer.serialize_map(Some(1))?;
335 (match self {
336 MatchAll(ref q) => map_ser.serialize_entry("match_all", q),
338
339 Match(ref q) => map_ser.serialize_entry("match", q),
341 MultiMatch(ref q) => map_ser.serialize_entry("multi_match", q),
342 Common(ref q) => map_ser.serialize_entry("common", q),
343 QueryString(ref q) => map_ser.serialize_entry("query_string", q),
344 SimpleQueryString(ref q) => map_ser.serialize_entry("simple_query_string", q),
345
346 Term(ref q) => map_ser.serialize_entry("term", q),
348 Terms(ref q) => map_ser.serialize_entry("terms", q),
349 Range(ref q) => map_ser.serialize_entry("range", q),
350 Exists(ref q) => map_ser.serialize_entry("exists", q),
351 Prefix(ref q) => map_ser.serialize_entry("prefix", q),
352 Wildcard(ref q) => map_ser.serialize_entry("wildcard", q),
353 Regexp(ref q) => map_ser.serialize_entry("regexp", q),
354 Fuzzy(ref q) => map_ser.serialize_entry("fuzzy", q),
355 Type(ref q) => map_ser.serialize_entry("type", q),
356 Ids(ref q) => map_ser.serialize_entry("ids", q),
357
358 ConstantScore(ref q) => map_ser.serialize_entry("constant_score", q),
360 Bool(ref q) => map_ser.serialize_entry("bool", q),
361 DisMax(ref q) => map_ser.serialize_entry("dis_max", q),
362 FunctionScore(ref q) => map_ser.serialize_entry("function_score", q),
363 Boosting(ref q) => map_ser.serialize_entry("boosting", q),
364 Indices(ref q) => map_ser.serialize_entry("indices", q),
365
366 Nested(ref q) => map_ser.serialize_entry("nested", q),
368 HasChild(ref q) => map_ser.serialize_entry("has_child", q),
369 HasParent(ref q) => map_ser.serialize_entry("has_parent", q),
370
371 GeoShape(ref q) => map_ser.serialize_entry("geo_shape", q),
373 GeoBoundingBox(ref q) => map_ser.serialize_entry("geo_bounding_box", q),
374 GeoDistance(ref q) => map_ser.serialize_entry("geo_distance", q),
375 GeoPolygon(ref q) => map_ser.serialize_entry("geo_polygon", q),
376 GeohashCell(ref q) => map_ser.serialize_entry("geohash_cell", q),
377
378 MoreLikeThis(ref q) => map_ser.serialize_entry("more_like_this", q),
380 })?;
381 map_ser.end()
382 }
383}
384
385#[derive(Debug, Default, Serialize)]
390pub struct MatchAllQuery {
391 #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
392 boost: Option<f64>,
393}
394
395impl Query {
396 pub fn build_match_all() -> MatchAllQuery {
397 MatchAllQuery::default()
398 }
399}
400
401impl MatchAllQuery {
402 add_field!(with_boost, boost, f64);
403
404 build!(MatchAll);
405}
406
407#[cfg(test)]
408mod tests {
409 extern crate serde_json;
410
411 use super::full_text::SimpleQueryStringFlags;
412 use super::functions::Function;
413 use super::term::TermsQueryLookup;
414 use super::{Flags, Query};
415
416 #[test]
417 fn test_simple_query_string_flags() {
418 let opts = vec![SimpleQueryStringFlags::And, SimpleQueryStringFlags::Not];
419 let flags: Flags<SimpleQueryStringFlags> = opts.into();
420 let json = serde_json::to_string(&flags);
421 assert_eq!("\"AND|NOT\"", json.unwrap());
422 }
423
424 #[test]
425 fn test_terms_query() {
426 let terms_query = Query::build_terms("field_name")
427 .with_values(vec!["a", "b", "c"])
428 .build();
429 assert_eq!(
430 "{\"terms\":{\"field_name\":[\"a\",\"b\",\"c\"]}}",
431 serde_json::to_string(&terms_query).unwrap()
432 );
433
434 let terms_query_2 = Query::build_terms("field_name")
435 .with_values(["a", "b", "c"].as_ref())
436 .build();
437 assert_eq!(
438 "{\"terms\":{\"field_name\":[\"a\",\"b\",\"c\"]}}",
439 serde_json::to_string(&terms_query_2).unwrap()
440 );
441
442 let terms_query_3 = Query::build_terms("field_name")
443 .with_values(TermsQueryLookup::new(123, "blah.de.blah").with_index("other"))
444 .build();
445 assert_eq!("{\"terms\":{\"field_name\":{\"id\":123,\"index\":\"other\",\"path\":\"blah.de.blah\"}}}",
446 serde_json::to_string(&terms_query_3).unwrap());
447 }
448
449 #[test]
450 fn test_function_score_query() {
451 let function_score_query = Query::build_function_score()
452 .with_function(
453 Function::build_script_score("this_is_a_script")
454 .with_lang("made_up")
455 .add_param("A", 12)
456 .build(),
457 )
458 .build();
459 assert_eq!("{\"function_score\":{\"functions\":[{\"script_score\":{\"lang\":\"made_up\",\"params\":{\"A\":12},\"inline\":\"this_is_a_script\"}}]}}",
460 serde_json::to_string(&function_score_query).unwrap());
461 }
462
463 #[test]
464 fn test_exists_query() {
465 let exists_query = Query::build_exists("name").build();
466 assert_eq!(
467 "{\"exists\":{\"field\":\"name\"}}",
468 serde_json::to_string(&exists_query).unwrap()
469 );
470 }
471}