Add card artists

This commit is contained in:
Correl Roush 2024-05-10 14:09:28 -04:00
parent fc5c212db5
commit fba63c1e1f
9 changed files with 109 additions and 3 deletions

View file

@ -0,0 +1,62 @@
ALTER TABLE "scryfall"
ADD COLUMN IF NOT EXISTS "artist" TEXT;
DROP MATERIALIZED VIEW IF EXISTS "cards";
CREATE MATERIALIZED VIEW "cards" AS
SELECT "oracle"."oracle_id"
, "oracle"."name"
, "oracle"."color_identity"
, "oracle"."cmc"
, "oracle"."mana_cost"
, "oracle"."type_line"
, "oracle"."edhrec_rank"
, "oracle"."oracle_text"
, "scryfall"."scryfall_id"
, "scryfall"."set_code"
, "scryfall"."collector_number"
, "scryfall"."release_date"
, "scryfall"."rarity"
, "scryfall"."artist"
, "sets"."name" AS "set_name"
, "card_prices"."usd" AS "price_usd"
, "card_prices"."usd_foil" AS "price_usd_foil"
, "card_prices"."eur" AS "price_eur"
, "card_prices"."eur_foil" AS "price_eur_foil"
, "card_prices"."tix" AS "price_tix"
FROM "oracle"
JOIN "scryfall" USING ("oracle_id")
LEFT JOIN "card_prices" ON ("scryfall"."scryfall_id" = "card_prices"."scryfall_id"
AND "card_prices"."date" = (SELECT VALUE FROM "vars" WHERE "key" = 'last_update'))
JOIN "sets" USING ("set_code");
DROP MATERIALIZED VIEW IF EXISTS "oracle_latest";
CREATE MATERIALIZED VIEW "oracle_latest" AS
SELECT "oracle"."oracle_id"
, "oracle"."name"
, "oracle"."color_identity"
, "oracle"."cmc"
, "oracle"."mana_cost"
, "oracle"."type_line"
, "oracle"."edhrec_rank"
, "oracle"."oracle_text"
, "scryfall"."scryfall_id"
, "scryfall"."set_code"
, "scryfall"."collector_number"
, "scryfall"."release_date"
, "scryfall"."rarity"
, "scryfall"."artist"
, "sets"."name" AS "set_name"
, "card_prices"."usd" AS "price_usd"
, "card_prices"."usd_foil" AS "price_usd_foil"
, "card_prices"."eur" AS "price_eur"
, "card_prices"."eur_foil" AS "price_eur_foil"
, "card_prices"."tix" AS "price_tix"
FROM "oracle"
JOIN (
SELECT DISTINCT ON ("oracle_id") *
FROM "scryfall"
ORDER BY "oracle_id", "release_date" DESC
) "scryfall" USING ("oracle_id")
LEFT JOIN "card_prices" ON ("scryfall"."scryfall_id" = "card_prices"."scryfall_id"
AND "card_prices"."date" = (SELECT VALUE FROM "vars" WHERE "key" = 'last_update'))
JOIN "sets" USING ("set_code");

View file

@ -289,12 +289,21 @@ def update_scryfall(ctx, filename):
await cursor.execute(
"""
INSERT INTO "scryfall"
( "scryfall_id"
, "oracle_id"
, "set_code"
, "collector_number"
, "release_date"
, "rarity"
, "artist"
)
SELECT "scryfall_id"
, "oracle_id"
, "set_code"
, "collector_number"
, "release_date"
, "rarity"
, "artist"
FROM "tmp_cards"
ON CONFLICT (scryfall_id) DO UPDATE
SET "oracle_id" = "excluded"."oracle_id"
@ -302,6 +311,7 @@ def update_scryfall(ctx, filename):
, "collector_number" = "excluded"."collector_number"
, "release_date" = "excluded"."release_date"
, "rarity" = "excluded"."rarity"
, "artist" = "excluded"."artist"
"""
)
print("Updating card price data & indexes")

View file

