use std::default::Default;
use serde::de::{self, Deserializer, Visitor};
use serde::ser::{SerializeMap, Serializer};
use serde::{Deserialize, Serialize};
#[cfg_attr(all(test, not(feature = "graphql")), derive(PartialEq))]
#[cfg_attr(feature = "graphql", derive(async_graphql::Enum, Eq, PartialEq, Copy))]
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum SortOrder {
Asc,
Desc,
}
#[cfg_attr(all(test, not(feature = "graphql")), derive(PartialEq))]
#[cfg_attr(feature = "graphql", derive(async_graphql::Enum, Eq, PartialEq, Copy))]
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum SortMode {
Min,
Max,
Sum,
Avg,
Median,
}
#[cfg(feature = "graphql")]
#[derive(async_graphql::InputObject, PartialEq, Clone, Debug)]
pub struct SortInput {
pub field: String,
pub order: Option<SortOrder>,
pub mode: Option<SortMode>,
}
#[cfg(feature = "graphql")]
impl Default for SortInput {
#[inline]
fn default() -> Self {
Self {
field: "id".to_string(),
order: None,
mode: None,
}
}
}
#[cfg(feature = "graphql")]
impl Serialize for SortInput {
#[inline]
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(Some(1))?;
let field = match self.field.as_str() {
"score" => "_score",
"key" => "_key",
"count" => "_count",
_ => self.field.as_str(),
};
map.serialize_entry(&field, &InnerSortValue::from(self))?;
map.end()
}
}
#[cfg_attr(all(test, not(feature = "graphql")), derive(PartialEq))]
#[cfg_attr(feature = "graphql", derive(async_graphql::SimpleObject, PartialEq))]
#[derive(Clone, Debug)]
pub struct Sort {
field: String,
order: Option<SortOrder>,
mode: Option<SortMode>,
}
impl Default for Sort {
#[inline]
fn default() -> Self {
Self {
field: "id".to_string(),
order: None,
mode: None,
}
}
}
#[cfg(feature = "graphql")]
impl From<SortInput> for Sort {
#[inline]
fn from(input: SortInput) -> Self {
Sort {
field: input.field,
order: input.order,
mode: input.mode,
}
}
}
impl Serialize for Sort {
#[inline]
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(Some(1))?;
let field = match self.field.as_str() {
"score" => "_score",
"key" => "_key",
"count" => "_count",
_ => &self.field,
};
map.serialize_entry(&field, &InnerSortValue::from(self))?;
map.end()
}
}
impl<'de> Deserialize<'de> for Sort {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Sort, D::Error>
where
D: Deserializer<'de>,
{
struct SortVisitor;
impl<'de> Visitor<'de> for SortVisitor {
type Value = Sort;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a `Sort`")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let field = map
.next_key::<String>()?
.ok_or_else(|| de::Error::missing_field("field"))?;
let inner: InnerSortValue = map.next_value()?;
Ok(Sort {
field,
order: inner.order,
mode: inner.mode,
})
}
}
deserializer.deserialize_map(SortVisitor)
}
}
#[derive(Serialize, Deserialize)]
struct InnerSortValue {
#[serde(skip_serializing_if = "Option::is_none")]
order: Option<SortOrder>,
#[serde(skip_serializing_if = "Option::is_none")]
mode: Option<SortMode>,
#[serde(skip_serializing_if = "Option::is_none")]
unmapped_type: Option<String>,
}
#[cfg(feature = "graphql")]
impl From<&SortInput> for InnerSortValue {
#[inline]
fn from(sort: &SortInput) -> Self {
InnerSortValue {
order: sort.order,
mode: sort.mode,
unmapped_type: if sort.field.starts_with('_') {
None
} else {
Some("keyword".to_string())
},
}
}
}
impl From<&Sort> for InnerSortValue {
#[inline]
fn from(sort: &Sort) -> Self {
#[allow(clippy::clone_on_copy)] InnerSortValue {
order: sort.order.clone(),
mode: sort.mode.clone(),
unmapped_type: if sort.field.starts_with('_') {
None
} else {
Some("keyword".to_string())
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn can_serialize_default() {
let f = Sort::default();
let j = json!({ "id": { "unmapped_type": "keyword" } });
assert_eq!(serde_json::to_value(&f).unwrap(), j, "{}", &j);
}
#[test]
fn can_serialize_with_order() {
let sort = vec![
Sort {
field: "id".to_string(),
mode: None,
order: Some(SortOrder::Asc),
},
Sort {
field: "id".to_string(),
mode: None,
order: Some(SortOrder::Desc),
},
];
let j = json!([
{ "id": { "order": "asc", "unmapped_type": "keyword" } },
{ "id": { "order": "desc", "unmapped_type": "keyword" } },
]);
assert_eq!(serde_json::to_value(&sort).unwrap(), j, "{}", &j);
}
#[test]
fn can_serialize_with_mode() {
let sorts: Vec<Sort> = vec![
SortMode::Min,
SortMode::Max,
SortMode::Sum,
SortMode::Avg,
SortMode::Median,
]
.into_iter()
.map(|m| Sort {
field: "id".to_string(),
mode: Some(m),
order: None,
})
.collect();
let j = json!([
{ "id": { "mode": "min", "unmapped_type": "keyword" } },
{ "id": { "mode": "max", "unmapped_type": "keyword" } },
{ "id": { "mode": "sum", "unmapped_type": "keyword" } },
{ "id": { "mode": "avg", "unmapped_type": "keyword" } },
{ "id": { "mode": "median", "unmapped_type": "keyword" } },
]);
assert_eq!(serde_json::to_value(&sorts).unwrap(), j, "{}", &j);
}
#[test]
fn can_serialize_with_everything() {
let sort = Sort {
field: "id".to_string(),
mode: Some(SortMode::Max),
order: Some(SortOrder::Desc),
};
let j = json!({ "id": { "mode": "max", "order": "desc", "unmapped_type": "keyword" } });
assert_eq!(serde_json::to_value(&sort).unwrap(), j, "{}", &j);
}
#[test]
fn can_serialize_with_special_field() {
let sort = Sort {
field: "_score".to_string(),
mode: None,
order: None,
};
let j = json!({ "_score": { } });
assert_eq!(serde_json::to_value(&sort).unwrap(), j, "{}", &j);
let sort = Sort {
field: "_key".to_string(),
mode: Some(SortMode::Avg),
order: None,
};
let j = json!({ "_key": { "mode": "avg" } });
assert_eq!(serde_json::to_value(&sort).unwrap(), j, "{}", &j);
let sort = Sort {
field: "_count".to_string(),
mode: None,
order: None,
};
let j = json!({ "_count": { } });
assert_eq!(serde_json::to_value(&sort).unwrap(), j, "{}", &j);
}
#[test]
fn can_deserialize_with_everything() {
let j = json!({ "id": { "mode": "max", "order": "desc", "unmapped_type": "keyword" } });
let actual: Sort = serde_json::from_value(j).unwrap();
let expected = Sort {
field: "id".to_string(),
mode: Some(SortMode::Max),
order: Some(SortOrder::Desc),
};
assert_eq!(actual, expected, "{:#?}", &actual);
}
}