support regexp search in single field

This commit is contained in:
Damien Elmes 2020-03-21 13:06:46 +10:00
parent 97577dbc16
commit f0ed34d79b
2 changed files with 41 additions and 10 deletions

View file

@ -53,6 +53,7 @@ pub(super) enum SearchNode<'a> {
SingleField {
field: Cow<'a, str>,
text: Cow<'a, str>,
is_re: bool,
},
AddedInDays(u32),
CardTemplate(TemplateKind),
@ -272,10 +273,7 @@ fn search_node_for_text_with_argument<'a>(
"prop" => parse_prop(val.as_ref())?,
"re" => SearchNode::Regex(val),
// anything else is a field search
_ => SearchNode::SingleField {
field: key,
text: val,
},
_ => parse_single_field(key.as_ref(), val.as_ref()),
})
}
@ -392,6 +390,20 @@ fn parse_template(val: &str) -> SearchNode<'static> {
})
}
fn parse_single_field(key: &str, mut val: &str) -> SearchNode<'static> {
let is_re = if val.starts_with("re:") {
val = val.trim_start_matches("re:");
true
} else {
false
};
SearchNode::SingleField {
field: key.to_string().into(),
text: val.to_string().into(),
is_re,
}
}
#[cfg(test)]
mod test {
use super::*;
@ -424,7 +436,8 @@ mod test {
And,
Search(SingleField {
field: "foo".into(),
text: "bar baz".into()
text: "bar baz".into(),
is_re: false,
})
]))),
Or,
@ -432,6 +445,15 @@ mod test {
]
);
assert_eq!(
parse("foo:re:bar")?,
vec![Search(SingleField {
field: "foo".into(),
text: "bar".into(),
is_re: true
})]
);
// any character should be escapable in quotes
assert_eq!(
parse(r#""re:\btest""#)?,

View file

@ -55,8 +55,8 @@ impl SqlWriter<'_, '_> {
fn write_search_node_to_sql(&mut self, node: &SearchNode) -> Result<()> {
match node {
SearchNode::UnqualifiedText(text) => self.write_unqualified(text),
SearchNode::SingleField { field, text } => {
self.write_single_field(field.as_ref(), text.as_ref())?
SearchNode::SingleField { field, text, is_re } => {
self.write_single_field(field.as_ref(), text.as_ref(), *is_re)?
}
SearchNode::AddedInDays(days) => self.write_added(*days)?,
SearchNode::CardTemplate(template) => self.write_template(template)?,
@ -279,7 +279,7 @@ impl SqlWriter<'_, '_> {
Ok(())
}
fn write_single_field(&mut self, field_name: &str, val: &str) -> Result<()> {
fn write_single_field(&mut self, field_name: &str, val: &str, is_re: bool) -> Result<()> {
let note_types = self.req.storage.all_note_types()?;
let mut field_map = vec![];
@ -299,15 +299,24 @@ impl SqlWriter<'_, '_> {
return Ok(());
}
let cmp;
if is_re {
cmp = "regexp";
self.args.push(format!("(?i){}", val));
} else {
cmp = "like";
self.args.push(val.replace('*', "%"));
}
let arg_idx = self.args.len();
let searches: Vec<_> = field_map
.iter()
.map(|(ntid, ord)| {
format!(
"(n.mid = {mid} and field_at_index(n.flds, {ord}) like ?{n})",
"(n.mid = {mid} and field_at_index(n.flds, {ord}) {cmp} ?{n})",
mid = ntid,
ord = ord,
cmp = cmp,
n = arg_idx
)
})