Add card sets and allow to filter by them
This commit is contained in:
parent
1d3a79857c
commit
eee93f0d6e
74
src/data.rs
74
src/data.rs
@ -1,5 +1,5 @@
|
||||
use serde::Deserialize;
|
||||
use std::fmt::{self, Display};
|
||||
use std::fmt::{self, Display, Write};
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
|
||||
pub struct CardInfo {
|
||||
@ -26,6 +26,26 @@ pub struct Card {
|
||||
pub link_rating: Option<i32>,
|
||||
#[serde(rename = "linkmarkers")]
|
||||
pub link_arrows: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub card_sets: Vec<CardSet>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Default)]
|
||||
pub struct CardSet {
|
||||
pub set_name: String,
|
||||
pub set_code: String,
|
||||
pub set_rarity: String,
|
||||
}
|
||||
|
||||
impl Card {
|
||||
pub fn extended_info(&self) -> Result<String, fmt::Error> {
|
||||
let mut s = String::with_capacity(1000);
|
||||
s.push_str("<h3>Printings:</h3>");
|
||||
for printing in &self.card_sets {
|
||||
write!(s, "{}: {} ({})<br/>", printing.set_name, printing.set_code, printing.set_rarity)?;
|
||||
}
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Card {
|
||||
@ -70,7 +90,23 @@ pub mod tests {
|
||||
"name": "The Cheerful Coffin",
|
||||
"type": "Spell Card",
|
||||
"desc": "Discard up to 3 Monster Cards from your hand to the Graveyard.",
|
||||
"race": "Normal"
|
||||
"race": "Normal",
|
||||
"card_sets": [
|
||||
{
|
||||
"set_name": "Dark Beginning 1",
|
||||
"set_code": "DB1-EN167",
|
||||
"set_rarity": "Common",
|
||||
"set_rarity_code": "(C)",
|
||||
"set_price": "1.41"
|
||||
},
|
||||
{
|
||||
"set_name": "Metal Raiders",
|
||||
"set_code": "MRD-059",
|
||||
"set_rarity": "Common",
|
||||
"set_rarity_code": "(C)",
|
||||
"set_price": "1.55"
|
||||
}
|
||||
]
|
||||
}"#;
|
||||
|
||||
pub const RAW_MONSTER: &str = r#"
|
||||
@ -83,7 +119,23 @@ pub mod tests {
|
||||
"def": 600,
|
||||
"level": 3,
|
||||
"race": "Zombie",
|
||||
"attribute": "EARTH"
|
||||
"attribute": "EARTH",
|
||||
"card_sets": [
|
||||
{
|
||||
"set_name": "Astral Pack Three",
|
||||
"set_code": "AP03-EN018",
|
||||
"set_rarity": "Common",
|
||||
"set_rarity_code": "(C)",
|
||||
"set_price": "1.24"
|
||||
},
|
||||
{
|
||||
"set_name": "Gold Series",
|
||||
"set_code": "GLD1-EN010",
|
||||
"set_rarity": "Common",
|
||||
"set_rarity_code": "(C)",
|
||||
"set_price": "2.07"
|
||||
}
|
||||
]
|
||||
}"#;
|
||||
|
||||
#[test]
|
||||
@ -97,6 +149,14 @@ pub mod tests {
|
||||
name: "The Cheerful Coffin".to_owned(),
|
||||
text: "Discard up to 3 Monster Cards from your hand to the Graveyard.".to_owned(),
|
||||
r#type: "Normal".to_owned(),
|
||||
card_sets: vec![
|
||||
CardSet {
|
||||
set_name: "Dark Beginning 1".to_owned(),
|
||||
set_code: "DB1-EN167".to_owned(),
|
||||
set_rarity: "Common".to_owned(),
|
||||
},
|
||||
CardSet { set_name: "Metal Raiders".to_owned(), set_code: "MRD-059".to_owned(), set_rarity: "Common".to_owned() }
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
)
|
||||
@ -119,6 +179,14 @@ pub mod tests {
|
||||
level: Some(3),
|
||||
r#type: "Zombie".to_owned(),
|
||||
attribute: Some("EARTH".to_owned()),
|
||||
card_sets: vec![
|
||||
CardSet {
|
||||
set_name: "Astral Pack Three".to_owned(),
|
||||
set_code: "AP03-EN018".to_owned(),
|
||||
set_rarity: "Common".to_owned(),
|
||||
},
|
||||
CardSet { set_name: "Gold Series".to_owned(), set_code: "GLD1-EN010".to_owned(), set_rarity: "Common".to_owned() }
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
|
@ -18,6 +18,7 @@ pub struct SearchCard {
|
||||
level: Option<i32>,
|
||||
link_rating: Option<i32>,
|
||||
link_arrows: Option<Vec<String>>,
|
||||
sets: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<&Card> for SearchCard {
|
||||
@ -34,6 +35,7 @@ impl From<&Card> for SearchCard {
|
||||
level: card.level,
|
||||
link_rating: card.link_rating,
|
||||
link_arrows: card.link_arrows.as_ref().map(|arrows| arrows.iter().map(|a| a.to_lowercase()).collect()),
|
||||
sets: card.card_sets.iter().filter_map(|s| s.set_code.split('-').next().map(str::to_lowercase)).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,6 +74,7 @@ pub fn build_filter(query: RawCardFilter) -> Result<CardFilter, String> {
|
||||
RawCardFilter(Field::Text, Operator::NotEqual, Value::String(s)) => Box::new(move |card| !card.text.contains(&s)),
|
||||
RawCardFilter(Field::Name, Operator::Equal, Value::String(s)) => Box::new(move |card| card.name.contains(&s)),
|
||||
RawCardFilter(Field::Name, Operator::NotEqual, Value::String(s)) => Box::new(move |card| !card.name.contains(&s)),
|
||||
RawCardFilter(Field::Set, Operator::Equal, Value::String(s)) => Box::new(move |card| card.sets.contains(&s)),
|
||||
q => Err(format!("unknown query: {q:?}"))?,
|
||||
})
|
||||
}
|
||||
@ -85,8 +88,8 @@ mod tests {
|
||||
fn level_filter_test() {
|
||||
let lacooda = SearchCard::from(&serde_json::from_str::<Card>(RAW_MONSTER).unwrap());
|
||||
let filter_level_3 = parse_filters("l=3").unwrap();
|
||||
assert!(filter_level_3[0].1(&lacooda));
|
||||
assert!(filter_level_3.1[0](&lacooda));
|
||||
let filter_level_5 = parse_filters("l=5").unwrap();
|
||||
assert!(!filter_level_5[0].1(&lacooda));
|
||||
assert!(!filter_level_5.1[0](&lacooda));
|
||||
}
|
||||
}
|
||||
|
@ -83,9 +83,11 @@ async fn card_info(card_id: web::Path<usize>) -> Result<HttpResponse, Box<dyn st
|
||||
<div>
|
||||
<img class="fullimage" src="{}/static/full/{}.jpg"/>
|
||||
{card}
|
||||
{}
|
||||
</div>"#,
|
||||
IMG_HOST.as_str(),
|
||||
card.id,
|
||||
card.extended_info().unwrap_or_else(|_| String::new()),
|
||||
)?;
|
||||
}
|
||||
None => res.push_str("Card not found"),
|
||||
|
@ -66,11 +66,12 @@ pub enum Field {
|
||||
Def = 2,
|
||||
Level = 3,
|
||||
LinkRating = 4,
|
||||
Type = 5,
|
||||
Attribute = 6,
|
||||
Class = 7,
|
||||
Name = 8,
|
||||
Text = 9,
|
||||
Set = 5,
|
||||
Type = 6,
|
||||
Attribute = 7,
|
||||
Class = 8,
|
||||
Name = 9,
|
||||
Text = 10,
|
||||
}
|
||||
|
||||
impl Display for Field {
|
||||
@ -85,6 +86,7 @@ impl Display for Field {
|
||||
Self::Atk => "ATK",
|
||||
Self::Def => "DEF",
|
||||
Self::LinkRating => "link rating",
|
||||
Self::Set => "set",
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -102,6 +104,7 @@ impl FromStr for Field {
|
||||
"o" | "eff" | "text" | "effect" | "e" => Self::Text,
|
||||
"lr" | "linkrating" => Self::LinkRating,
|
||||
"name" => Self::Name,
|
||||
"set" | "s" => Self::Set,
|
||||
_ => Err(s.to_string())?,
|
||||
})
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ Currently supported search fields are:
|
||||
<li>The <code>type</code> (or <code>t</code>) of a card (this is “Warrior”, “Pyro”, “Insect”, etc. for monsters, but also “quick-play”, “counter”, or “normal” for Spells/Traps).</li>
|
||||
<li>The <code>attribute</code> (or <code>attr</code> or <code>a</code>) of a card. This is “Light”, “Dark”, “Earth”, etc.</li>
|
||||
<li>The <code>text</code> (or <code>effect</code>, <code>eff</code>, <code>e</code>, or <code>o</code>) of a card. This is either the effect or flavor text (for normal monsters). For pendulum cards, this searches in both pendulum and monster effects. The <code>o</code> alias is to help my muscle memory coming from Scryfall.</li>
|
||||
<li>The <code>set</code> (or <code>s</code>) a card was printed in. This considers all printings, not just the original.</li>
|
||||
</ul>
|
||||
Anything not associated with a search field is interpreted as a search in the card name, so <a href="/?q=l%3A4+utopia"><code>l:4 utopia</code></a> will show all level/rank 4 monsters with “Utopia” in their name.<br/>
|
||||
If your search contains spaces (e.g. searching for an effect that says “destroy that target”), the text must be quoted like <code>effect:"destroy that target"</code>.
|
||||
@ -32,4 +33,5 @@ The following search operators are supported:
|
||||
<li>All “Blue-eyes” fusion monsters except the ones that are level 12: <a href="/?q=c%3Afusion+l%21%3D12+blue-eyes"><code>c:fusion l!=12 blue-eyes</code></a></li>
|
||||
<li>All Synchro monsters that are Dark attribute, level 5 or higher, and have exactly 2200 ATK: <a href="/?q=c%3Asynchro+a%3Adark+l%3E%3D5+atk%3A2200"><code>c:synchro a:dark l>=5 atk:2200</code></a></li>
|
||||
<li>All counter traps that can negate summons: <a href="/?q=c%3Atrap+t%3Acounter+e%3A%22negate+the+summon%22"><code>c:trap t:counter e:"negate the summon"</code></a></li>
|
||||
<li>All effect monsters printed in Legend of Blue-Eyes: <a href="/?q=set%3Alob+c%3Aeffect"><code>set:lob c:effect</code></a></li>
|
||||
</ul>
|
||||
|
Loading…
Reference in New Issue
Block a user