use std::borrow::Cow;
use std::collections::HashMap;
use serde::Serialize;
use serde_json::{Map, Value};
use crate::util::is_empty_slice;
use crate::{QueryType, ToOpenSearchJson};
mod aggregation_type;
mod collapse;
mod highlight;
mod sort_type;
pub use aggregation_type::*;
pub use collapse::*;
pub use highlight::*;
pub use sort_type::*;
#[derive(Default, Debug, Clone, Serialize)]
pub struct SearchRequest<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub query: Option<QueryType<'a>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<u32>,
#[serde(skip_serializing_if = "is_empty_slice", default, borrow)]
pub sort: Cow<'a, [SortType<'a>]>,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
#[serde(borrow)]
pub aggs: HashMap<Cow<'a, str>, AggregationType<'a>>,
#[serde(skip_serializing_if = "is_empty_slice", default, borrow)]
pub _source: Cow<'a, [Cow<'a, str>]>,
#[serde(skip_serializing_if = "Option::is_none")]
pub highlight: Option<Highlight<'a>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub track_total_hits: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub collapse: Option<Collapse<'a>>,
#[serde(skip_serializing_if = "is_empty_slice", default, borrow)]
pub search_after: Cow<'a, [Value]>,
}
impl<'a> SearchRequest<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn query(mut self, query: QueryType<'a>) -> Self {
self.query = Some(query);
self
}
pub fn size(mut self, size: u32) -> Self {
self.size = Some(size);
self
}
pub fn from(mut self, from: u32) -> Self {
self.from = Some(from);
self
}
pub fn sort(mut self, sort: SortType<'a>) -> Self {
self.sort.to_mut().push(sort);
self
}
pub fn agg(mut self, name: impl Into<Cow<'a, str>>, agg: AggregationType<'a>) -> Self {
self.aggs.insert(name.into(), agg);
self
}
pub fn source_fields<I>(mut self, fields: I) -> Self
where
I: IntoIterator,
I::Item: Into<Cow<'a, str>>,
{
self._source = fields.into_iter().map(|s| s.into()).collect();
self
}
pub fn highlight(mut self, highlight: Highlight<'a>) -> Self {
self.highlight = Some(highlight);
self
}
pub fn track_total_hits(mut self, track: bool) -> Self {
self.track_total_hits = Some(track);
self
}
pub fn collapse(mut self, collapse: Collapse<'a>) -> Self {
self.collapse = Some(collapse);
self
}
pub fn search_after<I>(mut self, values: I) -> Self
where
I: Into<Cow<'a, [Value]>>,
{
self.search_after = values.into();
self
}
}
impl<'a> ToOpenSearchJson for SearchRequest<'a> {
fn to_json(&self) -> Value {
let mut result = Map::new();
if let Some(ref query) = self.query {
result.insert("query".to_string(), query.to_json());
}
if let Some(size) = self.size {
result.insert("size".to_string(), Value::Number(size.into()));
}
if let Some(from) = self.from {
result.insert("from".to_string(), Value::Number(from.into()));
}
if !self.sort.is_empty() {
let sorts: Vec<Value> = self.sort.iter().map(|s| s.to_json()).collect();
result.insert("sort".to_string(), Value::Array(sorts));
}
if !self.aggs.is_empty() {
let mut aggs_obj = Map::new();
for (name, agg) in &self.aggs {
aggs_obj.insert(name.to_string(), agg.to_json());
}
result.insert("aggs".to_string(), Value::Object(aggs_obj));
}
if !self._source.is_empty() {
let sources: Vec<Value> = self
._source
.iter()
.map(|s| Value::String(s.to_string()))
.collect();
result.insert("_source".to_string(), Value::Array(sources));
}
if let Some(ref highlight) = self.highlight {
result.insert("highlight".to_string(), highlight.to_json());
}
if let Some(track_total_hits) = self.track_total_hits {
result.insert(
"track_total_hits".to_string(),
Value::Bool(track_total_hits),
);
}
if let Some(ref collapse) = self.collapse {
result.insert("collapse".to_string(), collapse.to_json());
}
if !self.search_after.is_empty() {
result.insert(
"search_after".to_string(),
Value::Array(self.search_after.to_vec()),
);
}
Value::Object(result)
}
}
#[derive(Default, Debug, Clone)]
pub struct SearchRequestBuilder<'a> {
query: Option<QueryType<'a>>,
size: Option<u32>,
from: Option<u32>,
sort: Cow<'a, [SortType<'a>]>,
aggs: HashMap<Cow<'a, str>, AggregationType<'a>>,
_source: Cow<'a, [Cow<'a, str>]>,
highlight: Option<Highlight<'a>>,
track_total_hits: Option<bool>,
collapse: Option<Collapse<'a>>,
search_after: Cow<'a, [Value]>,
}
impl<'a> SearchRequestBuilder<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn query(&mut self, query: QueryType<'a>) -> &mut Self {
self.query = Some(query);
self
}
pub fn size(&mut self, size: u32) -> &mut Self {
self.size = Some(size);
self
}
pub fn from(&mut self, from: u32) -> &mut Self {
self.from = Some(from);
self
}
pub fn add_sort(&mut self, sort: SortType<'a>) -> &mut Self {
self.sort.to_mut().push(sort);
self
}
pub fn set_sorts(&mut self, sorts: Cow<'a, [SortType<'a>]>) -> &mut Self {
self.sort = sorts;
self
}
pub fn clear_sorts(&mut self) -> &mut Self {
self.sort = Cow::Borrowed(&[]);
self
}
pub fn add_agg(
&mut self,
name: impl Into<Cow<'a, str>>,
agg: AggregationType<'a>,
) -> &mut Self {
self.aggs.insert(name.into(), agg);
self
}
pub fn remove_agg(&mut self, name: impl Into<Cow<'a, str>>) -> &mut Self {
self.aggs.remove(&name.into());
self
}
pub fn clear_aggs(&mut self) -> &mut Self {
self.aggs.clear();
self
}
pub fn add_source_field(&mut self, field: impl Into<Cow<'a, str>>) -> &mut Self {
self._source.to_mut().push(field.into());
self
}
pub fn set_source_fields<I>(&mut self, fields: I) -> &mut Self
where
I: IntoIterator,
I::Item: Into<Cow<'a, str>>,
{
self._source = fields.into_iter().map(|s| s.into()).collect();
self
}
pub fn clear_source_fields(&mut self) -> &mut Self {
self._source = Cow::Borrowed(&[]);
self
}
pub fn highlight(&mut self, highlight: Highlight<'a>) -> &mut Self {
self.highlight = Some(highlight);
self
}
pub fn track_total_hits(&mut self, track: bool) -> &mut Self {
self.track_total_hits = Some(track);
self
}
pub fn collapse(&mut self, collapse: Collapse<'a>) -> &mut Self {
self.collapse = Some(collapse);
self
}
pub fn add_search_after_value(&mut self, value: Value) -> &mut Self {
self.search_after.to_mut().push(value);
self
}
pub fn set_search_after<I>(&mut self, values: I) -> &mut Self
where
I: Into<Cow<'a, [Value]>>,
{
self.search_after = values.into();
self
}
pub fn clear_search_after(&mut self) -> &mut Self {
self.search_after = Cow::Borrowed(&[]);
self
}
pub fn build(self) -> SearchRequest<'a> {
SearchRequest {
query: self.query,
size: self.size,
from: self.from,
sort: self.sort,
aggs: self.aggs,
_source: self._source,
highlight: self.highlight,
track_total_hits: self.track_total_hits,
collapse: self.collapse,
search_after: self.search_after,
}
}
}