chore: introduce new error ParseGeoError type

This commit is contained in:
Filip Bachul 2023-02-07 18:57:27 +01:00
parent ff595156d7
commit e405702733

View File

@ -22,12 +22,30 @@ pub struct Filter<'a> {
} }
#[derive(Debug)] #[derive(Debug)]
enum FilterError<'a> { enum ParseGeoError {
AttributeNotFilterable { attribute: &'a str, filterable_fields: HashSet<String> }, BadGeo(String),
BadGeo(&'a str),
BadGeoLat(f64), BadGeoLat(f64),
BadGeoLng(f64), BadGeoLng(f64),
BadGeoBoundingBoxTopIsBelowBottom(f64, f64), BadGeoBoundingBoxTopIsBelowBottom(f64, f64),
}
impl std::error::Error for ParseGeoError {}
impl Display for ParseGeoError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::BadGeo(keyword) => write!(f, "`{}` is a reserved keyword and thus can't be used as a filter expression. Use the `_geoRadius(latitude, longitude, distance)` or `_geoBoundingBox([latitude, longitude], [latitude, longitude])` built-in rules to filter on `_geo` field coordinates.", keyword),
Self::BadGeoBoundingBoxTopIsBelowBottom(top, bottom) => write!(f, "The top latitude `{top}` is below the bottom latitude `{bottom}`."),
Self::BadGeoLat(lat) => write!(f, "Bad latitude `{}`. Latitude must be contained between -90 and 90 degrees. ", lat),
Self::BadGeoLng(lng) => write!(f, "Bad longitude `{}`. Longitude must be contained between -180 and 180 degrees. ", lng),
}
}
}
#[derive(Debug)]
enum FilterError<'a> {
AttributeNotFilterable { attribute: &'a str, filterable_fields: HashSet<String> },
ParseGeoError(ParseGeoError),
Reserved(&'a str), Reserved(&'a str),
TooDeep, TooDeep,
} }
@ -44,7 +62,11 @@ impl<'a> Display for FilterError<'a> {
attribute, attribute,
) )
} else { } else {
let filterables_list = filterable_fields.iter().map(AsRef::as_ref).collect::<Vec<&str>>().join(" "); let filterables_list = filterable_fields
.iter()
.map(AsRef::as_ref)
.collect::<Vec<&str>>()
.join(" ");
write!( write!(
f, f,
@ -53,8 +75,9 @@ impl<'a> Display for FilterError<'a> {
filterables_list, filterables_list,
) )
} }
}, }
Self::TooDeep => write!(f, Self::TooDeep => write!(
f,
"Too many filter conditions, can't process more than {} filters.", "Too many filter conditions, can't process more than {} filters.",
MAX_FILTER_DEPTH MAX_FILTER_DEPTH
), ),
@ -63,10 +86,7 @@ impl<'a> Display for FilterError<'a> {
"`{}` is a reserved keyword and thus can't be used as a filter expression.", "`{}` is a reserved keyword and thus can't be used as a filter expression.",
keyword keyword
), ),
Self::BadGeo(keyword) => write!(f, "`{}` is a reserved keyword and thus can't be used as a filter expression. Use the `_geoRadius(latitude, longitude, distance)` or `_geoBoundingBox([latitude, longitude], [latitude, longitude])` built-in rules to filter on `_geo` field coordinates.", keyword), Self::ParseGeoError(error) => write!(f, "{}", error),
Self::BadGeoBoundingBoxTopIsBelowBottom(top, bottom) => write!(f, "The top latitude `{top}` is below the bottom latitude `{bottom}`."),
Self::BadGeoLat(lat) => write!(f, "Bad latitude `{}`. Latitude must be contained between -90 and 90 degrees. ", lat),
Self::BadGeoLng(lng) => write!(f, "Bad longitude `{}`. Longitude must be contained between -180 and 180 degrees. ", lng),
} }
} }
} }
@ -297,12 +317,13 @@ impl<'a> Filter<'a> {
} }
} else { } else {
match fid.value() { match fid.value() {
attribute @ "_geo" => { attribute @ "_geo" => Err(fid.as_external_error(
Err(fid.as_external_error(FilterError::BadGeo(attribute)))? FilterError::ParseGeoError(ParseGeoError::BadGeo(attribute.to_owned())),
} ))?,
attribute if attribute.starts_with("_geoPoint(") => { attribute if attribute.starts_with("_geoPoint(") => Err(fid
Err(fid.as_external_error(FilterError::BadGeo("_geoPoint")))? .as_external_error(FilterError::ParseGeoError(
} ParseGeoError::BadGeo("_geoPoint".to_owned()),
)))?,
attribute @ "_geoDistance" => { attribute @ "_geoDistance" => {
Err(fid.as_external_error(FilterError::Reserved(attribute)))? Err(fid.as_external_error(FilterError::Reserved(attribute)))?
} }
@ -353,14 +374,14 @@ impl<'a> Filter<'a> {
let base_point: [f64; 2] = let base_point: [f64; 2] =
[point[0].parse_finite_float()?, point[1].parse_finite_float()?]; [point[0].parse_finite_float()?, point[1].parse_finite_float()?];
if !(-90.0..=90.0).contains(&base_point[0]) { if !(-90.0..=90.0).contains(&base_point[0]) {
return Err( return Err(point[0].as_external_error(FilterError::ParseGeoError(
point[0].as_external_error(FilterError::BadGeoLat(base_point[0])) ParseGeoError::BadGeoLat(base_point[0]),
)?; )))?;
} }
if !(-180.0..=180.0).contains(&base_point[1]) { if !(-180.0..=180.0).contains(&base_point[1]) {
return Err( return Err(point[1].as_external_error(FilterError::ParseGeoError(
point[1].as_external_error(FilterError::BadGeoLng(base_point[1])) ParseGeoError::BadGeoLng(base_point[1]),
)?; )))?;
} }
let radius = radius.parse_finite_float()?; let radius = radius.parse_finite_float()?;
let rtree = match index.geo_rtree(rtxn)? { let rtree = match index.geo_rtree(rtxn)? {
@ -398,26 +419,32 @@ impl<'a> Filter<'a> {
bottom_right_point[1].parse_finite_float()?, bottom_right_point[1].parse_finite_float()?,
]; ];
if !(-90.0..=90.0).contains(&top_left[0]) { if !(-90.0..=90.0).contains(&top_left[0]) {
return Err(top_left_point[0] return Err(top_left_point[0].as_external_error(
.as_external_error(FilterError::BadGeoLat(top_left[0])))?; FilterError::ParseGeoError(ParseGeoError::BadGeoLat(top_left[0])),
))?;
} }
if !(-180.0..=180.0).contains(&top_left[1]) { if !(-180.0..=180.0).contains(&top_left[1]) {
return Err(top_left_point[1] return Err(top_left_point[1].as_external_error(
.as_external_error(FilterError::BadGeoLng(top_left[1])))?; FilterError::ParseGeoError(ParseGeoError::BadGeoLng(top_left[1])),
))?;
} }
if !(-90.0..=90.0).contains(&bottom_right[0]) { if !(-90.0..=90.0).contains(&bottom_right[0]) {
return Err(bottom_right_point[0] return Err(bottom_right_point[0].as_external_error(
.as_external_error(FilterError::BadGeoLat(bottom_right[0])))?; FilterError::ParseGeoError(ParseGeoError::BadGeoLat(bottom_right[0])),
))?;
} }
if !(-180.0..=180.0).contains(&bottom_right[1]) { if !(-180.0..=180.0).contains(&bottom_right[1]) {
return Err(bottom_right_point[1] return Err(bottom_right_point[1].as_external_error(
.as_external_error(FilterError::BadGeoLng(bottom_right[1])))?; FilterError::ParseGeoError(ParseGeoError::BadGeoLng(bottom_right[1])),
))?;
} }
if top_left[0] < bottom_right[0] { if top_left[0] < bottom_right[0] {
return Err(bottom_right_point[1].as_external_error( return Err(bottom_right_point[1].as_external_error(
FilterError::BadGeoBoundingBoxTopIsBelowBottom( FilterError::ParseGeoError(
top_left[0], ParseGeoError::BadGeoBoundingBoxTopIsBelowBottom(
bottom_right[0], top_left[0],
bottom_right[0],
),
), ),
))?; ))?;
} }