Compare commits

...

3 commits

Author SHA1 Message Date
fba63c1e1f Add card artists 2024-05-10 14:09:28 -04:00
fc5c212db5 Split apart text lines in card details 2024-05-10 11:45:30 -04:00
d74b4db4e7 Fix card row height 2024-05-10 11:33:53 -04:00
10 changed files with 110 additions and 5 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( await cursor.execute(
""" """
INSERT INTO "scryfall" INSERT INTO "scryfall"
( "scryfall_id"
, "oracle_id"
, "set_code"
, "collector_number"
, "release_date"
, "rarity"
, "artist"
)
SELECT "scryfall_id" SELECT "scryfall_id"
, "oracle_id" , "oracle_id"
, "set_code" , "set_code"
, "collector_number" , "collector_number"
, "release_date" , "release_date"
, "rarity" , "rarity"
, "artist"
FROM "tmp_cards" FROM "tmp_cards"
ON CONFLICT (scryfall_id) DO UPDATE ON CONFLICT (scryfall_id) DO UPDATE
SET "oracle_id" = "excluded"."oracle_id" SET "oracle_id" = "excluded"."oracle_id"
@ -302,6 +311,7 @@ def update_scryfall(ctx, filename):
, "collector_number" = "excluded"."collector_number" , "collector_number" = "excluded"."collector_number"
, "release_date" = "excluded"."release_date" , "release_date" = "excluded"."release_date"
, "rarity" = "excluded"."rarity" , "rarity" = "excluded"."rarity"
, "artist" = "excluded"."artist"
""" """
) )
print("Updating card price data & indexes") print("Updating card price data & indexes")

View file

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

View file

@ -94,6 +94,7 @@ class Card:
legalities: typing.Dict[str, Legality] legalities: typing.Dict[str, Legality]
mana_cost: typing.Optional[str] = None mana_cost: typing.Optional[str] = None
edhrec_rank: typing.Optional[int] = None edhrec_rank: typing.Optional[int] = None
artist: typing.Optional[str] = None
oracle_text: typing.Optional[str] = None oracle_text: typing.Optional[str] = None
price_usd: typing.Optional[decimal.Decimal] = None price_usd: typing.Optional[decimal.Decimal] = None
price_usd_foil: 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")) edhrec_rank=Maybe.from_optional(data.get("edhrec_rank"))
.map(int) .map(int)
.value_or(None), .value_or(None),
artist=data.get("artist"),
oracle_text=data.get("oracle_text"), oracle_text=data.get("oracle_text"),
price_usd=prices.get("usd"), price_usd=prices.get("usd"),
price_usd_foil=prices.get("usd_foil"), price_usd_foil=prices.get("usd_foil"),

View file

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

View file

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

View file

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

View file

@ -620,8 +620,9 @@ viewCardDetails model =
[ E.text copy.card.name ] [ E.text copy.card.name ]
, E.row [ E.spacing 5, E.centerX ] <| , E.row [ E.spacing 5, E.centerX ] <|
List.map UI.priceBadge (prices copy.card copy.foil) 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.paragraph [] <| [ Symbol.text model.symbols 20 copy.card.manaCost, UI.text <| " " ++ copy.card.typeLine ]
, E.paragraph [] <| , E.column [ E.spacing 10 ] <|
List.map (Symbol.text model.symbols 16) (String.lines copy.card.oracleText) List.map (Symbol.text model.symbols 16) (String.lines copy.card.oracleText)
] ]

View file

@ -291,7 +291,6 @@ cardRow options attributes symbols card =
E.row E.row
(List.append (List.append
[ E.width E.fill [ E.width E.fill
, E.height (E.fill |> E.minimum 66)
, E.spacing 10 , E.spacing 10
, E.padding 3 , E.padding 3
, E.mouseOver [ Background.color colors.hover ] , E.mouseOver [ Background.color colors.hover ]