From 9dc721793135af6dc054510c968ae43b079cc06d Mon Sep 17 00:00:00 2001 From: trinity-1686a Date: Thu, 21 Mar 2024 17:17:30 +0100 Subject: [PATCH 1/2] extend field grouping --- query-grammar/src/query_grammar.rs | 81 +++++++++-------------------- query-grammar/src/user_input_ast.rs | 30 +++++++++++ 2 files changed, 55 insertions(+), 56 deletions(-) diff --git a/query-grammar/src/query_grammar.rs b/query-grammar/src/query_grammar.rs index 92d7738b20..15802002b1 100644 --- a/query-grammar/src/query_grammar.rs +++ b/query-grammar/src/query_grammar.rs @@ -218,27 +218,14 @@ fn term_or_phrase_infallible(inp: &str) -> JResult<&str, Option> } fn term_group(inp: &str) -> IResult<&str, UserInputAst> { - let occur_symbol = alt(( - value(Occur::MustNot, char('-')), - value(Occur::Must, char('+')), - )); - map( tuple(( terminated(field_name, multispace0), - delimited( - tuple((char('('), multispace0)), - separated_list0(multispace1, tuple((opt(occur_symbol), term_or_phrase))), - char(')'), - ), + delimited(tuple((char('('), multispace0)), ast, char(')')), )), - |(field_name, terms)| { - UserInputAst::Clause( - terms - .into_iter() - .map(|(occur, leaf)| (occur, leaf.set_field(Some(field_name.clone())).into())) - .collect(), - ) + |(field_name, mut ast)| { + ast.set_default_field(field_name); + ast }, )(inp) } @@ -258,46 +245,18 @@ fn term_group_precond(inp: &str) -> IResult<&str, (), ()> { } fn term_group_infallible(inp: &str) -> JResult<&str, UserInputAst> { - let (mut inp, (field_name, _, _, _)) = + let (inp, (field_name, _, _, _)) = tuple((field_name, multispace0, char('('), multispace0))(inp).expect("precondition failed"); - let mut terms = Vec::new(); - let mut errs = Vec::new(); - - let mut first_round = true; - loop { - let mut space_error = if first_round { - first_round = false; - Vec::new() - } else { - let (rest, (_, err)) = space1_infallible(inp)?; - inp = rest; - err - }; - if inp.is_empty() { - errs.push(LenientErrorInternal { - pos: inp.len(), - message: "missing )".to_string(), - }); - break Ok((inp, (UserInputAst::Clause(terms), errs))); - } - if let Some(inp) = inp.strip_prefix(')') { - break Ok((inp, (UserInputAst::Clause(terms), errs))); - } - // only append missing space error if we did not reach the end of group - errs.append(&mut space_error); - - // here we do the assumption term_or_phrase_infallible always consume something if the - // first byte is not `)` or ' '. If it did not, we would end up looping. - - let (rest, ((occur, leaf), mut err)) = - tuple_infallible((occur_symbol, term_or_phrase_infallible))(inp)?; - errs.append(&mut err); - if let Some(leaf) = leaf { - terms.push((occur, leaf.set_field(Some(field_name.clone())).into())); - } - inp = rest; - } + let res = delimited_infallible( + nothing, + map(ast_infallible, |(mut ast, errors)| { + ast.set_default_field(field_name.to_string()); + (ast, errors) + }), + opt_i_err(char(')'), "expected ')'"), + )(inp); + res } fn exists(inp: &str) -> IResult<&str, UserInputLeaf> { @@ -1468,8 +1427,18 @@ mod test { #[test] fn test_parse_query_term_group() { - test_parse_query_to_ast_helper(r#"field:(abc)"#, r#"(*"field":abc)"#); + test_parse_query_to_ast_helper(r#"field:(abc)"#, r#""field":abc"#); test_parse_query_to_ast_helper(r#"field:(+a -"b c")"#, r#"(+"field":a -"field":"b c")"#); + test_parse_query_to_ast_helper(r#"field:(a AND "b c")"#, r#"(+"field":a +"field":"b c")"#); + test_parse_query_to_ast_helper(r#"field:(a OR "b c")"#, r#"(?"field":a ?"field":"b c")"#); + test_parse_query_to_ast_helper( + r#"field:(a OR (b AND c))"#, + r#"(?"field":a ?(+"field":b +"field":c))"#, + ); + test_parse_query_to_ast_helper( + r#"field:(a [b TO c])"#, + r#"(*"field":a *"field":["b" TO "c"])"#, + ); test_is_parse_err(r#"field:(+a -"b c""#, r#"(+"field":a -"field":"b c")"#); } diff --git a/query-grammar/src/user_input_ast.rs b/query-grammar/src/user_input_ast.rs index d0d1a02667..7236d2faea 100644 --- a/query-grammar/src/user_input_ast.rs +++ b/query-grammar/src/user_input_ast.rs @@ -44,6 +44,26 @@ impl UserInputLeaf { }, } } + + pub(crate) fn set_default_field(&mut self, default_field: String) { + match self { + UserInputLeaf::Literal(ref mut literal) if literal.field_name.is_none() => { + literal.field_name = Some(default_field) + } + UserInputLeaf::All => { + *self = UserInputLeaf::Exists { + field: default_field, + } + } + UserInputLeaf::Range { ref mut field, .. } if field.is_none() => { + *field = Some(default_field) + } + UserInputLeaf::Set { ref mut field, .. } if field.is_none() => { + *field = Some(default_field) + } + _ => (), // field was already set, do nothing + } + } } impl Debug for UserInputLeaf { @@ -205,6 +225,16 @@ impl UserInputAst { pub fn or(asts: Vec) -> UserInputAst { UserInputAst::compose(Occur::Should, asts) } + + pub fn set_default_field(&mut self, field: String) { + match self { + UserInputAst::Clause(clauses) => clauses + .iter_mut() + .for_each(|(_, ast)| ast.set_default_field(field.clone())), + UserInputAst::Leaf(leaf) => leaf.set_default_field(field), + UserInputAst::Boost(ref mut ast, _) => ast.set_default_field(field), + } + } } impl From for UserInputLeaf { From a17fca0026a2ce721a6c3f48e8fb951a747ee737 Mon Sep 17 00:00:00 2001 From: trinity-1686a Date: Fri, 22 Mar 2024 10:02:39 +0100 Subject: [PATCH 2/2] make set_default_field crate-pub --- query-grammar/src/user_input_ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query-grammar/src/user_input_ast.rs b/query-grammar/src/user_input_ast.rs index 7236d2faea..7289da55ff 100644 --- a/query-grammar/src/user_input_ast.rs +++ b/query-grammar/src/user_input_ast.rs @@ -226,7 +226,7 @@ impl UserInputAst { UserInputAst::compose(Occur::Should, asts) } - pub fn set_default_field(&mut self, field: String) { + pub(crate) fn set_default_field(&mut self, field: String) { match self { UserInputAst::Clause(clauses) => clauses .iter_mut()