clean up multiple filter parsing

This commit is contained in:
kageru 2023-04-18 00:27:31 +02:00
parent 55bb41958b
commit bd6e92fa2d
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
2 changed files with 28 additions and 24 deletions

@ -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::<Card>(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));
}

@ -51,7 +51,7 @@ fn word_non_empty(input: &str) -> IResult<&str, &str> {
}
fn sanitize(query: &str) -> Result<String, String> {
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::<i32>() {
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<Value, String> {
let values = input.split('|').map(parse_single_value).collect::<Result<Vec<Value>, String>>()?;
Ok(match values.as_slice() {
[v] => v.clone(),
_ => Value::Multiple(values),
})
}
fn parse_single_value(input: &str) -> Result<Value, String> {
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,