Skip to content

Commit

Permalink
feat(QueryParser): Add support for patterns like "field:*".
Browse files Browse the repository at this point in the history
  • Loading branch information
LebranceBW committed Oct 10, 2024
1 parent 2f5a269 commit 695de2c
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 8 deletions.
4 changes: 4 additions & 0 deletions src/query/query_parser/logical_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ pub enum LogicalLiteral {
Set {
elements: Vec<Term>,
},
Exist {
field_name: String,
},
All,
}

Expand Down Expand Up @@ -147,6 +150,7 @@ impl fmt::Debug for LogicalLiteral {
write!(formatter, "]")
}
LogicalLiteral::All => write!(formatter, "*"),
LogicalLiteral::Exist { ref field_name } => write!(formatter, "{field_name:?}: *"),
}
}
}
60 changes: 52 additions & 8 deletions src/query/query_parser/query_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use crate::index::Index;
use crate::json_utils::convert_to_fast_value_and_append_to_json_term;
use crate::query::range_query::{is_type_valid_for_fastfield_range_query, RangeQuery};
use crate::query::{
AllQuery, BooleanQuery, BoostQuery, EmptyQuery, FuzzyTermQuery, Occur, PhrasePrefixQuery,
PhraseQuery, Query, TermQuery, TermSetQuery,
AllQuery, BooleanQuery, BoostQuery, EmptyQuery, ExistsQuery, FuzzyTermQuery, Occur,
PhrasePrefixQuery, PhraseQuery, Query, TermQuery, TermSetQuery,
};
use crate::schema::{
Facet, FacetParseError, Field, FieldType, IndexRecordOption, IntoIpv6Addr, JsonObjectOptions,
Expand Down Expand Up @@ -848,12 +848,32 @@ impl QueryParser {
let logical_ast = LogicalAst::Leaf(Box::new(LogicalLiteral::Set { elements }));
(Some(logical_ast), errors)
}
UserInputLeaf::Exists { .. } => (
None,
vec![QueryParserError::UnsupportedQuery(
"Range query need to target a specific field.".to_string(),
)],
),
UserInputLeaf::Exists { field: full_path } => {
let mut errors = Vec::<QueryParserError>::new();
let (field, json_path) = try_tuple!(self
.split_full_path(&full_path)
.ok_or_else(|| QueryParserError::FieldDoesNotExist(full_path.clone())));
let field_entry = self.schema.get_field_entry(field);
let field_type = field_entry.field_type();
if !field_type.is_fast() {
// FIXME: FieldNotIndexed error is not accurate.
errors.push(QueryParserError::FieldNotIndexed(
field_entry.name().to_string(),
));
return (None, errors);
}
if !json_path.is_empty() && field_type.is_json() {
errors.push(QueryParserError::UnsupportedQuery(format!(
"Json path is not supported for field {:?}",
field_entry.name()
)));
return (None, errors);
}
let logical_ast = LogicalAst::Leaf(Box::new(LogicalLiteral::Exist {
field_name: field_entry.name().to_string(),
}));
(Some(logical_ast), errors)
}
}
}
}
Expand Down Expand Up @@ -896,6 +916,7 @@ fn convert_literal_to_query(
LogicalLiteral::Range { lower, upper } => Box::new(RangeQuery::new(lower, upper)),
LogicalLiteral::Set { elements, .. } => Box::new(TermSetQuery::new(elements)),
LogicalLiteral::All => Box::new(AllQuery),
LogicalLiteral::Exist { field_name } => Box::new(ExistsQuery::new_exists_query(field_name)),
}
}

Expand Down Expand Up @@ -1922,4 +1943,27 @@ mod test {
);
}
}

#[test]
pub fn test_exist_query() {
let query_parser = make_query_parser_with_default_fields(&["title", "text", "u64_ff"]);
// Basic function.
{
let query = query_parser.parse_query("u64_ff:*").unwrap();
assert_eq!(
format!("{query:?}"),
r##"ExistsQuery { field_name: "u64_ff" }"##
)
}
// Non-existed field should raise `FieldDoesNotExist` error.
assert_matches!(
query_parser.parse_query("Aether:*"),
Err(QueryParserError::FieldDoesNotExist(_))
);
// Non-fast field should raise `FieldNotIndexed` error.
assert_matches!(
query_parser.parse_query("text:*"),
Err(QueryParserError::FieldNotIndexed(_))
);
}
}

0 comments on commit 695de2c

Please sign in to comment.