rs_es/query/
term.rs

1/*
2 * Copyright 2016-2019 Ben Ashford
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! Specific Term level queries
18
19use serde::{Serialize, Serializer};
20
21use crate::{
22    json::{NoOuter, ShouldSkip},
23    units::{JsonPotential, JsonVal, OneOrMany},
24};
25
26use super::{common::FieldBasedQuery, Flags, Fuzziness, Query};
27
28/// Values of the rewrite option used by multi-term queries
29#[derive(Debug)]
30pub enum Rewrite {
31    ConstantScoreAuto,
32    ScoringBoolean,
33    ConstantScoreBoolean,
34    ConstantScoreFilter,
35    TopTerms(i64),
36    TopTermsBoost(i64),
37    TopTermsBlendedFreqs(i64),
38}
39
40impl Serialize for Rewrite {
41    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
42    where
43        S: Serializer,
44    {
45        use self::Rewrite::*;
46        match self {
47            ConstantScoreAuto => "constant_score_auto".serialize(serializer),
48            ScoringBoolean => "scoring_boolean".serialize(serializer),
49            ConstantScoreBoolean => "constant_score_boolean".serialize(serializer),
50            ConstantScoreFilter => "constant_score_filter".serialize(serializer),
51            TopTerms(n) => format!("top_terms_{}", n).serialize(serializer),
52            TopTermsBoost(n) => format!("top_terms_boost_{}", n).serialize(serializer),
53            TopTermsBlendedFreqs(n) => {
54                format!("top_terms_blended_freqs_{}", n).serialize(serializer)
55            }
56        }
57    }
58}
59
60/// Term query
61#[derive(Debug, Default, Serialize)]
62pub struct TermQueryInner {
63    value: JsonVal,
64    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
65    boost: Option<f64>,
66}
67
68impl TermQueryInner {
69    fn new(value: JsonVal) -> Self {
70        TermQueryInner {
71            value,
72            ..Default::default()
73        }
74    }
75}
76
77#[derive(Debug, Serialize)]
78pub struct TermQuery(FieldBasedQuery<TermQueryInner, NoOuter>);
79
80impl Query {
81    pub fn build_term<A, B>(field: A, value: B) -> TermQuery
82    where
83        A: Into<String>,
84        B: Into<JsonVal>,
85    {
86        TermQuery(FieldBasedQuery::new(
87            field.into(),
88            TermQueryInner::new(value.into()),
89            NoOuter,
90        ))
91    }
92}
93
94impl TermQuery {
95    add_inner_field!(with_boost, boost, f64);
96
97    build!(Term);
98}
99
100// Terms query
101/// Terms Query Lookup
102#[derive(Debug, Default, Serialize)]
103pub struct TermsQueryLookup {
104    id: JsonVal,
105    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
106    index: Option<String>,
107    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
108    doc_type: Option<String>,
109    path: String,
110    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
111    routing: Option<String>,
112}
113
114impl<'a> TermsQueryLookup {
115    pub fn new<A, B>(id: A, path: B) -> TermsQueryLookup
116    where
117        A: Into<JsonVal>,
118        B: Into<String>,
119    {
120        TermsQueryLookup {
121            id: id.into(),
122            path: path.into(),
123            ..Default::default()
124        }
125    }
126
127    add_field!(with_index, index, String);
128    add_field!(with_type, doc_type, String);
129    add_field!(with_routing, routing, String);
130}
131
132/// TermsQueryIn
133#[derive(Debug)]
134pub enum TermsQueryIn {
135    /// A `Vec` of values
136    Values(Vec<JsonVal>),
137
138    /// An indirect reference to another document
139    Lookup(TermsQueryLookup),
140}
141
142// TODO - if this looks useful it can be extracted into a macro
143impl Serialize for TermsQueryIn {
144    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
145    where
146        S: Serializer,
147    {
148        match self {
149            TermsQueryIn::Values(ref q) => q.serialize(serializer),
150            TermsQueryIn::Lookup(ref q) => q.serialize(serializer),
151        }
152    }
153}
154
155impl Default for TermsQueryIn {
156    fn default() -> Self {
157        TermsQueryIn::Values(Default::default())
158    }
159}
160
161impl From<TermsQueryLookup> for TermsQueryIn {
162    fn from(from: TermsQueryLookup) -> TermsQueryIn {
163        TermsQueryIn::Lookup(from)
164    }
165}
166
167impl From<Vec<JsonVal>> for TermsQueryIn {
168    fn from(from: Vec<JsonVal>) -> TermsQueryIn {
169        TermsQueryIn::Values(from)
170    }
171}
172
173impl<'a, A> From<&'a [A]> for TermsQueryIn
174where
175    A: JsonPotential,
176{
177    fn from(from: &'a [A]) -> Self {
178        TermsQueryIn::Values(from.iter().map(JsonPotential::to_json_val).collect())
179    }
180}
181
182impl<A> From<Vec<A>> for TermsQueryIn
183where
184    A: JsonPotential,
185{
186    fn from(from: Vec<A>) -> TermsQueryIn {
187        (&from[..]).into()
188    }
189}
190
191/// Terms Query
192#[derive(Debug, Serialize)]
193pub struct TermsQuery(FieldBasedQuery<TermsQueryIn, NoOuter>);
194
195impl Query {
196    pub fn build_terms<A>(field: A) -> TermsQuery
197    where
198        A: Into<String>,
199    {
200        TermsQuery(FieldBasedQuery::new(
201            field.into(),
202            Default::default(),
203            NoOuter,
204        ))
205    }
206}
207
208impl TermsQuery {
209    pub fn with_values<T>(mut self, values: T) -> Self
210    where
211        T: Into<TermsQueryIn>,
212    {
213        self.0.inner = values.into();
214        self
215    }
216
217    build!(Terms);
218}
219
220/// Range query
221/// TODO: Check all possible combinations: gt, gte, lte, lt, from, to, include_upper, include_lower
222/// and share with other range queries
223#[derive(Debug, Default, Serialize)]
224pub struct RangeQueryInner {
225    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
226    gte: Option<JsonVal>,
227    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
228    gt: Option<JsonVal>,
229    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
230    lte: Option<JsonVal>,
231    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
232    lt: Option<JsonVal>,
233    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
234    boost: Option<f64>,
235    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
236    time_zone: Option<String>,
237    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
238    format: Option<String>,
239}
240
241#[derive(Debug, Serialize)]
242pub struct RangeQuery(FieldBasedQuery<RangeQueryInner, NoOuter>);
243
244impl Query {
245    pub fn build_range<A>(field: A) -> RangeQuery
246    where
247        A: Into<String>,
248    {
249        RangeQuery(FieldBasedQuery::new(
250            field.into(),
251            Default::default(),
252            NoOuter,
253        ))
254    }
255}
256
257impl RangeQuery {
258    add_inner_field!(with_gte, gte, JsonVal);
259    add_inner_field!(with_gt, gt, JsonVal);
260    add_inner_field!(with_lte, lte, JsonVal);
261    add_inner_field!(with_lt, lt, JsonVal);
262    add_inner_field!(with_boost, boost, f64);
263    add_inner_field!(with_time_zone, time_zone, String);
264    add_inner_field!(with_format, format, String);
265
266    build!(Range);
267}
268
269/// Exists query
270#[derive(Debug, Serialize)]
271pub struct ExistsQuery {
272    field: String,
273}
274
275impl Query {
276    pub fn build_exists<A>(field: A) -> ExistsQuery
277    where
278        A: Into<String>,
279    {
280        ExistsQuery {
281            field: field.into(),
282        }
283    }
284}
285
286impl ExistsQuery {
287    build!(Exists);
288}
289
290/// Prefix query
291#[derive(Debug, Serialize)]
292pub struct PrefixQuery(FieldBasedQuery<PrefixQueryInner, NoOuter>);
293
294#[derive(Debug, Default, Serialize)]
295pub struct PrefixQueryInner {
296    value: String,
297    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
298    boost: Option<f64>,
299    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
300    rewrite: Option<Rewrite>,
301}
302
303impl Query {
304    pub fn build_prefix<A, B>(field: A, value: B) -> PrefixQuery
305    where
306        A: Into<String>,
307        B: Into<String>,
308    {
309        PrefixQuery(FieldBasedQuery::new(
310            field.into(),
311            PrefixQueryInner {
312                value: value.into(),
313                ..Default::default()
314            },
315            NoOuter,
316        ))
317    }
318}
319
320impl PrefixQuery {
321    add_inner_field!(with_boost, boost, f64);
322    add_inner_field!(with_rewrite, rewrite, Rewrite);
323
324    build!(Prefix);
325}
326
327/// Wildcard query
328#[derive(Debug, Serialize)]
329pub struct WildcardQuery(FieldBasedQuery<WildcardQueryInner, NoOuter>);
330
331#[derive(Debug, Default, Serialize)]
332pub struct WildcardQueryInner {
333    value: String,
334    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
335    boost: Option<f64>,
336    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
337    rewrite: Option<Rewrite>,
338}
339
340impl Query {
341    pub fn build_wildcard<A, B>(field: A, value: B) -> WildcardQuery
342    where
343        A: Into<String>,
344        B: Into<String>,
345    {
346        WildcardQuery(FieldBasedQuery::new(
347            field.into(),
348            WildcardQueryInner {
349                value: value.into(),
350                ..Default::default()
351            },
352            NoOuter,
353        ))
354    }
355}
356
357impl WildcardQuery {
358    add_inner_field!(with_boost, boost, f64);
359    add_inner_field!(with_rewrite, rewrite, Rewrite);
360
361    build!(Wildcard);
362}
363
364// Regexp query
365/// Flags for the Regexp query
366#[derive(Debug)]
367pub enum RegexpQueryFlags {
368    All,
369    Anystring,
370    Complement,
371    Empty,
372    Intersection,
373    Interval,
374    None,
375}
376
377impl AsRef<str> for RegexpQueryFlags {
378    fn as_ref(&self) -> &str {
379        match self {
380            RegexpQueryFlags::All => "ALL",
381            RegexpQueryFlags::Anystring => "ANYSTRING",
382            RegexpQueryFlags::Complement => "COMPLEMENT",
383            RegexpQueryFlags::Empty => "EMPTY",
384            RegexpQueryFlags::Intersection => "INTERSECTION",
385            RegexpQueryFlags::Interval => "INTERVAL",
386            RegexpQueryFlags::None => "NONE",
387        }
388    }
389}
390
391/// Regexp query
392#[derive(Debug, Serialize)]
393pub struct RegexpQuery(FieldBasedQuery<RegexpQueryInner, NoOuter>);
394
395#[derive(Debug, Default, Serialize)]
396pub struct RegexpQueryInner {
397    value: String,
398    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
399    boost: Option<f64>,
400    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
401    flags: Option<Flags<RegexpQueryFlags>>,
402    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
403    max_determined_states: Option<u64>,
404}
405
406impl Query {
407    pub fn build_query<A, B>(field: A, value: B) -> RegexpQuery
408    where
409        A: Into<String>,
410        B: Into<String>,
411    {
412        RegexpQuery(FieldBasedQuery::new(
413            field.into(),
414            RegexpQueryInner {
415                value: value.into(),
416                ..Default::default()
417            },
418            NoOuter,
419        ))
420    }
421}
422
423impl RegexpQuery {
424    add_inner_field!(with_boost, boost, f64);
425    add_inner_field!(with_flags, flags, Flags<RegexpQueryFlags>);
426    add_inner_field!(with_max_determined_states, max_determined_states, u64);
427
428    build!(Regexp);
429}
430
431/// Fuzzy query
432#[derive(Debug, Serialize)]
433pub struct FuzzyQuery(FieldBasedQuery<FuzzyQueryInner, NoOuter>);
434
435#[derive(Debug, Default, Serialize)]
436pub struct FuzzyQueryInner {
437    value: String,
438    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
439    boost: Option<f64>,
440    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
441    fuzziness: Option<Fuzziness>,
442    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
443    prefix_length: Option<u64>,
444    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
445    max_expansions: Option<u64>,
446}
447
448impl Query {
449    pub fn build_fuzzy<A, B>(field: A, value: B) -> FuzzyQuery
450    where
451        A: Into<String>,
452        B: Into<String>,
453    {
454        FuzzyQuery(FieldBasedQuery::new(
455            field.into(),
456            FuzzyQueryInner {
457                value: value.into(),
458                ..Default::default()
459            },
460            NoOuter,
461        ))
462    }
463}
464
465impl FuzzyQuery {
466    add_inner_field!(with_boost, boost, f64);
467    add_inner_field!(with_fuzziness, fuzziness, Fuzziness);
468    add_inner_field!(with_prefix_length, prefix_length, u64);
469    add_inner_field!(with_max_expansions, max_expansions, u64);
470
471    build!(Fuzzy);
472}
473
474/// Type query
475#[derive(Debug, Serialize)]
476pub struct TypeQuery {
477    value: String,
478}
479
480impl Query {
481    pub fn build_type<A>(value: A) -> TypeQuery
482    where
483        A: Into<String>,
484    {
485        TypeQuery {
486            value: value.into(),
487        }
488    }
489}
490
491impl TypeQuery {
492    build!(Type);
493}
494
495/// Ids query
496#[derive(Debug, Default, Serialize)]
497pub struct IdsQuery {
498    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
499    doc_type: Option<OneOrMany<String>>,
500    values: Vec<JsonVal>,
501}
502
503impl Query {
504    pub fn build_ids<A>(values: A) -> IdsQuery
505    where
506        A: Into<Vec<JsonVal>>,
507    {
508        IdsQuery {
509            values: values.into(),
510            ..Default::default()
511        }
512    }
513}
514
515impl IdsQuery {
516    add_field!(with_type, doc_type, OneOrMany<String>);
517
518    build!(Ids);
519}