add NotEqual filter
This commit is contained in:
parent
8fcb2824de
commit
557d7c680e
@ -46,7 +46,7 @@ pub fn fallback_filter(query: &str) -> Result<RawCardFilter, String> {
|
|||||||
return Err(format!("Invalid query: {query}"));
|
return Err(format!("Invalid query: {query}"));
|
||||||
}
|
}
|
||||||
let q = query.to_lowercase();
|
let q = query.to_lowercase();
|
||||||
Ok((Field::Name, Operator::Equals, Value::String(q)))
|
Ok((Field::Name, Operator::Equal, Value::String(q)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_filter(query: RawCardFilter) -> Result<CardFilter, String> {
|
pub fn build_filter(query: RawCardFilter) -> Result<CardFilter, String> {
|
||||||
@ -60,11 +60,14 @@ pub fn build_filter(query: RawCardFilter) -> Result<CardFilter, String> {
|
|||||||
Box::new(move |card| card.def.is_none() && card.link_rating.is_none() && card.card_type.contains("monster"))
|
Box::new(move |card| card.def.is_none() && card.link_rating.is_none() && card.card_type.contains("monster"))
|
||||||
}
|
}
|
||||||
(Field::Level, op, Value::Numerical(n)) => Box::new(move |card| op.filter_number(card.level, n)),
|
(Field::Level, op, Value::Numerical(n)) => Box::new(move |card| op.filter_number(card.level, n)),
|
||||||
(Field::Type, Operator::Equals, Value::String(s)) => Box::new(move |card| card.r#type == s),
|
(Field::Type, Operator::Equal, Value::String(s)) => Box::new(move |card| card.r#type == s),
|
||||||
(Field::Attribute, Operator::Equals, Value::String(s)) => Box::new(move |card| card.attribute.contains(&s)),
|
(Field::Type, Operator::NotEqual, Value::String(s)) => Box::new(move |card| card.r#type != s),
|
||||||
(Field::Class, Operator::Equals, Value::String(s)) => Box::new(move |card| card.card_type.contains(&s)),
|
(Field::Attribute, Operator::Equal, Value::String(s)) => Box::new(move |card| card.attribute.contains(&s)),
|
||||||
(Field::Text, Operator::Equals, Value::String(s)) => Box::new(move |card| card.text.contains(&s)),
|
(Field::Attribute, Operator::NotEqual, Value::String(s)) => Box::new(move |card| !card.attribute.contains(&s)),
|
||||||
(Field::Name, Operator::Equals, Value::String(s)) => Box::new(move |card| card.name.contains(&s)),
|
(Field::Class, Operator::Equal, Value::String(s)) => Box::new(move |card| card.card_type.contains(&s)),
|
||||||
|
(Field::Class, Operator::NotEqual, Value::String(s)) => Box::new(move |card| !card.card_type.contains(&s)),
|
||||||
|
(Field::Text, Operator::Equal, Value::String(s)) => Box::new(move |card| card.text.contains(&s)),
|
||||||
|
(Field::Name, Operator::Equal, Value::String(s)) => Box::new(move |card| card.name.contains(&s)),
|
||||||
q => Err(format!("unknown query: {q:?}"))?,
|
q => Err(format!("unknown query: {q:?}"))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ fn field(input: &str) -> IResult<&str, Field> {
|
|||||||
map_res(take_while(char::is_alphabetic), str::parse)(input)
|
map_res(take_while(char::is_alphabetic), str::parse)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const OPERATOR_CHARS: &[char] = &['=', '<', '>', ':'];
|
pub const OPERATOR_CHARS: &[char] = &['=', '<', '>', ':', '!'];
|
||||||
|
|
||||||
fn operator(input: &str) -> IResult<&str, Operator> {
|
fn operator(input: &str) -> IResult<&str, Operator> {
|
||||||
map_res(take_while_m_n(1, 2, |c| OPERATOR_CHARS.contains(&c)), str::parse)(input)
|
map_res(take_while_m_n(1, 2, |c| OPERATOR_CHARS.contains(&c)), str::parse)(input)
|
||||||
@ -84,7 +84,8 @@ impl FromStr for Field {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
Equals,
|
Equal,
|
||||||
|
NotEqual,
|
||||||
Less,
|
Less,
|
||||||
LessEqual,
|
LessEqual,
|
||||||
Greater,
|
Greater,
|
||||||
@ -95,14 +96,15 @@ impl Operator {
|
|||||||
pub fn filter_number(&self, a: Option<i32>, b: i32) -> bool {
|
pub fn filter_number(&self, a: Option<i32>, b: i32) -> bool {
|
||||||
if let Some(a) = a {
|
if let Some(a) = a {
|
||||||
match self {
|
match self {
|
||||||
Self::Equals => a == b,
|
Self::Equal => a == b,
|
||||||
Self::Less => a < b,
|
Self::Less => a < b,
|
||||||
Self::LessEqual => a <= b,
|
Self::LessEqual => a <= b,
|
||||||
Self::Greater => a > b,
|
Self::Greater => a > b,
|
||||||
Self::GreaterEqual => a >= b,
|
Self::GreaterEqual => a >= b,
|
||||||
|
Self::NotEqual => a != b,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
self == &Self::NotEqual
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,11 +113,12 @@ impl FromStr for Operator {
|
|||||||
type Err = String;
|
type Err = String;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Ok(match s {
|
Ok(match s {
|
||||||
"=" | "==" | ":" => Self::Equals,
|
"=" | "==" | ":" => Self::Equal,
|
||||||
">=" | "=>" => Self::GreaterEqual,
|
">=" | "=>" => Self::GreaterEqual,
|
||||||
"<=" | "=<" => Self::LessEqual,
|
"<=" | "=<" => Self::LessEqual,
|
||||||
">" => Self::Greater,
|
">" => Self::Greater,
|
||||||
"<" => Self::Less,
|
"<" => Self::Less,
|
||||||
|
"!=" => Self::NotEqual,
|
||||||
_ => Err(s.to_owned())?,
|
_ => Err(s.to_owned())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -132,13 +135,14 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
#[test_case("t=pyro" => Ok(("", (Field::Type, Operator::Equals, Value::String("pyro".into())))))]
|
#[test_case("t=pyro" => Ok(("", (Field::Type, Operator::Equal, Value::String("pyro".into())))))]
|
||||||
#[test_case("t:PYro" => Ok(("", (Field::Type, Operator::Equals, Value::String("pyro".into())))); "input is lowercased")]
|
#[test_case("t:PYro" => Ok(("", (Field::Type, Operator::Equal, Value::String("pyro".into())))); "input is lowercased")]
|
||||||
#[test_case("t==warrior" => Ok(("", (Field::Type, Operator::Equals, Value::String("warrior".into())))))]
|
#[test_case("t==warrior" => Ok(("", (Field::Type, Operator::Equal, Value::String("warrior".into())))))]
|
||||||
#[test_case("atk>=100" => Ok(("", (Field::Atk, Operator::GreaterEqual, Value::Numerical(100)))))]
|
#[test_case("atk>=100" => Ok(("", (Field::Atk, Operator::GreaterEqual, Value::Numerical(100)))))]
|
||||||
#[test_case("Necrovalley" => Ok(("", (Field::Name, Operator::Equals, Value::String("necrovalley".into())))))]
|
#[test_case("Necrovalley" => Ok(("", (Field::Name, Operator::Equal, Value::String("necrovalley".into())))))]
|
||||||
#[test_case("l=10" => Ok(("", (Field::Level, Operator::Equals, Value::Numerical(10)))))]
|
#[test_case("l=10" => Ok(("", (Field::Level, Operator::Equal, Value::Numerical(10)))))]
|
||||||
#[test_case("Ib" => Ok(("", (Field::Name, Operator::Equals, Value::String("ib".to_owned())))))]
|
#[test_case("Ib" => Ok(("", (Field::Name, Operator::Equal, Value::String("ib".to_owned())))))]
|
||||||
|
#[test_case("c!=synchro" => Ok(("", (Field::Class, Operator::NotEqual, Value::String("synchro".to_owned())))))]
|
||||||
fn successful_parsing_test(input: &str) -> IResult<&str, RawCardFilter> {
|
fn successful_parsing_test(input: &str) -> IResult<&str, RawCardFilter> {
|
||||||
parse_raw_filter(input)
|
parse_raw_filter(input)
|
||||||
}
|
}
|
||||||
@ -156,13 +160,13 @@ mod tests {
|
|||||||
fn sequential_parsing_test() {
|
fn sequential_parsing_test() {
|
||||||
let (rest, filter) = parse_raw_filter("atk>=100 l:4").unwrap();
|
let (rest, filter) = parse_raw_filter("atk>=100 l:4").unwrap();
|
||||||
assert_eq!(filter, (Field::Atk, Operator::GreaterEqual, Value::Numerical(100)));
|
assert_eq!(filter, (Field::Atk, Operator::GreaterEqual, Value::Numerical(100)));
|
||||||
assert_eq!(parse_raw_filter(rest), Ok(("", (Field::Level, Operator::Equals, Value::Numerical(4)))));
|
assert_eq!(parse_raw_filter(rest), Ok(("", (Field::Level, Operator::Equal, Value::Numerical(4)))));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_raw_filters("atk>=100 l=4"),
|
parse_raw_filters("atk>=100 l=4"),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
vec![(Field::Atk, Operator::GreaterEqual, Value::Numerical(100)), (Field::Level, Operator::Equals, Value::Numerical(4))]
|
vec![(Field::Atk, Operator::GreaterEqual, Value::Numerical(100)), (Field::Level, Operator::Equal, Value::Numerical(4))]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -171,9 +175,9 @@ mod tests {
|
|||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
vec![
|
vec![
|
||||||
(Field::Type, Operator::Equals, Value::String("counter".into())),
|
(Field::Type, Operator::Equal, Value::String("counter".into())),
|
||||||
(Field::Class, Operator::Equals, Value::String("trap".into())),
|
(Field::Class, Operator::Equal, Value::String("trap".into())),
|
||||||
(Field::Text, Operator::Equals, Value::String("negate the summon".into())),
|
(Field::Text, Operator::Equal, Value::String("negate the summon".into())),
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
@ -183,6 +187,6 @@ mod tests {
|
|||||||
fn quoted_value_test() {
|
fn quoted_value_test() {
|
||||||
let (rest, filter) = parse_raw_filter(r#"o:"destroy that target""#).unwrap();
|
let (rest, filter) = parse_raw_filter(r#"o:"destroy that target""#).unwrap();
|
||||||
assert_eq!(rest, "");
|
assert_eq!(rest, "");
|
||||||
assert_eq!(filter, (Field::Text, Operator::Equals, Value::String("destroy that target".into())));
|
assert_eq!(filter, (Field::Text, Operator::Equal, Value::String("destroy that target".into())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user