@ -95,6 +95,7 @@ async def search(
games=set(),
legalities={},
edhrec_rank=row["edhrec_rank"],
artist=row["artist"],
oracle_text=row["oracle_text"],
)
for row in rows
@ -184,6 +185,9 @@ async def advanced_search(
f'OR (NOT "copies"."isFoil" AND cards.price_usd <= %({param})s))'
)
params[param] = criterion.price
if isinstance(criterion, tutor.search.Artist):
constraints.append(f"cards.artist ILIKE %({param})s")
params[param] = f"%{criterion.text}%"
if isinstance(criterion, tutor.search.Oracle):
constraints.append(f"cards.oracle_text ILIKE %({param})s")
params[param] = f"%{criterion.text}%"
@ -255,6 +259,7 @@ async def advanced_search(
games=set(),
legalities={},
edhrec_rank=row["edhrec_rank"],
artist=row["artist"],
oracle_text=row["oracle_text"],
price_usd=convert_price(row["price_usd"]),
price_usd_foil=convert_price(row["price_usd_foil"]),
@ -290,11 +295,11 @@ async def store_card(db: psycopg.AsyncCursor, card: tutor.models.Card) -> None:
INSERT INTO tmp_cards
("scryfall_id", "oracle_id", "name", "set_code", "collector_number",
"rarity", "color_identity", "cmc", "mana_cost", "type_line",
"release_date", "edhrec_rank", "oracle_text")
"release_date", "edhrec_rank", "artist", "oracle_text")
VALUES (%(scryfall_id)s, %(oracle_id)s, %(name)s, %(set_code)s,
%(collector_number)s, %(rarity)s, %(color_identity)s, %(cmc)s,
%(mana_cost)s, %(type_line)s, %(release_date)s, %(edhrec_rank)s,
%(oracle_text)s)
%(artist)s, %(oracle_text)s)
""",
{
"scryfall_id": str(card.scryfall_id),
@ -309,6 +314,7 @@ async def store_card(db: psycopg.AsyncCursor, card: tutor.models.Card) -> None:
"type_line": card.type_line,
"release_date": str(card.release_date) if card.release_date else None,
"edhrec_rank": card.edhrec_rank,
"artist": card.artist,
"oracle_text": card.oracle_text,
},
)

View file

@ -94,6 +94,7 @@ class Card:
legalities: typing.Dict[str, Legality]
mana_cost: typing.Optional[str] = None
edhrec_rank: typing.Optional[int] = None
artist: typing.Optional[str] = None
oracle_text: typing.Optional[str] = None
price_usd: typing.Optional[decimal.Decimal] = None
price_usd_foil: typing.Optional[decimal.Decimal] = None

View file

@ -38,6 +38,7 @@ def to_card(data: dict) -> Maybe[tutor.models.Card]:
edhrec_rank=Maybe.from_optional(data.get("edhrec_rank"))
.map(int)
.value_or(None),
artist=data.get("artist"),
oracle_text=data.get("oracle_text"),
price_usd=prices.get("usd"),
price_usd_foil=prices.get("usd_foil"),

View file

@ -39,6 +39,11 @@ class Type(Criterion):
text: parsy.string
@dataclasses.dataclass
class Artist(Criterion):
text: parsy.string
@dataclasses.dataclass
class Oracle(Criterion):
text: parsy.string
@ -173,6 +178,12 @@ type_line = parsy.seq(
text=string_literal,
).combine_dict(Type)
artist = parsy.seq(
_keyword=lstring_from("a", "artist"),
operator=matches,
text=string_literal,
).combine_dict(Artist)
oracle = parsy.seq(
_keyword=lstring_from("o", "oracle"),
operator=matches,
@ -200,7 +211,15 @@ partial_name = parsy.seq(text=string_literal).combine_dict(Name)
name = exact_name | partial_name
criterion = (
colors | expansion | rarity | type_line | oracle | collection | price_usd | name
colors
| expansion
| rarity
| type_line
| artist
| oracle
| collection
| price_usd
| name
)
padding = parsy.regex(r"\s*")

View file

@ -92,6 +92,7 @@ class JSONEncoder(json.JSONEncoder):
"cmc": float(card.cmc),
"mana_cost": card.mana_cost,
"type_line": card.type_line,
"artist": card.artist,
"oracle_text": card.oracle_text,
"prices": {
"usd": price(card.price_usd),

View file

@ -31,6 +31,7 @@ type alias Card =
, manaCost : String
, cmc : Float
, typeLine : String
, artist: String
, oracleText : String
, prices : Prices
}
@ -73,6 +74,10 @@ decode =
)
|> JDP.required "cmc" Json.Decode.float
|> JDP.required "type_line" Json.Decode.string
|> JDP.required "artist"
(Json.Decode.nullable Json.Decode.string
|> Json.Decode.map (Maybe.withDefault "")
)
|> JDP.required "oracle_text"
(Json.Decode.nullable Json.Decode.string
|> Json.Decode.map (Maybe.withDefault "")

View file

@ -620,6 +620,7 @@ viewCardDetails model =
[ E.text copy.card.name ]
, E.row [ E.spacing 5, E.centerX ] <|
List.map UI.priceBadge (prices copy.card copy.foil)
, E.paragraph [Font.size 16, Font.italic, Font.center] [ UI.text "Artist: ", UI.text copy.card.artist ]
, E.paragraph [] <| [ Symbol.text model.symbols 20 copy.card.manaCost, UI.text <| " " ++ copy.card.typeLine ]
, E.column [ E.spacing 10 ] <|
List.map (Symbol.text model.symbols 16) (String.lines copy.card.oracleText)