From 584d1492e507b5240129c6d638a7180f4fdf0f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A8r=20Kessels?= Date: Sat, 6 Jun 2020 13:47:02 +0200 Subject: [PATCH] Restructure distance sorting JSON. This fixes issue #150, where the JSON is wrong for distance sorting. The structure is a little non-standard, as it is wrapped in an object with hardcoded _geo_distance as name. Reaching through inner-outer and tupled structs is unfortunate, but seems to be nessecary in order to keep the API the same and to keep everything nicely contained inside a GeoDistance struct as seen from the consumer or user. --- src/operations/search/mod.rs | 73 ++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/src/operations/search/mod.rs b/src/operations/search/mod.rs index c7ad89c..a354f09 100644 --- a/src/operations/search/mod.rs +++ b/src/operations/search/mod.rs @@ -25,7 +25,7 @@ use std::fmt::Debug; use reqwest::StatusCode; -use serde::{de::DeserializeOwned, ser::Serializer, Deserialize, Serialize}; +use serde::{de::DeserializeOwned, ser::SerializeMap, ser::Serializer, Deserialize, Serialize}; use serde_json::Value; use super::{ @@ -34,7 +34,7 @@ use super::{ }; use crate::{ error::EsError, - json::{FieldBased, NoOuter, ShouldSkip}, + json::{serialize_map_optional_kv, FieldBased, MergeSerialize, NoOuter, ShouldSkip}, query::Query, units::{DistanceType, DistanceUnit, Duration, JsonVal, Location, OneOrMany}, util::StrJoin, @@ -215,9 +215,11 @@ impl ToString for SortField { /// Representing sort options for sort by geodistance // TODO - fix structure to represent reality #[derive(Debug, Serialize)] -pub struct GeoDistance { - field: String, - location: OneOrMany, +pub struct GeoDistance(FieldBased); +#[derive(Debug, Serialize)] +struct GeoDistanceInner(FieldBased, GeoDistanceOuter>); +#[derive(Debug, Serialize)] +struct GeoDistanceOuter { #[serde(skip_serializing_if = "ShouldSkip::should_skip")] order: Option, #[serde(skip_serializing_if = "ShouldSkip::should_skip")] @@ -233,36 +235,69 @@ impl GeoDistance { where S: Into, { - GeoDistance { - field: field.into(), - location: OneOrMany::Many(vec![]), - order: None, - unit: None, - mode: None, - distance_type: None, - } + GeoDistance(FieldBased::new( + String::from("_geo_distance"), + GeoDistanceInner(FieldBased::new( + field.into(), + OneOrMany::Many(vec![]), + GeoDistanceOuter { + order: None, + unit: None, + mode: None, + distance_type: None, + }, + )), + NoOuter, + )) + } + + pub fn with_distance_type(mut self, distance_type: DistanceType) -> Self { + self.0.inner.0.outer.distance_type = distance_type.into(); + self } pub fn with_location>(mut self, location: L) -> Self { - self.location = OneOrMany::One(location.into()); + self.0.inner.0.inner = OneOrMany::One(location.into()); self } pub fn with_locations>(mut self, location: Vec) -> Self { - self.location = OneOrMany::Many(location.into_iter().map(Into::into).collect()); + self.0.inner.0.inner = OneOrMany::Many(location.into_iter().map(Into::into).collect()); self } - add_field!(with_order, order, Order); - add_field!(with_unit, unit, DistanceUnit); - add_field!(with_mode, mode, Mode); - add_field!(with_distance_type, distance_type, DistanceType); + pub fn with_mode(mut self, mode: Mode) -> Self { + self.0.inner.0.outer.mode = mode.into(); + self + } + + pub fn with_order(mut self, order: Order) -> Self { + self.0.inner.0.outer.order = order.into(); + self + } + + pub fn with_unit(mut self, unit: DistanceUnit) -> Self { + self.0.inner.0.outer.unit = unit.into(); + self + } pub fn build(self) -> SortBy { SortBy::Distance(self) } } +impl MergeSerialize for GeoDistanceOuter { + fn merge_serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where + S: SerializeMap, + { + serialize_map_optional_kv(serializer, "unit", &self.unit)?; + serialize_map_optional_kv(serializer, "mode", &self.mode)?; + serialize_map_optional_kv(serializer, "distance_type", &self.distance_type)?; + serialize_map_optional_kv(serializer, "order", &self.order) + } +} + /// Representing options for sort by script // TODO - fix structure // TODO - there are other 'Script's defined elsewhere, perhaps de-duplicate them