use serde::{Deserialize, Deserializer, Serialize};
use crate::{search::*, util::*};
#[derive(Default, Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(remote = "Self")]
pub struct TermsLookupQuery {
#[serde(skip)]
field: String,
#[serde(skip)]
terms_lookup: TermsLookup,
#[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
boost: Option<f32>,
#[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
_name: Option<String>,
}
#[derive(Default, Debug, Clone, PartialEq, Deserialize, Serialize)]
struct TermsLookup {
index: String,
id: String,
path: String,
#[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
routing: Option<String>,
}
impl Query {
pub fn terms_lookup<S, T, U, V>(field: S, index: T, id: U, path: V) -> TermsLookupQuery
where
S: ToString,
T: ToString,
U: ToString,
V: ToString,
{
TermsLookupQuery {
field: field.to_string(),
terms_lookup: TermsLookup {
index: index.to_string(),
id: id.to_string(),
path: path.to_string(),
routing: None,
},
boost: None,
_name: None,
}
}
}
impl TermsLookupQuery {
add_boost_and_name!();
}
impl TermsLookupQuery {
pub fn routing<S>(mut self, routing: S) -> Self
where
S: ToString,
{
self.terms_lookup.routing = Some(routing.to_string());
self
}
}
impl ShouldSkip for TermsLookupQuery {}
serialize_with_root_key_value_pair!("terms": TermsLookupQuery, field, terms_lookup);
impl<'de> Deserialize<'de> for TermsLookupQuery {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use std::fmt;
struct WrapperVisitor;
impl<'de> serde::de::Visitor<'de> for WrapperVisitor {
type Value = TermsLookupQuery;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct terms")
}
fn visit_map<A>(self, mut map: A) -> Result<TermsLookupQuery, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let mut query: TermsLookupQuery = TermsLookupQuery::default();
let mut found_value = false;
while let Some(key) = map.next_key::<String>()? {
if key == "terms" {
let inner_map =
map.next_value::<serde_json::Map<String, serde_json::Value>>()?;
for (k, v) in inner_map.iter() {
match k.as_str() {
"field" => match v.as_str() {
Some(field) => {
query.field = field.to_string();
}
None => {
return Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Other("not a string"),
&"a string",
));
}
},
"boost" => match v.as_f64() {
Some(boost) => {
query.boost = Some(boost as f32);
}
None => {
return Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Other("not a float"),
&"a float",
));
}
},
"_name" => match v.as_str() {
Some(_name) => {
query._name = Some(_name.to_string());
}
None => {
return Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Other("not a string"),
&"a string",
));
}
},
"value" => {
let terms_lookup =
serde_json::from_value::<TermsLookup>(v.clone());
match terms_lookup {
Ok(terms_lookup) => {
query.terms_lookup = terms_lookup;
found_value = true;
}
Err(e) => {
return Err(serde::de::Error::custom(format!(
"error parsing distance: {}",
e
)));
}
}
}
_ => {
query.field = k.to_owned();
let terms_lookup =
serde_json::from_value::<TermsLookup>(v.clone());
match terms_lookup {
Ok(terms_lookup) => {
query.terms_lookup = terms_lookup;
found_value = true;
}
Err(e) => {
return Err(serde::de::Error::custom(format!(
"error parsing {}: {}",
k, e
)));
}
}
}
}
}
}
}
if found_value {
Ok(query)
} else {
Err(serde::de::Error::missing_field("location value"))
}
}
}
deserializer.deserialize_struct("Wrapper", &["terms"], WrapperVisitor)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serialization() {
assert_serialize_query(
Query::terms_lookup("test", "index_value", "id_value", "path_value"),
json!({
"terms": {
"test": {
"index": "index_value",
"id": "id_value",
"path": "path_value",
}
}
}),
);
assert_serialize_query(
Query::terms_lookup("test", "index_value", "id_value", "path_value")
.routing("routing_value")
.boost(2)
.name("test"),
json!({
"terms": {
"test": {
"index": "index_value",
"id": "id_value",
"path": "path_value",
"routing": "routing_value"
},
"boost": 2.0,
"_name": "test",
}
}),
);
}
}