1use std::marker::PhantomData;
8
9use serde_json::{Map, Value};
10
11use super::{Common, MinimumShouldMatch, Operator, Text, common_opts, wrap};
12use crate::query::{AsQuery, Query, Root};
13
14fn string_array(values: impl IntoIterator<Item = impl Into<String>>) -> Vec<Value> {
15 values
16 .into_iter()
17 .map(|v| Value::String(v.into()))
18 .collect()
19}
20
21fn field_specs<S, Sub>(fields: impl IntoIterator<Item = Text<S, Sub>>) -> Vec<Value> {
22 fields
23 .into_iter()
24 .map(|f| Value::String(f.field_spec()))
25 .collect()
26}
27
28pub fn ids<S>(values: impl IntoIterator<Item = impl Into<String>>) -> IdsQuery<S> {
30 IdsQuery {
31 values: string_array(values),
32 common: Common::default(),
33 _scope: PhantomData,
34 }
35}
36
37#[derive(Debug, Clone)]
39pub struct IdsQuery<S = Root> {
40 values: Vec<Value>,
41 common: Common,
42 _scope: PhantomData<fn() -> S>,
43}
44
45impl<S> IdsQuery<S> {
46 common_opts!(common);
47}
48
49impl<S> AsQuery<S> for IdsQuery<S> {
50 fn into_query(self) -> Option<Query<S>> {
51 let mut body = Map::new();
52 body.insert("values".to_string(), Value::Array(self.values));
53 self.common.write(&mut body);
54 Some(wrap("ids", body))
55 }
56}
57
58pub fn query_string<S>(query: impl Into<String>) -> QueryStringQuery<S> {
62 QueryStringQuery {
63 query: query.into(),
64 opts: Map::new(),
65 common: Common::default(),
66 _scope: PhantomData,
67 }
68}
69
70#[derive(Debug, Clone)]
72pub struct QueryStringQuery<S = Root> {
73 query: String,
74 opts: Map<String, Value>,
75 common: Common,
76 _scope: PhantomData<fn() -> S>,
77}
78
79impl<S> QueryStringQuery<S> {
80 #[must_use]
82 pub fn default_field(mut self, field: impl Into<String>) -> Self {
83 self.opts
84 .insert("default_field".to_string(), Value::String(field.into()));
85 self
86 }
87
88 #[must_use]
90 pub fn fields<Sub>(mut self, fields: impl IntoIterator<Item = Text<S, Sub>>) -> Self {
91 self.opts
92 .insert("fields".to_string(), Value::Array(field_specs(fields)));
93 self
94 }
95
96 #[must_use]
98 pub fn default_operator(mut self, operator: Operator) -> Self {
99 self.opts.insert(
100 "default_operator".to_string(),
101 Value::String(operator.as_str().to_string()),
102 );
103 self
104 }
105
106 #[must_use]
108 pub fn analyzer(mut self, analyzer: impl Into<String>) -> Self {
109 self.opts
110 .insert("analyzer".to_string(), Value::String(analyzer.into()));
111 self
112 }
113
114 #[must_use]
116 pub fn lenient(mut self, lenient: bool) -> Self {
117 self.opts
118 .insert("lenient".to_string(), Value::Bool(lenient));
119 self
120 }
121
122 #[must_use]
124 pub fn param(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
125 self.opts.insert(key.into(), value.into());
126 self
127 }
128
129 common_opts!(common);
130}
131
132impl<S> AsQuery<S> for QueryStringQuery<S> {
133 fn into_query(self) -> Option<Query<S>> {
134 let mut body = self.opts;
135 body.insert("query".to_string(), Value::String(self.query));
136 self.common.write(&mut body);
137 Some(wrap("query_string", body))
138 }
139}
140
141pub fn simple_query_string<S>(query: impl Into<String>) -> SimpleQueryStringQuery<S> {
143 SimpleQueryStringQuery {
144 query: query.into(),
145 opts: Map::new(),
146 common: Common::default(),
147 _scope: PhantomData,
148 }
149}
150
151#[derive(Debug, Clone)]
153pub struct SimpleQueryStringQuery<S = Root> {
154 query: String,
155 opts: Map<String, Value>,
156 common: Common,
157 _scope: PhantomData<fn() -> S>,
158}
159
160impl<S> SimpleQueryStringQuery<S> {
161 #[must_use]
163 pub fn fields<Sub>(mut self, fields: impl IntoIterator<Item = Text<S, Sub>>) -> Self {
164 self.opts
165 .insert("fields".to_string(), Value::Array(field_specs(fields)));
166 self
167 }
168
169 #[must_use]
171 pub fn default_operator(mut self, operator: Operator) -> Self {
172 self.opts.insert(
173 "default_operator".to_string(),
174 Value::String(operator.as_str().to_string()),
175 );
176 self
177 }
178
179 #[must_use]
181 pub fn analyzer(mut self, analyzer: impl Into<String>) -> Self {
182 self.opts
183 .insert("analyzer".to_string(), Value::String(analyzer.into()));
184 self
185 }
186
187 #[must_use]
189 pub fn flags(mut self, flags: impl Into<String>) -> Self {
190 self.opts
191 .insert("flags".to_string(), Value::String(flags.into()));
192 self
193 }
194
195 #[must_use]
197 pub fn minimum_should_match(mut self, value: impl Into<MinimumShouldMatch>) -> Self {
198 self.opts
199 .insert("minimum_should_match".to_string(), value.into().to_value());
200 self
201 }
202
203 common_opts!(common);
204}
205
206impl<S> AsQuery<S> for SimpleQueryStringQuery<S> {
207 fn into_query(self) -> Option<Query<S>> {
208 let mut body = self.opts;
209 body.insert("query".to_string(), Value::String(self.query));
210 self.common.write(&mut body);
211 Some(wrap("simple_query_string", body))
212 }
213}
214
215pub fn combined_fields<S, Sub>(
218 query: impl Into<String>,
219 fields: impl IntoIterator<Item = Text<S, Sub>>,
220) -> CombinedFieldsQuery<S> {
221 CombinedFieldsQuery {
222 query: query.into(),
223 fields: field_specs(fields),
224 opts: Map::new(),
225 common: Common::default(),
226 _scope: PhantomData,
227 }
228}
229
230#[derive(Debug, Clone)]
232pub struct CombinedFieldsQuery<S = Root> {
233 query: String,
234 fields: Vec<Value>,
235 opts: Map<String, Value>,
236 common: Common,
237 _scope: PhantomData<fn() -> S>,
238}
239
240impl<S> CombinedFieldsQuery<S> {
241 #[must_use]
243 pub fn operator(mut self, operator: Operator) -> Self {
244 self.opts.insert(
245 "operator".to_string(),
246 Value::String(operator.as_str().to_string()),
247 );
248 self
249 }
250
251 #[must_use]
253 pub fn minimum_should_match(mut self, value: impl Into<MinimumShouldMatch>) -> Self {
254 self.opts
255 .insert("minimum_should_match".to_string(), value.into().to_value());
256 self
257 }
258
259 common_opts!(common);
260}
261
262impl<S> AsQuery<S> for CombinedFieldsQuery<S> {
263 fn into_query(self) -> Option<Query<S>> {
264 let mut body = self.opts;
265 body.insert("query".to_string(), Value::String(self.query));
266 body.insert("fields".to_string(), Value::Array(self.fields));
267 self.common.write(&mut body);
268 Some(wrap("combined_fields", body))
269 }
270}
271
272pub fn script<S>(source: impl Into<String>) -> ScriptQuery<S> {
275 ScriptQuery {
276 source: source.into(),
277 params: None,
278 lang: None,
279 common: Common::default(),
280 _scope: PhantomData,
281 }
282}
283
284#[derive(Debug, Clone)]
286pub struct ScriptQuery<S = Root> {
287 source: String,
288 params: Option<Value>,
289 lang: Option<String>,
290 common: Common,
291 _scope: PhantomData<fn() -> S>,
292}
293
294impl<S> ScriptQuery<S> {
295 #[must_use]
297 pub fn params(mut self, params: Value) -> Self {
298 self.params = Some(params);
299 self
300 }
301
302 #[must_use]
304 pub fn lang(mut self, lang: impl Into<String>) -> Self {
305 self.lang = Some(lang.into());
306 self
307 }
308
309 common_opts!(common);
310}
311
312fn script_object(source: String, params: Option<Value>, lang: Option<String>) -> Value {
313 let mut script = Map::new();
314 script.insert("source".to_string(), Value::String(source));
315 if let Some(params) = params {
316 script.insert("params".to_string(), params);
317 }
318 if let Some(lang) = lang {
319 script.insert("lang".to_string(), Value::String(lang));
320 }
321 Value::Object(script)
322}
323
324impl<S> AsQuery<S> for ScriptQuery<S> {
325 fn into_query(self) -> Option<Query<S>> {
326 let mut body = Map::new();
327 body.insert(
328 "script".to_string(),
329 script_object(self.source, self.params, self.lang),
330 );
331 self.common.write(&mut body);
332 Some(wrap("script", body))
333 }
334}
335
336pub fn script_score<S>(query: impl AsQuery<S>, source: impl Into<String>) -> ScriptScoreQuery<S> {
338 ScriptScoreQuery {
339 query: query
340 .into_query()
341 .map_or_else(super::match_all_value, |q| q.to_value()),
342 source: source.into(),
343 params: None,
344 min_score: None,
345 common: Common::default(),
346 _scope: PhantomData,
347 }
348}
349
350#[derive(Debug, Clone)]
352pub struct ScriptScoreQuery<S = Root> {
353 query: Value,
354 source: String,
355 params: Option<Value>,
356 min_score: Option<f32>,
357 common: Common,
358 _scope: PhantomData<fn() -> S>,
359}
360
361impl<S> ScriptScoreQuery<S> {
362 #[must_use]
364 pub fn params(mut self, params: Value) -> Self {
365 self.params = Some(params);
366 self
367 }
368
369 #[must_use]
371 pub fn min_score(mut self, min_score: f32) -> Self {
372 self.min_score = Some(min_score);
373 self
374 }
375
376 common_opts!(common);
377}
378
379impl<S> AsQuery<S> for ScriptScoreQuery<S> {
380 fn into_query(self) -> Option<Query<S>> {
381 let mut body = Map::new();
382 body.insert("query".to_string(), self.query);
383 body.insert(
384 "script".to_string(),
385 script_object(self.source, self.params, None),
386 );
387 if let Some(min_score) = self.min_score {
388 body.insert("min_score".to_string(), Value::from(min_score));
389 }
390 self.common.write(&mut body);
391 Some(wrap("script_score", body))
392 }
393}
394
395pub fn distance_feature<S>(
398 field: impl Into<String>,
399 origin: impl Into<Value>,
400 pivot: impl Into<String>,
401) -> DistanceFeatureQuery<S> {
402 DistanceFeatureQuery {
403 field: field.into(),
404 origin: origin.into(),
405 pivot: pivot.into(),
406 common: Common::default(),
407 _scope: PhantomData,
408 }
409}
410
411#[derive(Debug, Clone)]
413pub struct DistanceFeatureQuery<S = Root> {
414 field: String,
415 origin: Value,
416 pivot: String,
417 common: Common,
418 _scope: PhantomData<fn() -> S>,
419}
420
421impl<S> DistanceFeatureQuery<S> {
422 common_opts!(common);
423}
424
425impl<S> AsQuery<S> for DistanceFeatureQuery<S> {
426 fn into_query(self) -> Option<Query<S>> {
427 let mut body = Map::new();
428 body.insert("field".to_string(), Value::String(self.field));
429 body.insert("origin".to_string(), self.origin);
430 body.insert("pivot".to_string(), Value::String(self.pivot));
431 self.common.write(&mut body);
432 Some(wrap("distance_feature", body))
433 }
434}
435
436pub fn rank_feature<S>(field: impl Into<String>) -> RankFeatureQuery<S> {
439 RankFeatureQuery {
440 field: field.into(),
441 function: None,
442 common: Common::default(),
443 _scope: PhantomData,
444 }
445}
446
447#[derive(Debug, Clone)]
449pub struct RankFeatureQuery<S = Root> {
450 field: String,
451 function: Option<(&'static str, Value)>,
452 common: Common,
453 _scope: PhantomData<fn() -> S>,
454}
455
456impl<S> RankFeatureQuery<S> {
457 #[must_use]
459 pub fn saturation(mut self, pivot: f32) -> Self {
460 let mut body = Map::new();
461 body.insert("pivot".to_string(), Value::from(pivot));
462 self.function = Some(("saturation", Value::Object(body)));
463 self
464 }
465
466 #[must_use]
468 pub fn log(mut self, scaling_factor: f32) -> Self {
469 let mut body = Map::new();
470 body.insert("scaling_factor".to_string(), Value::from(scaling_factor));
471 self.function = Some(("log", Value::Object(body)));
472 self
473 }
474
475 #[must_use]
477 pub fn sigmoid(mut self, pivot: f32, exponent: f32) -> Self {
478 let mut body = Map::new();
479 body.insert("pivot".to_string(), Value::from(pivot));
480 body.insert("exponent".to_string(), Value::from(exponent));
481 self.function = Some(("sigmoid", Value::Object(body)));
482 self
483 }
484
485 common_opts!(common);
486}
487
488impl<S> AsQuery<S> for RankFeatureQuery<S> {
489 fn into_query(self) -> Option<Query<S>> {
490 let mut body = Map::new();
491 body.insert("field".to_string(), Value::String(self.field));
492 if let Some((name, function)) = self.function {
493 body.insert(name.to_string(), function);
494 }
495 self.common.write(&mut body);
496 Some(wrap("rank_feature", body))
497 }
498}
499
500pub fn more_like_this<S, Sub>(
502 fields: impl IntoIterator<Item = Text<S, Sub>>,
503 like: impl IntoIterator<Item = impl Into<String>>,
504) -> MoreLikeThisQuery<S> {
505 MoreLikeThisQuery {
506 fields: field_specs(fields),
507 like: string_array(like),
508 opts: Map::new(),
509 common: Common::default(),
510 _scope: PhantomData,
511 }
512}
513
514#[derive(Debug, Clone)]
516pub struct MoreLikeThisQuery<S = Root> {
517 fields: Vec<Value>,
518 like: Vec<Value>,
519 opts: Map<String, Value>,
520 common: Common,
521 _scope: PhantomData<fn() -> S>,
522}
523
524impl<S> MoreLikeThisQuery<S> {
525 #[must_use]
527 pub fn min_term_freq(mut self, min_term_freq: u32) -> Self {
528 self.opts
529 .insert("min_term_freq".to_string(), Value::from(min_term_freq));
530 self
531 }
532
533 #[must_use]
535 pub fn max_query_terms(mut self, max_query_terms: u32) -> Self {
536 self.opts
537 .insert("max_query_terms".to_string(), Value::from(max_query_terms));
538 self
539 }
540
541 #[must_use]
543 pub fn minimum_should_match(mut self, value: impl Into<MinimumShouldMatch>) -> Self {
544 self.opts
545 .insert("minimum_should_match".to_string(), value.into().to_value());
546 self
547 }
548
549 common_opts!(common);
550}
551
552impl<S> AsQuery<S> for MoreLikeThisQuery<S> {
553 fn into_query(self) -> Option<Query<S>> {
554 let mut body = self.opts;
555 body.insert("fields".to_string(), Value::Array(self.fields));
556 body.insert("like".to_string(), Value::Array(self.like));
557 self.common.write(&mut body);
558 Some(wrap("more_like_this", body))
559 }
560}