mirror of
https://github.com/meilisearch/MeiliSearch
synced 2024-11-30 00:34:26 +01:00
Introduce the NULL and NOT value NULL operator
This commit is contained in:
parent
43ff236df8
commit
7c0cd7172d
@ -20,6 +20,7 @@ pub enum Condition<'a> {
|
|||||||
GreaterThanOrEqual(Token<'a>),
|
GreaterThanOrEqual(Token<'a>),
|
||||||
Equal(Token<'a>),
|
Equal(Token<'a>),
|
||||||
NotEqual(Token<'a>),
|
NotEqual(Token<'a>),
|
||||||
|
Null,
|
||||||
Exists,
|
Exists,
|
||||||
LowerThan(Token<'a>),
|
LowerThan(Token<'a>),
|
||||||
LowerThanOrEqual(Token<'a>),
|
LowerThanOrEqual(Token<'a>),
|
||||||
@ -44,6 +45,21 @@ pub fn parse_condition(input: Span) -> IResult<FilterCondition> {
|
|||||||
Ok((input, condition))
|
Ok((input, condition))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// null = value "NULL"
|
||||||
|
pub fn parse_null(input: Span) -> IResult<FilterCondition> {
|
||||||
|
let (input, key) = terminated(parse_value, tag("NULL"))(input)?;
|
||||||
|
|
||||||
|
Ok((input, FilterCondition::Condition { fid: key, op: Null }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// null = value "NOT" WS+ "NULL"
|
||||||
|
pub fn parse_not_null(input: Span) -> IResult<FilterCondition> {
|
||||||
|
let (input, key) = parse_value(input)?;
|
||||||
|
|
||||||
|
let (input, _) = tuple((tag("NOT"), multispace1, tag("NULL")))(input)?;
|
||||||
|
Ok((input, FilterCondition::Not(Box::new(FilterCondition::Condition { fid: key, op: Null }))))
|
||||||
|
}
|
||||||
|
|
||||||
/// exist = value "EXISTS"
|
/// exist = value "EXISTS"
|
||||||
pub fn parse_exists(input: Span) -> IResult<FilterCondition> {
|
pub fn parse_exists(input: Span) -> IResult<FilterCondition> {
|
||||||
let (input, key) = terminated(parse_value, tag("EXISTS"))(input)?;
|
let (input, key) = terminated(parse_value, tag("EXISTS"))(input)?;
|
||||||
|
@ -47,7 +47,7 @@ mod value;
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
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, parse_not_null, parse_null};
|
||||||
use error::{cut_with_err, ExpectedValueKind, NomErrorExt};
|
use error::{cut_with_err, ExpectedValueKind, NomErrorExt};
|
||||||
pub use error::{Error, ErrorKind};
|
pub use error::{Error, ErrorKind};
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
@ -414,6 +414,8 @@ fn parse_primary(input: Span, depth: usize) -> IResult<FilterCondition> {
|
|||||||
parse_in,
|
parse_in,
|
||||||
parse_not_in,
|
parse_not_in,
|
||||||
parse_condition,
|
parse_condition,
|
||||||
|
parse_null,
|
||||||
|
parse_not_null,
|
||||||
parse_exists,
|
parse_exists,
|
||||||
parse_not_exists,
|
parse_not_exists,
|
||||||
parse_to,
|
parse_to,
|
||||||
@ -496,14 +498,23 @@ pub mod tests {
|
|||||||
insta::assert_display_snapshot!(p("subscribers <= 1000"), @"{subscribers} <= {1000}");
|
insta::assert_display_snapshot!(p("subscribers <= 1000"), @"{subscribers} <= {1000}");
|
||||||
insta::assert_display_snapshot!(p("subscribers 100 TO 1000"), @"{subscribers} {100} TO {1000}");
|
insta::assert_display_snapshot!(p("subscribers 100 TO 1000"), @"{subscribers} {100} TO {1000}");
|
||||||
|
|
||||||
// Test NOT + EXISTS
|
// Test NOT
|
||||||
insta::assert_display_snapshot!(p("subscribers EXISTS"), @"{subscribers} EXISTS");
|
|
||||||
insta::assert_display_snapshot!(p("NOT subscribers < 1000"), @"NOT ({subscribers} < {1000})");
|
insta::assert_display_snapshot!(p("NOT subscribers < 1000"), @"NOT ({subscribers} < {1000})");
|
||||||
|
insta::assert_display_snapshot!(p("NOT subscribers 100 TO 1000"), @"NOT ({subscribers} {100} TO {1000})");
|
||||||
|
|
||||||
|
// Test NULL + NOT NULL
|
||||||
|
insta::assert_display_snapshot!(p("subscribers NULL"), @"{subscribers} NULL");
|
||||||
|
insta::assert_display_snapshot!(p("NOT subscribers NULL"), @"NOT ({subscribers} NULL)");
|
||||||
|
insta::assert_display_snapshot!(p("subscribers NOT NULL"), @"NOT ({subscribers} NULL)");
|
||||||
|
insta::assert_display_snapshot!(p("NOT subscribers NOT NULL"), @"{subscribers} NULL");
|
||||||
|
insta::assert_display_snapshot!(p("subscribers NOT NULL"), @"NOT ({subscribers} NULL)");
|
||||||
|
|
||||||
|
// Test EXISTS + NOT EXITS
|
||||||
|
insta::assert_display_snapshot!(p("subscribers EXISTS"), @"{subscribers} EXISTS");
|
||||||
insta::assert_display_snapshot!(p("NOT subscribers EXISTS"), @"NOT ({subscribers} EXISTS)");
|
insta::assert_display_snapshot!(p("NOT subscribers EXISTS"), @"NOT ({subscribers} EXISTS)");
|
||||||
insta::assert_display_snapshot!(p("subscribers NOT EXISTS"), @"NOT ({subscribers} EXISTS)");
|
insta::assert_display_snapshot!(p("subscribers NOT EXISTS"), @"NOT ({subscribers} EXISTS)");
|
||||||
insta::assert_display_snapshot!(p("NOT subscribers NOT EXISTS"), @"{subscribers} EXISTS");
|
insta::assert_display_snapshot!(p("NOT subscribers NOT EXISTS"), @"{subscribers} EXISTS");
|
||||||
insta::assert_display_snapshot!(p("subscribers NOT EXISTS"), @"NOT ({subscribers} EXISTS)");
|
insta::assert_display_snapshot!(p("subscribers NOT EXISTS"), @"NOT ({subscribers} EXISTS)");
|
||||||
insta::assert_display_snapshot!(p("NOT subscribers 100 TO 1000"), @"NOT ({subscribers} {100} TO {1000})");
|
|
||||||
|
|
||||||
// Test nested NOT
|
// Test nested NOT
|
||||||
insta::assert_display_snapshot!(p("NOT NOT NOT NOT x = 5"), @"{x} = {5}");
|
insta::assert_display_snapshot!(p("NOT NOT NOT NOT x = 5"), @"{x} = {5}");
|
||||||
@ -800,6 +811,7 @@ impl<'a> std::fmt::Display for Condition<'a> {
|
|||||||
Condition::GreaterThanOrEqual(token) => write!(f, ">= {token}"),
|
Condition::GreaterThanOrEqual(token) => write!(f, ">= {token}"),
|
||||||
Condition::Equal(token) => write!(f, "= {token}"),
|
Condition::Equal(token) => write!(f, "= {token}"),
|
||||||
Condition::NotEqual(token) => write!(f, "!= {token}"),
|
Condition::NotEqual(token) => write!(f, "!= {token}"),
|
||||||
|
Condition::Null => write!(f, "NULL"),
|
||||||
Condition::Exists => write!(f, "EXISTS"),
|
Condition::Exists => write!(f, "EXISTS"),
|
||||||
Condition::LowerThan(token) => write!(f, "< {token}"),
|
Condition::LowerThan(token) => write!(f, "< {token}"),
|
||||||
Condition::LowerThanOrEqual(token) => write!(f, "<= {token}"),
|
Condition::LowerThanOrEqual(token) => write!(f, "<= {token}"),
|
||||||
|
@ -839,6 +839,18 @@ impl Index {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve all the documents which contain this field id set as null
|
||||||
|
pub fn null_faceted_documents_ids(
|
||||||
|
&self,
|
||||||
|
rtxn: &RoTxn,
|
||||||
|
field_id: FieldId,
|
||||||
|
) -> heed::Result<RoaringBitmap> {
|
||||||
|
match self.facet_id_is_null_docids.get(rtxn, &BEU16::new(field_id))? {
|
||||||
|
Some(docids) => Ok(docids),
|
||||||
|
None => Ok(RoaringBitmap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve all the documents which contain this field id
|
/// Retrieve all the documents which contain this field id
|
||||||
pub fn exists_faceted_documents_ids(
|
pub fn exists_faceted_documents_ids(
|
||||||
&self,
|
&self,
|
||||||
|
@ -219,6 +219,10 @@ impl<'a> Filter<'a> {
|
|||||||
Condition::Between { from, to } => {
|
Condition::Between { from, to } => {
|
||||||
(Included(from.parse_finite_float()?), Included(to.parse_finite_float()?))
|
(Included(from.parse_finite_float()?), Included(to.parse_finite_float()?))
|
||||||
}
|
}
|
||||||
|
Condition::Null => {
|
||||||
|
let is_null = index.null_faceted_documents_ids(rtxn, field_id)?;
|
||||||
|
return Ok(is_null);
|
||||||
|
}
|
||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user