mirror of
https://github.com/meilisearch/MeiliSearch
synced 2025-07-04 12:27:13 +02:00
Improve syntax errors for IN
filter
This commit is contained in:
parent
2fd20fadfc
commit
4ecfb95d0c
3 changed files with 83 additions and 10 deletions
|
@ -167,6 +167,12 @@ fn ws<'a, O>(inner: impl FnMut(Span<'a>) -> IResult<O>) -> impl FnMut(Span<'a>)
|
|||
|
||||
/// value_list = (value ("," value)* ","?)?
|
||||
fn parse_value_list<'a>(input: Span<'a>) -> IResult<Vec<Token<'a>>> {
|
||||
|
||||
// TODO: here, I should return a failure with a clear explanation whenever possible
|
||||
// for example:
|
||||
// * expected the name of a field, but got `AND`
|
||||
// * expected closing square bracket, but got `AND`
|
||||
|
||||
let (input, first_value) = opt(parse_value)(input)?;
|
||||
if let Some(first_value) = first_value {
|
||||
let value_list_el_parser = preceded(ws(tag(",")), parse_value);
|
||||
|
@ -186,9 +192,22 @@ fn parse_in(input: Span) -> IResult<FilterCondition> {
|
|||
let (input, value) = parse_value(input)?;
|
||||
let (input, _) = ws(tag("IN"))(input)?;
|
||||
|
||||
let mut els_parser = delimited(tag("["), parse_value_list, tag("]"));
|
||||
// everything after `IN` can be a failure
|
||||
let (input, _) = cut_with_err(tag("["), |_| {
|
||||
Error::new_from_kind(input, ErrorKind::InOpeningBracket)
|
||||
})(input)?;
|
||||
|
||||
let (input, content) = cut(parse_value_list)(input)?;
|
||||
|
||||
// everything after `IN` can be a failure
|
||||
let (input, _) = cut_with_err(tag("]"), |_| {
|
||||
if eof::<_, ()>(input).is_ok() {
|
||||
Error::new_from_kind(input, ErrorKind::InClosingBracket)
|
||||
} else {
|
||||
Error::new_from_kind(input, ErrorKind::InExpectedValue)
|
||||
}
|
||||
})(input)?;
|
||||
|
||||
let (input, content) = els_parser(input)?;
|
||||
let filter = FilterCondition::In { fid: value, els: content };
|
||||
Ok((input, filter))
|
||||
}
|
||||
|
@ -199,9 +218,19 @@ fn parse_not_in(input: Span) -> IResult<FilterCondition> {
|
|||
let (input, _) = multispace1(input)?;
|
||||
let (input, _) = ws(tag("IN"))(input)?;
|
||||
|
||||
let mut els_parser = delimited(tag("["), parse_value_list, tag("]"));
|
||||
|
||||
let (input, content) = els_parser(input)?;
|
||||
// everything after `IN` can be a failure
|
||||
let (input, _) = cut_with_err(tag("["), |_| {
|
||||
Error::new_from_kind(input, ErrorKind::InOpeningBracket)
|
||||
})(input)?;
|
||||
|
||||
let (input, content) = cut(parse_value_list)(input)?;
|
||||
|
||||
// everything after `IN` can be a failure
|
||||
let (input, _) = cut_with_err(tag("]"), |_| {
|
||||
Error::new_from_kind(input, ErrorKind::InClosingBracket)
|
||||
})(input)?;
|
||||
|
||||
let filter = FilterCondition::Not(Box::new(FilterCondition::In { fid: value, els: content }));
|
||||
Ok((input, filter))
|
||||
}
|
||||
|
@ -313,6 +342,9 @@ fn parse_primary(input: Span) -> IResult<FilterCondition> {
|
|||
))(input)
|
||||
// if the inner parsers did not match enough information to return an accurate error
|
||||
.map_err(|e| e.map_err(|_| Error::new_from_kind(input, ErrorKind::InvalidPrimary)))
|
||||
|
||||
// TODO: if the filter starts with a reserved keyword that is not NOT, then we should return the reserved keyword error
|
||||
// TODO: if the filter is x = reserved, idem
|
||||
}
|
||||
|
||||
/// expression = or
|
||||
|
@ -344,6 +376,13 @@ pub mod tests {
|
|||
|
||||
let test_case = [
|
||||
// simple test
|
||||
(
|
||||
"x = AND",
|
||||
Fc::Not(Box::new(Fc::Not(Box::new(Fc::In {
|
||||
fid: rtok("NOT NOT", "colour"),
|
||||
els: vec![]
|
||||
}))))
|
||||
),
|
||||
(
|
||||
"colour IN[]",
|
||||
Fc::In {
|
||||
|
@ -734,6 +773,11 @@ pub mod tests {
|
|||
("subscribers 100 TO1000", "Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `TO`, `EXISTS`, `NOT EXISTS`, or `_geoRadius` at `subscribers 100 TO1000`."),
|
||||
("channel = ponce ORdog != 'bernese mountain'", "Found unexpected characters at the end of the filter: `ORdog != \\'bernese mountain\\'`. You probably forgot an `OR` or an `AND` rule."),
|
||||
("channel = ponce AND'dog' != 'bernese mountain'", "Found unexpected characters at the end of the filter: `AND\\'dog\\' != \\'bernese mountain\\'`. You probably forgot an `OR` or an `AND` rule."),
|
||||
("colour IN blue, green]", "Expected `[` after `IN` keyword."),
|
||||
("colour IN [blue, green, 'blue' > 2]", "Expected only comma-separated field names inside `IN[..]` but instead found `> 2]`"),
|
||||
("colour IN [blue, green, AND]", "Expected only comma-separated field names inside `IN[..]` but instead found `AND]`"),
|
||||
("colour IN [blue, green", "Expected matching `]` after the list of field names given to `IN[`"),
|
||||
("colour IN ['blue, green", "Expression `\\'blue, green` is missing the following closing delimiter: `'`."),
|
||||
];
|
||||
|
||||
for (input, expected) in test_case {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue