mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-26 12:05:05 +08:00
fix: allow filters on = inf, = NaN, return InvalidFilter for < inf, < NaN
Fixes meilisearch/meilisearch#3000
This commit is contained in:
parent
6add470805
commit
3328560788
@ -65,6 +65,7 @@ pub enum ErrorKind<'a> {
|
|||||||
MalformedValue,
|
MalformedValue,
|
||||||
InOpeningBracket,
|
InOpeningBracket,
|
||||||
InClosingBracket,
|
InClosingBracket,
|
||||||
|
NonFiniteFloat,
|
||||||
InExpectedValue(ExpectedValueKind),
|
InExpectedValue(ExpectedValueKind),
|
||||||
ReservedKeyword(String),
|
ReservedKeyword(String),
|
||||||
MissingClosingDelimiter(char),
|
MissingClosingDelimiter(char),
|
||||||
@ -167,6 +168,9 @@ impl<'a> Display for Error<'a> {
|
|||||||
ErrorKind::InClosingBracket => {
|
ErrorKind::InClosingBracket => {
|
||||||
writeln!(f, "Expected matching `]` after the list of field names given to `IN[`")?
|
writeln!(f, "Expected matching `]` after the list of field names given to `IN[`")?
|
||||||
}
|
}
|
||||||
|
ErrorKind::NonFiniteFloat => {
|
||||||
|
writeln!(f, "Non finite floats are not supported")?
|
||||||
|
}
|
||||||
ErrorKind::InExpectedValue(ExpectedValueKind::ReservedKeyword) => {
|
ErrorKind::InExpectedValue(ExpectedValueKind::ReservedKeyword) => {
|
||||||
writeln!(f, "Expected only comma-separated field names inside `IN[..]` but instead found `{escaped_input}`, which is a keyword. To use `{escaped_input}` as a field name or a value, surround it by quotes.")?
|
writeln!(f, "Expected only comma-separated field names inside `IN[..]` but instead found `{escaped_input}`, which is a keyword. To use `{escaped_input}` as a field name or a value, surround it by quotes.")?
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,6 @@ mod error;
|
|||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
pub use condition::{parse_condition, parse_to, Condition};
|
pub use condition::{parse_condition, parse_to, Condition};
|
||||||
use condition::{parse_exists, parse_not_exists};
|
use condition::{parse_exists, parse_not_exists};
|
||||||
@ -100,12 +99,13 @@ impl<'a> Token<'a> {
|
|||||||
Error::new_from_external(self.span, error)
|
Error::new_from_external(self.span, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse<T>(&self) -> Result<T, Error>
|
pub fn parse_finite_float(&self) -> Result<f64, Error> {
|
||||||
where
|
let value: f64 = self.span.parse().map_err(|e| self.as_external_error(e))?;
|
||||||
T: FromStr,
|
if value.is_finite() {
|
||||||
T::Err: std::error::Error,
|
Ok(value)
|
||||||
{
|
} else {
|
||||||
self.span.parse().map_err(|e| self.as_external_error(e))
|
Err(Error::new_from_kind(self.span, ErrorKind::NonFiniteFloat))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,11 +169,19 @@ impl<'a> Filter<'a> {
|
|||||||
// field id and the level.
|
// field id and the level.
|
||||||
|
|
||||||
let (left, right) = match operator {
|
let (left, right) = match operator {
|
||||||
Condition::GreaterThan(val) => (Excluded(val.parse()?), Included(f64::MAX)),
|
Condition::GreaterThan(val) => {
|
||||||
Condition::GreaterThanOrEqual(val) => (Included(val.parse()?), Included(f64::MAX)),
|
(Excluded(val.parse_finite_float()?), Included(f64::MAX))
|
||||||
Condition::LowerThan(val) => (Included(f64::MIN), Excluded(val.parse()?)),
|
}
|
||||||
Condition::LowerThanOrEqual(val) => (Included(f64::MIN), Included(val.parse()?)),
|
Condition::GreaterThanOrEqual(val) => {
|
||||||
Condition::Between { from, to } => (Included(from.parse()?), Included(to.parse()?)),
|
(Included(val.parse_finite_float()?), Included(f64::MAX))
|
||||||
|
}
|
||||||
|
Condition::LowerThan(val) => (Included(f64::MIN), Excluded(val.parse_finite_float()?)),
|
||||||
|
Condition::LowerThanOrEqual(val) => {
|
||||||
|
(Included(f64::MIN), Included(val.parse_finite_float()?))
|
||||||
|
}
|
||||||
|
Condition::Between { from, to } => {
|
||||||
|
(Included(from.parse_finite_float()?), Included(to.parse_finite_float()?))
|
||||||
|
}
|
||||||
Condition::Exists => {
|
Condition::Exists => {
|
||||||
let exist = index.exists_faceted_documents_ids(rtxn, field_id)?;
|
let exist = index.exists_faceted_documents_ids(rtxn, field_id)?;
|
||||||
return Ok(exist);
|
return Ok(exist);
|
||||||
@ -190,7 +198,7 @@ impl<'a> Filter<'a> {
|
|||||||
)?
|
)?
|
||||||
.map(|v| v.bitmap)
|
.map(|v| v.bitmap)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let number = val.parse::<f64>().ok();
|
let number = val.parse_finite_float().ok();
|
||||||
let number_docids = match number {
|
let number_docids = match number {
|
||||||
Some(n) => {
|
Some(n) => {
|
||||||
let n = Included(n);
|
let n = Included(n);
|
||||||
@ -389,7 +397,8 @@ impl<'a> Filter<'a> {
|
|||||||
}
|
}
|
||||||
FilterCondition::GeoLowerThan { point, radius } => {
|
FilterCondition::GeoLowerThan { point, radius } => {
|
||||||
if filterable_fields.contains("_geo") {
|
if filterable_fields.contains("_geo") {
|
||||||
let base_point: [f64; 2] = [point[0].parse()?, point[1].parse()?];
|
let base_point: [f64; 2] =
|
||||||
|
[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::BadGeoLat(base_point[0]))
|
point[0].as_external_error(FilterError::BadGeoLat(base_point[0]))
|
||||||
@ -400,7 +409,7 @@ impl<'a> Filter<'a> {
|
|||||||
point[1].as_external_error(FilterError::BadGeoLng(base_point[1]))
|
point[1].as_external_error(FilterError::BadGeoLng(base_point[1]))
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
let radius = radius.parse()?;
|
let radius = radius.parse_finite_float()?;
|
||||||
let rtree = match index.geo_rtree(rtxn)? {
|
let rtree = match index.geo_rtree(rtxn)? {
|
||||||
Some(rtree) => rtree,
|
Some(rtree) => rtree,
|
||||||
None => return Ok(RoaringBitmap::new()),
|
None => return Ok(RoaringBitmap::new()),
|
||||||
|
Loading…
Reference in New Issue
Block a user