Implement the simplified NOT operator

This commit is contained in:
Loïc Lecrenier 2022-06-14 15:15:05 +02:00
parent 01675771d5
commit 44744d9e67
2 changed files with 14 additions and 19 deletions

View File

@ -112,6 +112,7 @@ impl<'a> From<Span<'a>> for Token<'a> {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum FilterCondition<'a> { pub enum FilterCondition<'a> {
Not(Box<Self>),
Condition { fid: Token<'a>, op: Condition<'a> }, Condition { fid: Token<'a>, op: Condition<'a> },
Or(Vec<Self>), Or(Vec<Self>),
And(Vec<Self>), And(Vec<Self>),
@ -148,24 +149,6 @@ impl<'a> FilterCondition<'a> {
} }
} }
pub fn negate(self) -> FilterCondition<'a> {
use FilterCondition::*;
match self {
Condition { fid, op } => match op.negate() {
(op, None) => Condition { fid, op },
(a, Some(b)) => Or(vec![
Condition { fid: fid.clone(), op: a }.into(),
Condition { fid, op: b }.into(),
]),
},
Or(subfilters) => And(subfilters.into_iter().map(|x| x.negate().into()).collect()),
And(subfilters) => Or(subfilters.into_iter().map(|x| x.negate().into()).collect()),
GeoLowerThan { point, radius } => GeoGreaterThan { point, radius },
GeoGreaterThan { point, radius } => GeoLowerThan { point, radius },
}
}
pub fn parse(input: &'a str) -> Result<Option<Self>, Error> { pub fn parse(input: &'a str) -> Result<Option<Self>, Error> {
if input.trim().is_empty() { if input.trim().is_empty() {
return Ok(None); return Ok(None);
@ -219,7 +202,9 @@ fn parse_and(input: Span) -> IResult<FilterCondition> {
/// If we parse a `NOT` we MUST parse something behind. /// If we parse a `NOT` we MUST parse something behind.
fn parse_not(input: Span) -> IResult<FilterCondition> { fn parse_not(input: Span) -> IResult<FilterCondition> {
alt(( alt((
map(preceded(ws(tuple((tag("NOT"), multispace1))), cut(parse_not)), |e| e.negate()), map(preceded(ws(tuple((tag("NOT"), multispace1))), cut(parse_not)), |e| {
FilterCondition::Not(Box::new(e))
}),
parse_primary, parse_primary,
))(input) ))(input)
} }

View File

@ -360,6 +360,16 @@ impl<'a> Filter<'a> {
filterable_fields: &HashSet<String>, filterable_fields: &HashSet<String>,
) -> Result<RoaringBitmap> { ) -> Result<RoaringBitmap> {
match &self.condition { match &self.condition {
FilterCondition::Not(f) => {
let all_ids = index.documents_ids(rtxn)?;
let selected = Self::inner_evaluate(
&(f.as_ref().clone()).into(),
rtxn,
index,
filterable_fields,
)?;
return Ok(all_ids - selected);
}
FilterCondition::Condition { fid, op } => { FilterCondition::Condition { fid, op } => {
if crate::is_faceted(fid.value(), filterable_fields) { if crate::is_faceted(fid.value(), filterable_fields) {
let field_ids_map = index.fields_ids_map(rtxn)?; let field_ids_map = index.fields_ids_map(rtxn)?;