combine name searches

This commit is contained in:
kageru 2023-02-03 17:27:01 +01:00
parent 11ad72a33f
commit 0e4c792542

@ -4,6 +4,7 @@ use std::{
}; };
use crate::filter::{build_filter, fallback_filter, CardFilter}; use crate::filter::{build_filter, fallback_filter, CardFilter};
use itertools::Itertools;
use nom::{ use nom::{
branch::alt, branch::alt,
bytes::complete::{take_until1, take_while, take_while_m_n}, bytes::complete::{take_until1, take_while, take_while_m_n},
@ -17,8 +18,24 @@ use nom::{
pub fn parse_filters(input: &str) -> Result<(Vec<RawCardFilter>, Vec<CardFilter>), String> { pub fn parse_filters(input: &str) -> Result<(Vec<RawCardFilter>, Vec<CardFilter>), String> {
parse_raw_filters(input).map_err(|e| format!("Error while parsing filters “{input}”: {e:?}")).and_then(|(rest, mut v)| { parse_raw_filters(input).map_err(|e| format!("Error while parsing filters “{input}”: {e:?}")).and_then(|(rest, mut v)| {
if rest.is_empty() { if rest.is_empty() {
v.sort_unstable_by_key(|RawCardFilter(f, _, _)| *f as u8); // Sorting must be stable or we can’t combine multiple name filters into one.
Ok((v.clone(), v.into_iter().map(|r| build_filter(r)).collect::<Result<Vec<_>, _>>()?)) v.sort_by_key(|RawCardFilter(f, _, _)| *f as u8);
// Combine multiple names searches into one search filter. This makes the readable query nicer
// (“Showing 21 results where name is ally and name is of and name is justice” becomes
// “Showing 21 results where name is ‘ally of justice’”)
// and improves search performance by only performing one String::contains.
// This could be done without allocating two vectors, but coalesce is just so much nicer.
v = v
.into_iter()
.coalesce(|a, b| match (&a, &b) {
(
RawCardFilter(Field::Name, Operator::Equal, Value::String(s1)),
RawCardFilter(Field::Name, Operator::Equal, Value::String(s2)),
) => Ok(RawCardFilter(Field::Name, Operator::Equal, Value::String(format!("{s1} {s2}")))),
_ => Err((a, b)),
})
.collect();
Ok((v.clone(), v.clone().into_iter().map(|r| build_filter(r)).collect::<Result<Vec<_>, _>>()?))
} else { } else {
Err(format!("Input was not fully parsed. Left over: “{rest}")) Err(format!("Input was not fully parsed. Left over: “{rest}"))
} }