diff --git a/filter-parser/src/condition.rs b/filter-parser/src/condition.rs index 63fab7e8f..8453f2639 100644 --- a/filter-parser/src/condition.rs +++ b/filter-parser/src/condition.rs @@ -19,7 +19,6 @@ pub enum Condition<'a> { GreaterThan(Token<'a>), GreaterThanOrEqual(Token<'a>), Equal(Token<'a>), - NotEqual(Token<'a>), Null, Empty, Exists, @@ -39,7 +38,9 @@ pub fn parse_condition(input: Span) -> IResult { let condition = match *op.fragment() { "<=" => FilterCondition::Condition { fid, op: LowerThanOrEqual(value) }, ">=" => FilterCondition::Condition { fid, op: GreaterThanOrEqual(value) }, - "!=" => FilterCondition::Condition { fid, op: NotEqual(value) }, + "!=" => { + FilterCondition::Not(Box::new(FilterCondition::Condition { fid, op: Equal(value) })) + } "<" => FilterCondition::Condition { fid, op: LowerThan(value) }, ">" => FilterCondition::Condition { fid, op: GreaterThan(value) }, "=" => FilterCondition::Condition { fid, op: Equal(value) }, diff --git a/filter-parser/src/lib.rs b/filter-parser/src/lib.rs index 61e534adb..6b04dabcb 100644 --- a/filter-parser/src/lib.rs +++ b/filter-parser/src/lib.rs @@ -534,7 +534,7 @@ pub mod tests { insta::assert_display_snapshot!(p(" colour IN [green, blue] "), @"{colour} IN[{green}, {blue}, ]"); // Test conditions - insta::assert_display_snapshot!(p("channel != ponce"), @"{channel} != {ponce}"); + insta::assert_display_snapshot!(p("channel != ponce"), @"NOT ({channel} = {ponce})"); insta::assert_display_snapshot!(p("NOT channel = ponce"), @"NOT ({channel} = {ponce})"); insta::assert_display_snapshot!(p("subscribers < 1000"), @"{subscribers} < {1000}"); insta::assert_display_snapshot!(p("subscribers > 1000"), @"{subscribers} > {1000}"); @@ -604,17 +604,17 @@ pub mod tests { insta::assert_display_snapshot!(p("_geoBoundingBox([12,13],[14,15])"), @"_geoBoundingBox([{12}, {13}], [{14}, {15}])"); // Test OR + AND - insta::assert_display_snapshot!(p("channel = ponce AND 'dog race' != 'bernese mountain'"), @"AND[{channel} = {ponce}, {dog race} != {bernese mountain}, ]"); - insta::assert_display_snapshot!(p("channel = ponce OR 'dog race' != 'bernese mountain'"), @"OR[{channel} = {ponce}, {dog race} != {bernese mountain}, ]"); - insta::assert_display_snapshot!(p("channel = ponce AND 'dog race' != 'bernese mountain' OR subscribers > 1000"), @"OR[AND[{channel} = {ponce}, {dog race} != {bernese mountain}, ], {subscribers} > {1000}, ]"); + insta::assert_display_snapshot!(p("channel = ponce AND 'dog race' != 'bernese mountain'"), @"AND[{channel} = {ponce}, NOT ({dog race} = {bernese mountain}), ]"); + insta::assert_display_snapshot!(p("channel = ponce OR 'dog race' != 'bernese mountain'"), @"OR[{channel} = {ponce}, NOT ({dog race} = {bernese mountain}), ]"); + insta::assert_display_snapshot!(p("channel = ponce AND 'dog race' != 'bernese mountain' OR subscribers > 1000"), @"OR[AND[{channel} = {ponce}, NOT ({dog race} = {bernese mountain}), ], {subscribers} > {1000}, ]"); insta::assert_display_snapshot!( p("channel = ponce AND 'dog race' != 'bernese mountain' OR subscribers > 1000 OR colour = red OR colour = blue AND size = 7"), - @"OR[AND[{channel} = {ponce}, {dog race} != {bernese mountain}, ], {subscribers} > {1000}, {colour} = {red}, AND[{colour} = {blue}, {size} = {7}, ], ]" + @"OR[AND[{channel} = {ponce}, NOT ({dog race} = {bernese mountain}), ], {subscribers} > {1000}, {colour} = {red}, AND[{colour} = {blue}, {size} = {7}, ], ]" ); // Test parentheses - insta::assert_display_snapshot!(p("channel = ponce AND ( 'dog race' != 'bernese mountain' OR subscribers > 1000 )"), @"AND[{channel} = {ponce}, OR[{dog race} != {bernese mountain}, {subscribers} > {1000}, ], ]"); - insta::assert_display_snapshot!(p("(channel = ponce AND 'dog race' != 'bernese mountain' OR subscribers > 1000) AND _geoRadius(12, 13, 14)"), @"AND[OR[AND[{channel} = {ponce}, {dog race} != {bernese mountain}, ], {subscribers} > {1000}, ], _geoRadius({12}, {13}, {14}), ]"); + insta::assert_display_snapshot!(p("channel = ponce AND ( 'dog race' != 'bernese mountain' OR subscribers > 1000 )"), @"AND[{channel} = {ponce}, OR[NOT ({dog race} = {bernese mountain}), {subscribers} > {1000}, ], ]"); + insta::assert_display_snapshot!(p("(channel = ponce AND 'dog race' != 'bernese mountain' OR subscribers > 1000) AND _geoRadius(12, 13, 14)"), @"AND[OR[AND[{channel} = {ponce}, NOT ({dog race} = {bernese mountain}), ], {subscribers} > {1000}, ], _geoRadius({12}, {13}, {14}), ]"); // Test recursion // This is the most that is allowed @@ -939,7 +939,6 @@ impl<'a> std::fmt::Display for Condition<'a> { Condition::GreaterThan(token) => write!(f, "> {token}"), Condition::GreaterThanOrEqual(token) => write!(f, ">= {token}"), Condition::Equal(token) => write!(f, "= {token}"), - Condition::NotEqual(token) => write!(f, "!= {token}"), Condition::Null => write!(f, "IS NULL"), Condition::Empty => write!(f, "IS EMPTY"), Condition::Exists => write!(f, "EXISTS"), diff --git a/milli/src/search/facet/filter.rs b/milli/src/search/facet/filter.rs index 5f8805217..c436fa47a 100644 --- a/milli/src/search/facet/filter.rs +++ b/milli/src/search/facet/filter.rs @@ -295,12 +295,6 @@ impl<'a> Filter<'a> { }; return Ok(string_docids | number_docids); } - Condition::NotEqual(val) => { - let operator = Condition::Equal(val.clone()); - let docids = Self::evaluate_operator(rtxn, index, field_id, &operator)?; - let all_ids = index.documents_ids(rtxn)?; - return Ok(all_ids - docids); - } Condition::Contains(val) => { let value = crate::normalize_facet(val.value()); let finder = Finder::new(&value);