diff --git a/src/data.rs b/src/data.rs index 51b6237..b7571f8 100644 --- a/src/data.rs +++ b/src/data.rs @@ -193,6 +193,43 @@ pub mod tests { ] }"#; + pub const RAW_LINK_MONSTER: &str = r#" + { + "id": 49202162, + "name": "Black Luster Soldier - Soldier of Chaos", + "type": "Link Monster", + "frameType": "link", + "desc": "3 monsters with different names\r\nIf this card was Link Summoned using a Level 7 or higher monster(s) as material, your opponent cannot target it with card effects, also it cannot be destroyed by your opponent's card effects. When this card destroys an opponent's monster by battle: You can activate 1 of these effects;\r\n● This card gains 1500 ATK.\r\n● This card can make a second attack during the Battle Phase of your next turn.\r\n● Banish 1 card on the field.", + "atk": 3000, + "race": "Warrior", + "attribute": "EARTH", + "archetype": "Black Luster Soldier", + "linkval": 3, + "linkmarkers": [ + "Top", + "Bottom-Left", + "Bottom-Right" + ], + "card_sets": [ + { + "set_name": "OTS Tournament Pack 17", + "set_code": "OP17-EN003", + "set_rarity": "Ultimate Rare", + "set_rarity_code": "(UtR)", + "set_price": "75.77" + } + ], + "card_images": [ + { + "id": 49202162, + "image_url": "https://images.ygoprodeck.com/images/cards/49202162.jpg", + "image_url_small": "https://images.ygoprodeck.com/images/cards_small/49202162.jpg", + "image_url_cropped": "https://images.ygoprodeck.com/images/cards_cropped/49202162.jpg" + } + ] + } + "#; + #[test] fn test_spell() { let coffin: Card = serde_json::from_str(RAW_SPELL).unwrap(); diff --git a/src/filter.rs b/src/filter.rs index 877dae6..0771fe9 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -56,12 +56,12 @@ pub type CardFilter = Box bool>; fn get_field_value(card: &SearchCard, field: Field) -> Value { match field { - Field::Atk => Value::Numerical(card.atk.unwrap_or(0)), - Field::Def => Value::Numerical(card.def.unwrap_or(0)), + Field::Atk => card.atk.map(Value::Numerical).unwrap_or_default(), + Field::Def => card.def.map(Value::Numerical).unwrap_or_default(), Field::Legal => Value::Numerical(card.legal_copies), - Field::Level => Value::Numerical(card.level.unwrap_or(0)), - Field::LinkRating => Value::Numerical(card.link_rating.unwrap_or(0)), - Field::Year => Value::Numerical(card.original_year.unwrap_or(0)), + Field::Level => card.level.map(Value::Numerical).unwrap_or_default(), + Field::LinkRating => card.link_rating.map(Value::Numerical).unwrap_or_default(), + Field::Year => card.original_year.map(Value::Numerical).unwrap_or_default(), Field::Set => Value::Multiple(card.sets.clone().into_iter().map(Value::String).collect()), Field::Type => Value::String(card.r#type.clone()), Field::Attribute => Value::String(card.attribute.clone().unwrap_or_default()), @@ -73,10 +73,12 @@ fn get_field_value(card: &SearchCard, field: Field) -> Value { fn filter_value(op: &Operator, field_value: &Value, query_value: &Value) -> bool { match (field_value, query_value) { + (Value::None, _) => false, (Value::Numerical(field), Value::Numerical(query)) => op.filter_number(Some(*field), *query), (Value::String(field), Value::String(query)) => match op { Operator::Equal => field.contains(query), Operator::NotEqual => !field.contains(query), + // greater/less than aren’t supported for string fields. _ => false, }, // Currently only for sets the card was released in. @@ -105,7 +107,10 @@ pub fn build_filter(RawCardFilter(field, op, value): RawCardFilter) -> Result(RAW_LINK_MONSTER).unwrap()); + let filter = parse_filters("l<=4").unwrap().1; + assert!(!filter[0](&bls)); + } + #[test] fn set_filter_test() { let lacooda = SearchCard::from(&serde_json::from_str::(RAW_MONSTER).unwrap()); diff --git a/src/parser.rs b/src/parser.rs index 6a6a0ef..2ac3834 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -232,11 +232,13 @@ impl Display for RawCardFilter { } } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Default)] pub enum Value { String(String), Numerical(i32), Multiple(Vec), + #[default] + None, } impl Display for Value { @@ -252,7 +254,8 @@ impl Display for Value { Self::Numerical(n) => write!(f, "{n}"), Self::Multiple(m) => { write!(f, "one of [{}]", m.iter().map(Value::to_string).join(", ")) - } + }, + Self::None => f.write_str("none"), } } }