mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-10-21 11:06:27 +00:00
Improve operation error on vector filters
This commit is contained in:
@@ -164,21 +164,24 @@ fn parse_vectors(input: Span) -> IResult<(Token, Option<Token>, VectorFilter<'_>
|
|||||||
Ok((input, (Token::from(fid), Some(embedder_name), filter)))
|
Ok((input, (Token::from(fid), Some(embedder_name), filter)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// vectors_exists = vectors "EXISTS"
|
/// vectors_exists = vectors ("EXISTS" | ("NOT" WS+ "EXISTS"))
|
||||||
pub fn parse_vectors_exists(input: Span) -> IResult<FilterCondition> {
|
pub fn parse_vectors_exists(input: Span) -> IResult<FilterCondition> {
|
||||||
let (input, (fid, embedder, filter)) = terminated(parse_vectors, tag("EXISTS"))(input)?;
|
|
||||||
|
|
||||||
Ok((input, FilterCondition::VectorExists { fid, embedder, filter }))
|
|
||||||
}
|
|
||||||
/// vectors_not_exists = vectors "NOT" WS+ "EXISTS"
|
|
||||||
pub fn parse_vectors_not_exists(input: Span) -> IResult<FilterCondition> {
|
|
||||||
let (input, (fid, embedder, filter)) = parse_vectors(input)?;
|
let (input, (fid, embedder, filter)) = parse_vectors(input)?;
|
||||||
|
|
||||||
let (input, _) = tuple((tag("NOT"), multispace1, tag("EXISTS")))(input)?;
|
// Try parsing "EXISTS" first
|
||||||
Ok((
|
if let Ok((input, _)) = tag::<_, _, ()>("EXISTS")(input) {
|
||||||
|
return Ok((input, FilterCondition::VectorExists { fid, embedder, filter }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try parsing "NOT EXISTS"
|
||||||
|
if let Ok((input, _)) = tuple::<_, _, (), _>((tag("NOT"), multispace1, tag("EXISTS")))(input) {
|
||||||
|
return Ok((
|
||||||
input,
|
input,
|
||||||
FilterCondition::Not(Box::new(FilterCondition::VectorExists { fid, embedder, filter })),
|
FilterCondition::Not(Box::new(FilterCondition::VectorExists { fid, embedder, filter })),
|
||||||
))
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(crate::Error::new_failure_from_kind(input, ErrorKind::VectorFilterOperation))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// contains = value "CONTAINS" value
|
/// contains = value "CONTAINS" value
|
||||||
|
@@ -83,6 +83,7 @@ pub enum ErrorKind<'a> {
|
|||||||
VectorFilterInvalidEmbedder,
|
VectorFilterInvalidEmbedder,
|
||||||
VectorFilterMissingFragment,
|
VectorFilterMissingFragment,
|
||||||
VectorFilterInvalidFragment,
|
VectorFilterInvalidFragment,
|
||||||
|
VectorFilterOperation,
|
||||||
InvalidPrimary,
|
InvalidPrimary,
|
||||||
InvalidEscapedNumber,
|
InvalidEscapedNumber,
|
||||||
ExpectedEof,
|
ExpectedEof,
|
||||||
@@ -210,6 +211,9 @@ impl Display for Error<'_> {
|
|||||||
ErrorKind::VectorFilterInvalidEmbedder => {
|
ErrorKind::VectorFilterInvalidEmbedder => {
|
||||||
writeln!(f, "The vector filter's embedder is invalid.")?
|
writeln!(f, "The vector filter's embedder is invalid.")?
|
||||||
}
|
}
|
||||||
|
ErrorKind::VectorFilterOperation => {
|
||||||
|
writeln!(f, "Was expecting an operation like `EXISTS` or `NOT EXISTS` after the vector filter.")?
|
||||||
|
}
|
||||||
ErrorKind::ReservedKeyword(word) => {
|
ErrorKind::ReservedKeyword(word) => {
|
||||||
writeln!(f, "`{word}` is a reserved keyword and thus cannot be used as a field name unless it is put inside quotes. Use \"{word}\" or \'{word}\' instead.")?
|
writeln!(f, "`{word}` is a reserved keyword and thus cannot be used as a field name unless it is put inside quotes. Use \"{word}\" or \'{word}\' instead.")?
|
||||||
}
|
}
|
||||||
|
@@ -65,7 +65,7 @@ use nom_locate::LocatedSpan;
|
|||||||
pub(crate) use value::parse_value;
|
pub(crate) use value::parse_value;
|
||||||
use value::word_exact;
|
use value::word_exact;
|
||||||
|
|
||||||
use crate::condition::{parse_vectors_exists, parse_vectors_not_exists};
|
use crate::condition::parse_vectors_exists;
|
||||||
use crate::error::IResultExt;
|
use crate::error::IResultExt;
|
||||||
|
|
||||||
pub type Span<'a> = LocatedSpan<&'a str, &'a str>;
|
pub type Span<'a> = LocatedSpan<&'a str, &'a str>;
|
||||||
@@ -525,7 +525,7 @@ fn parse_primary(input: Span, depth: usize) -> IResult<FilterCondition> {
|
|||||||
parse_is_not_null,
|
parse_is_not_null,
|
||||||
parse_is_empty,
|
parse_is_empty,
|
||||||
parse_is_not_empty,
|
parse_is_not_empty,
|
||||||
alt((parse_vectors_exists, parse_vectors_not_exists, parse_exists, parse_not_exists)),
|
alt((parse_vectors_exists, parse_exists, parse_not_exists)),
|
||||||
parse_to,
|
parse_to,
|
||||||
parse_contains,
|
parse_contains,
|
||||||
parse_not_contains,
|
parse_not_contains,
|
||||||
@@ -1002,16 +1002,16 @@ pub mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
insta::assert_snapshot!(p(r#"_vectors _vectors EXISTS"#), @r"
|
insta::assert_snapshot!(p(r#"_vectors _vectors EXISTS"#), @r"
|
||||||
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `NOT CONTAINS`, `STARTS WITH`, `NOT STARTS WITH`, `_geoRadius`, or `_geoBoundingBox` at `_vectors _vectors EXISTS`.
|
Was expecting an operation like `EXISTS` or `NOT EXISTS` after the vector filter.
|
||||||
1:25 _vectors _vectors EXISTS
|
10:25 _vectors _vectors EXISTS
|
||||||
");
|
");
|
||||||
insta::assert_snapshot!(p(r#"_vectors. embedderName EXISTS"#), @r"
|
insta::assert_snapshot!(p(r#"_vectors. embedderName EXISTS"#), @r"
|
||||||
Was expecting embedder name but found nothing.
|
Was expecting embedder name but found nothing.
|
||||||
10:11 _vectors. embedderName EXISTS
|
10:11 _vectors. embedderName EXISTS
|
||||||
");
|
");
|
||||||
insta::assert_snapshot!(p(r#"_vectors .embedderName EXISTS"#), @r"
|
insta::assert_snapshot!(p(r#"_vectors .embedderName EXISTS"#), @r"
|
||||||
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `NOT CONTAINS`, `STARTS WITH`, `NOT STARTS WITH`, `_geoRadius`, or `_geoBoundingBox` at `_vectors .embedderName EXISTS`.
|
Was expecting an operation like `EXISTS` or `NOT EXISTS` after the vector filter.
|
||||||
1:30 _vectors .embedderName EXISTS
|
10:30 _vectors .embedderName EXISTS
|
||||||
");
|
");
|
||||||
insta::assert_snapshot!(p(r#"_vectors.embedderName. EXISTS"#), @r"
|
insta::assert_snapshot!(p(r#"_vectors.embedderName. EXISTS"#), @r"
|
||||||
The vector filter has leftover tokens.
|
The vector filter has leftover tokens.
|
||||||
@@ -1038,20 +1038,20 @@ pub mod tests {
|
|||||||
33:40 _vectors.embedderName.fragments. EXISTS
|
33:40 _vectors.embedderName.fragments. EXISTS
|
||||||
");
|
");
|
||||||
insta::assert_snapshot!(p(r#"_vectors.embedderName.fragments.test test EXISTS"#), @r"
|
insta::assert_snapshot!(p(r#"_vectors.embedderName.fragments.test test EXISTS"#), @r"
|
||||||
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `NOT CONTAINS`, `STARTS WITH`, `NOT STARTS WITH`, `_geoRadius`, or `_geoBoundingBox` at `_vectors.embedderName.fragments.test test EXISTS`.
|
Was expecting an operation like `EXISTS` or `NOT EXISTS` after the vector filter.
|
||||||
1:49 _vectors.embedderName.fragments.test test EXISTS
|
38:49 _vectors.embedderName.fragments.test test EXISTS
|
||||||
");
|
");
|
||||||
insta::assert_snapshot!(p(r#"_vectors.embedderName.fragments. test EXISTS"#), @r"
|
insta::assert_snapshot!(p(r#"_vectors.embedderName.fragments. test EXISTS"#), @r"
|
||||||
The vector filter's fragment is invalid.
|
The vector filter's fragment is invalid.
|
||||||
33:45 _vectors.embedderName.fragments. test EXISTS
|
33:45 _vectors.embedderName.fragments. test EXISTS
|
||||||
");
|
");
|
||||||
insta::assert_snapshot!(p(r#"_vectors.embedderName .fragments. test EXISTS"#), @r"
|
insta::assert_snapshot!(p(r#"_vectors.embedderName .fragments. test EXISTS"#), @r"
|
||||||
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `NOT CONTAINS`, `STARTS WITH`, `NOT STARTS WITH`, `_geoRadius`, or `_geoBoundingBox` at `_vectors.embedderName .fragments. test EXISTS`.
|
Was expecting an operation like `EXISTS` or `NOT EXISTS` after the vector filter.
|
||||||
1:46 _vectors.embedderName .fragments. test EXISTS
|
23:46 _vectors.embedderName .fragments. test EXISTS
|
||||||
");
|
");
|
||||||
insta::assert_snapshot!(p(r#"_vectors.embedderName .fragments.test EXISTS"#), @r"
|
insta::assert_snapshot!(p(r#"_vectors.embedderName .fragments.test EXISTS"#), @r"
|
||||||
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `NOT CONTAINS`, `STARTS WITH`, `NOT STARTS WITH`, `_geoRadius`, or `_geoBoundingBox` at `_vectors.embedderName .fragments.test EXISTS`.
|
Was expecting an operation like `EXISTS` or `NOT EXISTS` after the vector filter.
|
||||||
1:45 _vectors.embedderName .fragments.test EXISTS
|
23:45 _vectors.embedderName .fragments.test EXISTS
|
||||||
");
|
");
|
||||||
|
|
||||||
insta::assert_snapshot!(p(r#"NOT OR EXISTS AND EXISTS NOT EXISTS"#), @r###"
|
insta::assert_snapshot!(p(r#"NOT OR EXISTS AND EXISTS NOT EXISTS"#), @r###"
|
||||||
|
Reference in New Issue
Block a user