From bd6e92fa2dde5a94dbbf1016ef8d9b892de5e61c Mon Sep 17 00:00:00 2001 From: kageru Date: Tue, 18 Apr 2023 00:27:31 +0200 Subject: [PATCH] clean up multiple filter parsing --- src/filter.rs | 9 ++++++++- src/parser.rs | 43 ++++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/filter.rs b/src/filter.rs index d9ce1de..2ab7c7b 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -66,7 +66,7 @@ fn get_field_value(card: &SearchCard, field: Field) -> Value { // On the bright side, this means `set:HA` matches all Hidden Arsenals (plus reprints in HAC), but also all other set codes that contain HA. Field::Set => Value::String(card.sets.join(" ")), Field::Type => Value::String(card.r#type.clone()), - Field::Attribute => Value::String(card.attribute.clone().unwrap_or_else(|| "".to_string())), + Field::Attribute => Value::String(card.attribute.clone().unwrap_or_default()), Field::Class => Value::String(card.card_type.clone()), Field::Name => Value::String(card.name.clone()), Field::Text => Value::String(card.text.clone()), @@ -106,8 +106,15 @@ mod tests { #[test] fn level_filter_test() { let lacooda = SearchCard::from(&serde_json::from_str::(RAW_MONSTER).unwrap()); + let lacooda_but_level_4 = SearchCard { level: Some(4), ..lacooda.clone() }; + let filter_level_3 = parse_filters("l=3").unwrap(); assert!(filter_level_3.1[0](&lacooda)); + + let filter_level_3_4 = parse_filters("l=3|4").unwrap(); + assert!(filter_level_3_4.1[0](&lacooda)); + assert!(filter_level_3_4.1[0](&lacooda_but_level_4)); + let filter_level_5 = parse_filters("l=5").unwrap(); assert!(!filter_level_5.1[0](&lacooda)); } diff --git a/src/parser.rs b/src/parser.rs index d070544..0cc441a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -51,7 +51,7 @@ fn word_non_empty(input: &str) -> IResult<&str, &str> { } fn sanitize(query: &str) -> Result { - if query.contains(OPERATOR_CHARS) { + if query.contains(OPERATOR_CHARS) || query.is_empty() { Err(format!("Invalid query: {query}")) } else { Ok(query.to_lowercase()) @@ -91,30 +91,25 @@ fn values(input: &str) -> IResult<&str, Value> { take_until1(" "), rest, )), - |i: &str| { - if i.contains('|') { - let items: Vec<_> = i.split('|').collect(); - let mut values = Vec::new(); - - for item in items { - match item.parse::() { - Ok(n) => values.push(Value::Numerical(n)), - Err(_) => values.push(Value::String(sanitize(item)?)), - } - } - - Ok(Value::Multiple(values)) - } else { - match i.parse() { - Ok(n) => Ok(Value::Numerical(n)), - Err(_) if i.is_empty() => Err("empty filter argument".to_string()), - Err(_) => Ok(Value::String(sanitize(i)?)), - } - } - }, + parse_values, )(input) } +fn parse_values(input: &str) -> Result { + let values = input.split('|').map(parse_single_value).collect::, String>>()?; + Ok(match values.as_slice() { + [v] => v.clone(), + _ => Value::Multiple(values), + }) +} + +fn parse_single_value(input: &str) -> Result { + Ok(match input.parse() { + Ok(n) => Value::Numerical(n), + Err(_) => Value::String(sanitize(input)?), + }) +} + /// Ordinals are given highest = fastest to filter. /// This is used to sort filters before applying them. #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -283,6 +278,8 @@ mod tests { } #[test_case("atk<=>1")] + #[test_case("atk=50|")] + #[test_case("def=|")] #[test_case("l===10")] #[test_case("t=")] #[test_case("=100")] @@ -324,7 +321,7 @@ mod tests { } #[test] - fn test_parse_raw_filters_with_multiple_values() { + fn parse_multiple_values() { let input = "level=4|5|6"; let expected_output = vec![RawCardFilter( Field::Level,