mirror of
https://github.com/quickwit-oss/tantivy.git
synced 2025-12-26 12:09:57 +00:00
@@ -218,27 +218,14 @@ fn term_or_phrase_infallible(inp: &str) -> JResult<&str, Option<UserInputLeaf>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn term_group(inp: &str) -> IResult<&str, UserInputAst> {
|
fn term_group(inp: &str) -> IResult<&str, UserInputAst> {
|
||||||
let occur_symbol = alt((
|
|
||||||
value(Occur::MustNot, char('-')),
|
|
||||||
value(Occur::Must, char('+')),
|
|
||||||
));
|
|
||||||
|
|
||||||
map(
|
map(
|
||||||
tuple((
|
tuple((
|
||||||
terminated(field_name, multispace0),
|
terminated(field_name, multispace0),
|
||||||
delimited(
|
delimited(tuple((char('('), multispace0)), ast, char(')')),
|
||||||
tuple((char('('), multispace0)),
|
|
||||||
separated_list0(multispace1, tuple((opt(occur_symbol), term_or_phrase))),
|
|
||||||
char(')'),
|
|
||||||
),
|
|
||||||
)),
|
)),
|
||||||
|(field_name, terms)| {
|
|(field_name, mut ast)| {
|
||||||
UserInputAst::Clause(
|
ast.set_default_field(field_name);
|
||||||
terms
|
ast
|
||||||
.into_iter()
|
|
||||||
.map(|(occur, leaf)| (occur, leaf.set_field(Some(field_name.clone())).into()))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)(inp)
|
)(inp)
|
||||||
}
|
}
|
||||||
@@ -258,46 +245,18 @@ fn term_group_precond(inp: &str) -> IResult<&str, (), ()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn term_group_infallible(inp: &str) -> JResult<&str, UserInputAst> {
|
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");
|
tuple((field_name, multispace0, char('('), multispace0))(inp).expect("precondition failed");
|
||||||
|
|
||||||
let mut terms = Vec::new();
|
let res = delimited_infallible(
|
||||||
let mut errs = Vec::new();
|
nothing,
|
||||||
|
map(ast_infallible, |(mut ast, errors)| {
|
||||||
let mut first_round = true;
|
ast.set_default_field(field_name.to_string());
|
||||||
loop {
|
(ast, errors)
|
||||||
let mut space_error = if first_round {
|
}),
|
||||||
first_round = false;
|
opt_i_err(char(')'), "expected ')'"),
|
||||||
Vec::new()
|
)(inp);
|
||||||
} else {
|
res
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists(inp: &str) -> IResult<&str, UserInputLeaf> {
|
fn exists(inp: &str) -> IResult<&str, UserInputLeaf> {
|
||||||
@@ -1468,8 +1427,18 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_query_term_group() {
|
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 -"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")"#);
|
test_is_parse_err(r#"field:(+a -"b c""#, r#"(+"field":a -"field":"b c")"#);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
impl Debug for UserInputLeaf {
|
||||||
@@ -205,6 +225,16 @@ impl UserInputAst {
|
|||||||
pub fn or(asts: Vec<UserInputAst>) -> UserInputAst {
|
pub fn or(asts: Vec<UserInputAst>) -> UserInputAst {
|
||||||
UserInputAst::compose(Occur::Should, asts)
|
UserInputAst::compose(Occur::Should, asts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) 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<UserInputLiteral> for UserInputLeaf {
|
impl From<UserInputLiteral> for UserInputLeaf {
|
||||||
|
|||||||
Reference in New Issue
Block a user