1use std::marker::PhantomData;
8
9use serde_json::{Map, Value};
10
11use super::{Common, 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>(fields: impl IntoIterator<Item = Text<S>>) -> 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(mut self, fields: impl IntoIterator<Item = Text<S>>) -> 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: impl Into<String>) -> Self {
99 self.opts.insert(
100 "default_operator".to_string(),
101 Value::String(operator.into()),
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(mut self, fields: impl IntoIterator<Item = Text<S>>) -> 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: impl Into<String>) -> Self {
172 self.opts.insert(
173 "default_operator".to_string(),
174 Value::String(operator.into()),
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<String>) -> Self {
198 self.opts.insert(
199 "minimum_should_match".to_string(),
200 Value::String(value.into()),
201 );
202 self
203 }
204
205 common_opts!(common);
206}
207
208impl<S> AsQuery<S> for SimpleQueryStringQuery<S> {
209 fn into_query(self) -> Option<Query<S>> {
210 let mut body = self.opts;
211 body.insert("query".to_string(), Value::String(self.query));
212 self.common.write(&mut body);
213 Some(wrap("simple_query_string", body))
214 }
215}
216
217pub fn combined_fields<S>(
220 query: impl Into<String>,
221 fields: impl IntoIterator<Item = Text<S>>,
222) -> CombinedFieldsQuery<S> {
223 CombinedFieldsQuery {
224 query: query.into(),
225 fields: field_specs(fields),
226 opts: Map::new(),
227 common: Common::default(),
228 _scope: PhantomData,
229 }
230}
231
232#[derive(Debug, Clone)]
234pub struct CombinedFieldsQuery<S = Root> {
235 query: String,
236 fields: Vec<Value>,
237 opts: Map<String, Value>,
238 common: Common,
239 _scope: PhantomData<fn() -> S>,
240}
241
242impl<S> CombinedFieldsQuery<S> {
243 #[must_use]
245 pub fn operator(mut self, operator: impl Into<String>) -> Self {
246 self.opts
247 .insert("operator".to_string(), Value::String(operator.into()));
248 self
249 }
250
251 #[must_use]
253 pub fn minimum_should_match(mut self, value: impl Into<String>) -> Self {
254 self.opts.insert(
255 "minimum_should_match".to_string(),
256 Value::String(value.into()),
257 );
258 self
259 }
260
261 common_opts!(common);
262}
263
264impl<S> AsQuery<S> for CombinedFieldsQuery<S> {
265 fn into_query(self) -> Option<Query<S>> {
266 let mut body = self.opts;
267 body.insert("query".to_string(), Value::String(self.query));
268 body.insert("fields".to_string(), Value::Array(self.fields));
269 self.common.write(&mut body);
270 Some(wrap("combined_fields", body))
271 }
272}
273
274pub fn script<S>(source: impl Into<String>) -> ScriptQuery<S> {
277 ScriptQuery {
278 source: source.into(),
279 params: None,
280 lang: None,
281 common: Common::default(),
282 _scope: PhantomData,
283 }
284}
285
286#[derive(Debug, Clone)]
288pub struct ScriptQuery<S = Root> {
289 source: String,
290 params: Option<Value>,
291 lang: Option<String>,
292 common: Common,
293 _scope: PhantomData<fn() -> S>,
294}
295
296impl<S> ScriptQuery<S> {
297 #[must_use]
299 pub fn params(mut self, params: Value) -> Self {
300 self.params = Some(params);
301 self
302 }
303
304 #[must_use]
306 pub fn lang(mut self, lang: impl Into<String>) -> Self {
307 self.lang = Some(lang.into());
308 self
309 }
310
311 common_opts!(common);
312}
313
314fn script_object(source: String, params: Option<Value>, lang: Option<String>) -> Value {
315 let mut script = Map::new();
316 script.insert("source".to_string(), Value::String(source));
317 if let Some(params) = params {
318 script.insert("params".to_string(), params);
319 }
320 if let Some(lang) = lang {
321 script.insert("lang".to_string(), Value::String(lang));
322 }
323 Value::Object(script)
324}
325
326impl<S> AsQuery<S> for ScriptQuery<S> {
327 fn into_query(self) -> Option<Query<S>> {
328 let mut body = Map::new();
329 body.insert(
330 "script".to_string(),
331 script_object(self.source, self.params, self.lang),
332 );
333 self.common.write(&mut body);
334 Some(wrap("script", body))
335 }
336}
337
338pub fn script_score<S>(query: impl AsQuery<S>, source: impl Into<String>) -> ScriptScoreQuery<S> {
340 ScriptScoreQuery {
341 query: query
342 .into_query()
343 .map_or_else(super::match_all_value, |q| q.to_value()),
344 source: source.into(),
345 params: None,
346 min_score: None,
347 common: Common::default(),
348 _scope: PhantomData,
349 }
350}
351
352#[derive(Debug, Clone)]
354pub struct ScriptScoreQuery<S = Root> {
355 query: Value,
356 source: String,
357 params: Option<Value>,
358 min_score: Option<f32>,
359 common: Common,
360 _scope: PhantomData<fn() -> S>,
361}
362
363impl<S> ScriptScoreQuery<S> {
364 #[must_use]
366 pub fn params(mut self, params: Value) -> Self {
367 self.params = Some(params);
368 self
369 }
370
371 #[must_use]
373 pub fn min_score(mut self, min_score: f32) -> Self {
374 self.min_score = Some(min_score);
375 self
376 }
377
378 common_opts!(common);
379}
380
381impl<S> AsQuery<S> for ScriptScoreQuery<S> {
382 fn into_query(self) -> Option<Query<S>> {
383 let mut body = Map::new();
384 body.insert("query".to_string(), self.query);
385 body.insert(
386 "script".to_string(),
387 script_object(self.source, self.params, None),
388 );
389 if let Some(min_score) = self.min_score {
390 body.insert("min_score".to_string(), Value::from(min_score));
391 }
392 self.common.write(&mut body);
393 Some(wrap("script_score", body))
394 }
395}
396
397pub fn distance_feature<S>(
400 field: impl Into<String>,
401 origin: impl Into<Value>,
402 pivot: impl Into<String>,
403) -> DistanceFeatureQuery<S> {
404 DistanceFeatureQuery {
405 field: field.into(),
406 origin: origin.into(),
407 pivot: pivot.into(),
408 common: Common::default(),
409 _scope: PhantomData,
410 }
411}
412
413#[derive(Debug, Clone)]
415pub struct DistanceFeatureQuery<S = Root> {
416 field: String,
417 origin: Value,
418 pivot: String,
419 common: Common,
420 _scope: PhantomData<fn() -> S>,
421}
422
423impl<S> DistanceFeatureQuery<S> {
424 common_opts!(common);
425}
426
427impl<S> AsQuery<S> for DistanceFeatureQuery<S> {
428 fn into_query(self) -> Option<Query<S>> {
429 let mut body = Map::new();
430 body.insert("field".to_string(), Value::String(self.field));
431 body.insert("origin".to_string(), self.origin);
432 body.insert("pivot".to_string(), Value::String(self.pivot));
433 self.common.write(&mut body);
434 Some(wrap("distance_feature", body))
435 }
436}
437
438pub fn rank_feature<S>(field: impl Into<String>) -> RankFeatureQuery<S> {
441 RankFeatureQuery {
442 field: field.into(),
443 function: None,
444 common: Common::default(),
445 _scope: PhantomData,
446 }
447}
448
449#[derive(Debug, Clone)]
451pub struct RankFeatureQuery<S = Root> {
452 field: String,
453 function: Option<(&'static str, Value)>,
454 common: Common,
455 _scope: PhantomData<fn() -> S>,
456}
457
458impl<S> RankFeatureQuery<S> {
459 #[must_use]
461 pub fn saturation(mut self, pivot: f32) -> Self {
462 let mut body = Map::new();
463 body.insert("pivot".to_string(), Value::from(pivot));
464 self.function = Some(("saturation", Value::Object(body)));
465 self
466 }
467
468 #[must_use]
470 pub fn log(mut self, scaling_factor: f32) -> Self {
471 let mut body = Map::new();
472 body.insert("scaling_factor".to_string(), Value::from(scaling_factor));
473 self.function = Some(("log", Value::Object(body)));
474 self
475 }
476
477 #[must_use]
479 pub fn sigmoid(mut self, pivot: f32, exponent: f32) -> Self {
480 let mut body = Map::new();
481 body.insert("pivot".to_string(), Value::from(pivot));
482 body.insert("exponent".to_string(), Value::from(exponent));
483 self.function = Some(("sigmoid", Value::Object(body)));
484 self
485 }
486
487 common_opts!(common);
488}
489
490impl<S> AsQuery<S> for RankFeatureQuery<S> {
491 fn into_query(self) -> Option<Query<S>> {
492 let mut body = Map::new();
493 body.insert("field".to_string(), Value::String(self.field));
494 if let Some((name, function)) = self.function {
495 body.insert(name.to_string(), function);
496 }
497 self.common.write(&mut body);
498 Some(wrap("rank_feature", body))
499 }
500}
501
502pub fn more_like_this<S>(
504 fields: impl IntoIterator<Item = Text<S>>,
505 like: impl IntoIterator<Item = impl Into<String>>,
506) -> MoreLikeThisQuery<S> {
507 MoreLikeThisQuery {
508 fields: field_specs(fields),
509 like: string_array(like),
510 opts: Map::new(),
511 common: Common::default(),
512 _scope: PhantomData,
513 }
514}
515
516#[derive(Debug, Clone)]
518pub struct MoreLikeThisQuery<S = Root> {
519 fields: Vec<Value>,
520 like: Vec<Value>,
521 opts: Map<String, Value>,
522 common: Common,
523 _scope: PhantomData<fn() -> S>,
524}
525
526impl<S> MoreLikeThisQuery<S> {
527 #[must_use]
529 pub fn min_term_freq(mut self, min_term_freq: u32) -> Self {
530 self.opts
531 .insert("min_term_freq".to_string(), Value::from(min_term_freq));
532 self
533 }
534
535 #[must_use]
537 pub fn max_query_terms(mut self, max_query_terms: u32) -> Self {
538 self.opts
539 .insert("max_query_terms".to_string(), Value::from(max_query_terms));
540 self
541 }
542
543 #[must_use]
545 pub fn minimum_should_match(mut self, value: impl Into<String>) -> Self {
546 self.opts.insert(
547 "minimum_should_match".to_string(),
548 Value::String(value.into()),
549 );
550 self
551 }
552
553 common_opts!(common);
554}
555
556impl<S> AsQuery<S> for MoreLikeThisQuery<S> {
557 fn into_query(self) -> Option<Query<S>> {
558 let mut body = self.opts;
559 body.insert("fields".to_string(), Value::Array(self.fields));
560 body.insert("like".to_string(), Value::Array(self.like));
561 self.common.write(&mut body);
562 Some(wrap("more_like_this", body))
563 }
564}