Improve price lookup and display
This commit is contained in:
parent
20e8c024ce
commit
10e239d65e
8 changed files with 89 additions and 42 deletions
|
@ -149,8 +149,17 @@ SELECT "oracle"."oracle_id"
|
|||
, "scryfall"."collector_number"
|
||||
, "scryfall"."release_date"
|
||||
, "scryfall"."rarity"
|
||||
, "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");
|
||||
JOIN "scryfall" USING ("oracle_id")
|
||||
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
|
||||
|
@ -167,9 +176,18 @@ SELECT "oracle"."oracle_id"
|
|||
, "scryfall"."collector_number"
|
||||
, "scryfall"."release_date"
|
||||
, "scryfall"."rarity"
|
||||
, "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");
|
||||
) "scryfall" USING ("oracle_id")
|
||||
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");
|
||||
|
|
|
@ -16,6 +16,13 @@ import tutor.search
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def convert_price(price: typing.Optional[str]) -> typing.Optional[decimal.Decimal]:
|
||||
if price:
|
||||
return decimal.Decimal(price)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
async def search(
|
||||
db: psycopg.Cursor,
|
||||
name: typing.Optional[str] = None,
|
||||
|
@ -171,10 +178,6 @@ async def advanced_search(
|
|||
else:
|
||||
joins.append("LEFT JOIN copies ON (cards.scryfall_id = copies.scryfall_id)")
|
||||
joins.append("JOIN sets ON (cards.set_code = sets.set_code)")
|
||||
joins.append(
|
||||
"JOIN card_prices ON (cards.scryfall_id = card_prices.scryfall_id "
|
||||
"AND card_prices.date = (select value from vars where key = %(last_update_key)s))"
|
||||
)
|
||||
orderings = [
|
||||
"cards.rarity DESC",
|
||||
"length(cards.color_identity) DESC",
|
||||
|
@ -185,15 +188,15 @@ async def advanced_search(
|
|||
]
|
||||
if sort_by == "price":
|
||||
orderings = [
|
||||
'CAST(COALESCE(CASE WHEN "copies"."isFoil" THEN card_prices.usd_foil ELSE card_prices.usd END, 0) as decimal) DESC',
|
||||
'CAST(COALESCE(CASE WHEN "copies"."isFoil" THEN cards.price_usd_foil ELSE cards.price_usd END, 0) as decimal) DESC',
|
||||
*orderings,
|
||||
]
|
||||
params["last_update_key"] = "last_update"
|
||||
query = " ".join(
|
||||
[
|
||||
"SELECT cards.*, card_prices.*, copies.*",
|
||||
', CASE WHEN "copies"."isFoil" THEN card_prices.usd_foil',
|
||||
" ELSE card_prices.usd END AS usd",
|
||||
"SELECT cards.*, copies.*",
|
||||
', CASE WHEN "copies"."isFoil" THEN cards.price_usd_foil',
|
||||
" ELSE cards.price_usd END AS usd",
|
||||
"FROM cards",
|
||||
" ".join(joins),
|
||||
"WHERE" if constraints else "",
|
||||
|
@ -207,12 +210,6 @@ async def advanced_search(
|
|||
await db.execute(query, params)
|
||||
rows = await db.fetchall()
|
||||
|
||||
def convert_price(price: typing.Optional[str]) -> typing.Optional[decimal.Decimal]:
|
||||
if price:
|
||||
return decimal.Decimal(price)
|
||||
else:
|
||||
return None
|
||||
|
||||
return [
|
||||
tutor.models.CardCopy(
|
||||
card=tutor.models.Card(
|
||||
|
@ -220,6 +217,7 @@ async def advanced_search(
|
|||
oracle_id=row["oracle_id"],
|
||||
name=row["name"],
|
||||
set_code=row["set_code"],
|
||||
set_name=row["set_name"],
|
||||
collector_number=row["collector_number"],
|
||||
rarity=tutor.models.Rarity.from_string(row["rarity"]),
|
||||
color_identity=tutor.models.Color.from_string(row["color_identity"]),
|
||||
|
@ -231,11 +229,11 @@ async def advanced_search(
|
|||
legalities={},
|
||||
edhrec_rank=row["edhrec_rank"],
|
||||
oracle_text=row["oracle_text"],
|
||||
price_usd=convert_price(row["usd"]),
|
||||
price_usd_foil=convert_price(row["usd_foil"]),
|
||||
price_eur=convert_price(row["eur"]),
|
||||
price_eur_foil=convert_price(row["eur_foil"]),
|
||||
price_tix=convert_price(row["tix"]),
|
||||
price_usd=convert_price(row["price_usd"]),
|
||||
price_usd_foil=convert_price(row["price_usd_foil"]),
|
||||
price_eur=convert_price(row["price_eur"]),
|
||||
price_eur_foil=convert_price(row["price_eur_foil"]),
|
||||
price_tix=convert_price(row["price_tix"]),
|
||||
),
|
||||
foil=row["isFoil"] if row["isFoil"] is not None else False,
|
||||
collection=row["collection"] or "Default",
|
||||
|
@ -380,9 +378,15 @@ async def get_decks(
|
|||
'oracle_text', "oracle_latest"."oracle_text",
|
||||
'scryfall_id', "oracle_latest"."scryfall_id",
|
||||
'set_code', "oracle_latest"."set_code",
|
||||
'set_name', "oracle_latest"."set_name",
|
||||
'collector_number', "oracle_latest"."collector_number",
|
||||
'rarity', "oracle_latest"."rarity",
|
||||
'release_date', "oracle_latest"."release_date",
|
||||
'price_usd', "oracle_latest"."price_usd",
|
||||
'price_usd_foil', "oracle_latest"."price_usd_foil",
|
||||
'price_eur', "oracle_latest"."price_eur",
|
||||
'price_eur_foil', "oracle_latest"."price_eur_foil",
|
||||
'price_tix', "oracle_latest"."price_tix",
|
||||
'quantity', "deck_list"."quantity"
|
||||
))) AS "cards"
|
||||
FROM "decks"
|
||||
|
@ -417,9 +421,15 @@ async def get_decks(
|
|||
oracle_text=card.get("oracle_text"),
|
||||
scryfall_id=card["scryfall_id"],
|
||||
set_code=card["set_code"],
|
||||
set_name=card["set_name"],
|
||||
collector_number=card["collector_number"],
|
||||
rarity=card["rarity"],
|
||||
release_date=card["release_date"],
|
||||
price_usd=convert_price(card.get("price_usd")),
|
||||
price_usd_foil=convert_price(card.get("price_usd_foil")),
|
||||
price_eur=convert_price(card.get("price_eur")),
|
||||
price_eur_foil=convert_price(card.get("price_eur_foil")),
|
||||
price_tix=convert_price(card.get("price_tix")),
|
||||
),
|
||||
quantity=card["quantity"],
|
||||
)
|
||||
|
@ -450,9 +460,15 @@ async def get_deck(
|
|||
'oracle_text', "oracle_latest"."oracle_text",
|
||||
'scryfall_id', "oracle_latest"."scryfall_id",
|
||||
'set_code', "oracle_latest"."set_code",
|
||||
'set_name', "oracle_latest"."set_name",
|
||||
'collector_number', "oracle_latest"."collector_number",
|
||||
'rarity', "oracle_latest"."rarity",
|
||||
'release_date', "oracle_latest"."release_date",
|
||||
'price_usd', "oracle_latest"."price_usd",
|
||||
'price_usd_foil', "oracle_latest"."price_usd_foil",
|
||||
'price_eur', "oracle_latest"."price_eur",
|
||||
'price_eur_foil', "oracle_latest"."price_eur_foil",
|
||||
'price_tix', "oracle_latest"."price_tix",
|
||||
'quantity', "deck_list"."quantity"
|
||||
))) AS "cards"
|
||||
FROM "decks"
|
||||
|
@ -486,9 +502,15 @@ async def get_deck(
|
|||
oracle_text=card.get("oracle_text"),
|
||||
scryfall_id=card["scryfall_id"],
|
||||
set_code=card["set_code"],
|
||||
set_name=card["set_name"],
|
||||
collector_number=card["collector_number"],
|
||||
rarity=card["rarity"],
|
||||
release_date=card["release_date"],
|
||||
price_usd=convert_price(card.get("price_usd")),
|
||||
price_usd_foil=convert_price(card.get("price_usd_foil")),
|
||||
price_eur=convert_price(card.get("price_eur")),
|
||||
price_eur_foil=convert_price(card.get("price_eur_foil")),
|
||||
price_tix=convert_price(card.get("price_tix")),
|
||||
),
|
||||
quantity=card["quantity"],
|
||||
)
|
||||
|
@ -517,16 +539,13 @@ async def collection_stats(db: psycopg.Cursor) -> dict:
|
|||
SELECT COUNT("copies"."id") AS cards
|
||||
, SUM(
|
||||
CASE WHEN "copies"."isFoil"
|
||||
THEN "card_prices"."usd_foil"
|
||||
ELSE "card_prices"."usd"
|
||||
THEN "cards"."price_usd_foil"
|
||||
ELSE "cards"."price_usd"
|
||||
END
|
||||
) AS value
|
||||
, COUNT(DISTINCT cards.set_code) AS sets
|
||||
FROM "copies"
|
||||
JOIN "cards" USING ("scryfall_id")
|
||||
LEFT JOIN "card_prices" USING ("scryfall_id")
|
||||
WHERE "card_prices"."date" =
|
||||
(SELECT "value" FROM "vars" where "key" = 'last_update')
|
||||
"""
|
||||
)
|
||||
return await db.fetchone()
|
||||
|
|
|
@ -82,6 +82,7 @@ class Card:
|
|||
oracle_id: uuid.UUID
|
||||
name: str
|
||||
set_code: str
|
||||
set_name: str
|
||||
collector_number: str
|
||||
rarity: str
|
||||
color_identity: typing.List[Color]
|
||||
|
|
|
@ -65,9 +65,9 @@ class JSONEncoder(json.JSONEncoder):
|
|||
}
|
||||
|
||||
def _card(self, card: tutor.models.Card) -> dict:
|
||||
def price(amount: typing.Optional[decimal.Decimal]) -> typing.Optional[str]:
|
||||
def price(amount: typing.Optional[decimal.Decimal]) -> typing.Optional[float]:
|
||||
if amount is not None:
|
||||
return str(amount)
|
||||
return float(amount)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
@ -75,6 +75,7 @@ class JSONEncoder(json.JSONEncoder):
|
|||
"scryfall_id": str(card.scryfall_id),
|
||||
"name": card.name,
|
||||
"set_code": card.set_code,
|
||||
"set_name": card.set_name,
|
||||
"collector_number": card.collector_number,
|
||||
"rarity": str(card.rarity),
|
||||
"color_identity": tutor.models.Color.to_string(card.color_identity),
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
"elm/regex": "1.0.0",
|
||||
"elm/url": "1.0.0",
|
||||
"elm-community/maybe-extra": "5.2.0",
|
||||
"mdgriffith/elm-ui": "1.1.8"
|
||||
"mdgriffith/elm-ui": "1.1.8",
|
||||
"myrho/elm-round": "1.0.5"
|
||||
},
|
||||
"indirect": {
|
||||
"elm/bytes": "1.0.8",
|
||||
|
|
|
@ -5,11 +5,11 @@ import Json.Decode.Pipeline as JDP
|
|||
|
||||
|
||||
type alias Prices =
|
||||
{ usd : Maybe String
|
||||
, usd_foil : Maybe String
|
||||
, eur : Maybe String
|
||||
, eur_foil : Maybe String
|
||||
, tix : Maybe String
|
||||
{ usd : Maybe Float
|
||||
, usd_foil : Maybe Float
|
||||
, eur : Maybe Float
|
||||
, eur_foil : Maybe Float
|
||||
, tix : Maybe Float
|
||||
}
|
||||
|
||||
|
||||
|
@ -91,8 +91,8 @@ decodeCopy =
|
|||
decodePrices : Json.Decode.Decoder Prices
|
||||
decodePrices =
|
||||
Json.Decode.succeed Prices
|
||||
|> JDP.required "usd" (Json.Decode.nullable Json.Decode.string)
|
||||
|> JDP.required "usd_foil" (Json.Decode.nullable Json.Decode.string)
|
||||
|> JDP.required "eur" (Json.Decode.nullable Json.Decode.string)
|
||||
|> JDP.required "eur_foil" (Json.Decode.nullable Json.Decode.string)
|
||||
|> JDP.required "tix" (Json.Decode.nullable Json.Decode.string)
|
||||
|> JDP.required "usd" (Json.Decode.nullable Json.Decode.float)
|
||||
|> JDP.required "usd_foil" (Json.Decode.nullable Json.Decode.float)
|
||||
|> JDP.required "eur" (Json.Decode.nullable Json.Decode.float)
|
||||
|> JDP.required "eur_foil" (Json.Decode.nullable Json.Decode.float)
|
||||
|> JDP.required "tix" (Json.Decode.nullable Json.Decode.float)
|
||||
|
|
|
@ -495,7 +495,13 @@ viewCardBrowser model =
|
|||
[]
|
||||
)
|
||||
in
|
||||
UI.cardRow { foil = copy.foil, subtitle = copy.collection } cardAttrs model.symbols copy.card
|
||||
UI.cardRow
|
||||
{ foil = copy.foil
|
||||
, subtitle = String.join " " [ copy.collection ]
|
||||
}
|
||||
cardAttrs
|
||||
model.symbols
|
||||
copy.card
|
||||
in
|
||||
E.column attrs
|
||||
[ E.row
|
||||
|
|
|
@ -20,6 +20,7 @@ import Element.Background as Background
|
|||
import Element.Border as Border
|
||||
import Element.Font as Font
|
||||
import Maybe.Extra
|
||||
import Round
|
||||
import Spinner
|
||||
import Symbol
|
||||
import Task
|
||||
|
@ -183,7 +184,7 @@ subtitle string =
|
|||
E.el [ Font.size 16, Font.italic, Font.color colors.subtitle ] <| E.text string
|
||||
|
||||
|
||||
priceBadge : { currency : String, amount : String } -> E.Element msg
|
||||
priceBadge : { currency : String, amount : Float } -> E.Element msg
|
||||
priceBadge { currency, amount } =
|
||||
E.el
|
||||
[ Border.rounded 5
|
||||
|
@ -196,7 +197,7 @@ priceBadge { currency, amount } =
|
|||
<|
|
||||
E.row [ E.width E.fill ]
|
||||
[ E.el [ E.width <| E.fillPortion 1 ] <| E.text <| String.toUpper currency
|
||||
, E.el [ E.width <| E.fillPortion 2, Font.alignRight ] <| E.text amount
|
||||
, E.el [ E.width <| E.fillPortion 2, Font.alignRight ] <| E.text <| Round.round 2 amount
|
||||
]
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue