mirror of
https://github.com/ankitects/anki.git
synced 2025-09-22 07:52:24 -04:00
support regexp search in single field
This commit is contained in:
parent
97577dbc16
commit
f0ed34d79b
2 changed files with 41 additions and 10 deletions
|
@ -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""#)?,
|
||||
|
|
|
@ -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(());
|
||||
}
|
||||
|
||||
self.args.push(val.replace('*', "%"));
|
||||
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
|
||||
)
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue