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"."collector_number"
|
||||||
, "scryfall"."release_date"
|
, "scryfall"."release_date"
|
||||||
, "scryfall"."rarity"
|
, "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"
|
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";
|
DROP MATERIALIZED VIEW IF EXISTS "oracle_latest";
|
||||||
CREATE MATERIALIZED VIEW "oracle_latest" AS
|
CREATE MATERIALIZED VIEW "oracle_latest" AS
|
||||||
|
@ -167,9 +176,18 @@ SELECT "oracle"."oracle_id"
|
||||||
, "scryfall"."collector_number"
|
, "scryfall"."collector_number"
|
||||||
, "scryfall"."release_date"
|
, "scryfall"."release_date"
|
||||||
, "scryfall"."rarity"
|
, "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"
|
FROM "oracle"
|
||||||
JOIN (
|
JOIN (
|
||||||
SELECT DISTINCT ON ("oracle_id") *
|
SELECT DISTINCT ON ("oracle_id") *
|
||||||
FROM "scryfall"
|
FROM "scryfall"
|
||||||
ORDER BY "oracle_id", "release_date" DESC
|
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__)
|
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(
|
async def search(
|
||||||
db: psycopg.Cursor,
|
db: psycopg.Cursor,
|
||||||
name: typing.Optional[str] = None,
|
name: typing.Optional[str] = None,
|
||||||
|
@ -171,10 +178,6 @@ async def advanced_search(
|
||||||
else:
|
else:
|
||||||
joins.append("LEFT JOIN copies ON (cards.scryfall_id = copies.scryfall_id)")
|
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 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 = [
|
orderings = [
|
||||||
"cards.rarity DESC",
|
"cards.rarity DESC",
|
||||||
"length(cards.color_identity) DESC",
|
"length(cards.color_identity) DESC",
|
||||||
|
@ -185,15 +188,15 @@ async def advanced_search(
|
||||||
]
|
]
|
||||||
if sort_by == "price":
|
if sort_by == "price":
|
||||||
orderings = [
|
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,
|
*orderings,
|
||||||
]
|
]
|
||||||
params["last_update_key"] = "last_update"
|
params["last_update_key"] = "last_update"
|
||||||
query = " ".join(
|
query = " ".join(
|
||||||
[
|
[
|
||||||
"SELECT cards.*, card_prices.*, copies.*",
|
"SELECT cards.*, copies.*",
|
||||||
', CASE WHEN "copies"."isFoil" THEN card_prices.usd_foil',
|
', CASE WHEN "copies"."isFoil" THEN cards.price_usd_foil',
|
||||||
" ELSE card_prices.usd END AS usd",
|
" ELSE cards.price_usd END AS usd",
|
||||||
"FROM cards",
|
"FROM cards",
|
||||||
" ".join(joins),
|
" ".join(joins),
|
||||||
"WHERE" if constraints else "",
|
"WHERE" if constraints else "",
|
||||||
|
@ -207,12 +210,6 @@ async def advanced_search(
|
||||||
await db.execute(query, params)
|
await db.execute(query, params)
|
||||||
rows = await db.fetchall()
|
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 [
|
return [
|
||||||
tutor.models.CardCopy(
|
tutor.models.CardCopy(
|
||||||
card=tutor.models.Card(
|
card=tutor.models.Card(
|
||||||
|
@ -220,6 +217,7 @@ async def advanced_search(
|
||||||
oracle_id=row["oracle_id"],
|
oracle_id=row["oracle_id"],
|
||||||
name=row["name"],
|
name=row["name"],
|
||||||
set_code=row["set_code"],
|
set_code=row["set_code"],
|
||||||
|
set_name=row["set_name"],
|
||||||
collector_number=row["collector_number"],
|
collector_number=row["collector_number"],
|
||||||
rarity=tutor.models.Rarity.from_string(row["rarity"]),
|
rarity=tutor.models.Rarity.from_string(row["rarity"]),
|
||||||
color_identity=tutor.models.Color.from_string(row["color_identity"]),
|
color_identity=tutor.models.Color.from_string(row["color_identity"]),
|
||||||
|
@ -231,11 +229,11 @@ async def advanced_search(
|
||||||
legalities={},
|
legalities={},
|
||||||
edhrec_rank=row["edhrec_rank"],
|
edhrec_rank=row["edhrec_rank"],
|
||||||
oracle_text=row["oracle_text"],
|
oracle_text=row["oracle_text"],
|
||||||
price_usd=convert_price(row["usd"]),
|
price_usd=convert_price(row["price_usd"]),
|
||||||
price_usd_foil=convert_price(row["usd_foil"]),
|
price_usd_foil=convert_price(row["price_usd_foil"]),
|
||||||
price_eur=convert_price(row["eur"]),
|
price_eur=convert_price(row["price_eur"]),
|
||||||
price_eur_foil=convert_price(row["eur_foil"]),
|
price_eur_foil=convert_price(row["price_eur_foil"]),
|
||||||
price_tix=convert_price(row["tix"]),
|
price_tix=convert_price(row["price_tix"]),
|
||||||
),
|
),
|
||||||
foil=row["isFoil"] if row["isFoil"] is not None else False,
|
foil=row["isFoil"] if row["isFoil"] is not None else False,
|
||||||
collection=row["collection"] or "Default",
|
collection=row["collection"] or "Default",
|
||||||
|
@ -380,9 +378,15 @@ async def get_decks(
|
||||||
'oracle_text', "oracle_latest"."oracle_text",
|
'oracle_text', "oracle_latest"."oracle_text",
|
||||||
'scryfall_id', "oracle_latest"."scryfall_id",
|
'scryfall_id', "oracle_latest"."scryfall_id",
|
||||||
'set_code', "oracle_latest"."set_code",
|
'set_code', "oracle_latest"."set_code",
|
||||||
|
'set_name', "oracle_latest"."set_name",
|
||||||
'collector_number', "oracle_latest"."collector_number",
|
'collector_number', "oracle_latest"."collector_number",
|
||||||
'rarity', "oracle_latest"."rarity",
|
'rarity', "oracle_latest"."rarity",
|
||||||
'release_date', "oracle_latest"."release_date",
|
'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"
|
'quantity', "deck_list"."quantity"
|
||||||
))) AS "cards"
|
))) AS "cards"
|
||||||
FROM "decks"
|
FROM "decks"
|
||||||
|
@ -417,9 +421,15 @@ async def get_decks(
|
||||||
oracle_text=card.get("oracle_text"),
|
oracle_text=card.get("oracle_text"),
|
||||||
scryfall_id=card["scryfall_id"],
|
scryfall_id=card["scryfall_id"],
|
||||||
set_code=card["set_code"],
|
set_code=card["set_code"],
|
||||||
|
set_name=card["set_name"],
|
||||||
collector_number=card["collector_number"],
|
collector_number=card["collector_number"],
|
||||||
rarity=card["rarity"],
|
rarity=card["rarity"],
|
||||||
release_date=card["release_date"],
|
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"],
|
quantity=card["quantity"],
|
||||||
)
|
)
|
||||||
|
@ -450,9 +460,15 @@ async def get_deck(
|
||||||
'oracle_text', "oracle_latest"."oracle_text",
|
'oracle_text', "oracle_latest"."oracle_text",
|
||||||
'scryfall_id', "oracle_latest"."scryfall_id",
|
'scryfall_id', "oracle_latest"."scryfall_id",
|
||||||
'set_code', "oracle_latest"."set_code",
|
'set_code', "oracle_latest"."set_code",
|
||||||
|
'set_name', "oracle_latest"."set_name",
|
||||||
'collector_number', "oracle_latest"."collector_number",
|
'collector_number', "oracle_latest"."collector_number",
|
||||||
'rarity', "oracle_latest"."rarity",
|
'rarity', "oracle_latest"."rarity",
|
||||||
'release_date', "oracle_latest"."release_date",
|
'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"
|
'quantity', "deck_list"."quantity"
|
||||||
))) AS "cards"
|
))) AS "cards"
|
||||||
FROM "decks"
|
FROM "decks"
|
||||||
|
@ -486,9 +502,15 @@ async def get_deck(
|
||||||
oracle_text=card.get("oracle_text"),
|
oracle_text=card.get("oracle_text"),
|
||||||
scryfall_id=card["scryfall_id"],
|
scryfall_id=card["scryfall_id"],
|
||||||
set_code=card["set_code"],
|
set_code=card["set_code"],
|
||||||
|
set_name=card["set_name"],
|
||||||
collector_number=card["collector_number"],
|
collector_number=card["collector_number"],
|
||||||
rarity=card["rarity"],
|
rarity=card["rarity"],
|
||||||
release_date=card["release_date"],
|
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"],
|
quantity=card["quantity"],
|
||||||
)
|
)
|
||||||
|
@ -517,16 +539,13 @@ async def collection_stats(db: psycopg.Cursor) -> dict:
|
||||||
SELECT COUNT("copies"."id") AS cards
|
SELECT COUNT("copies"."id") AS cards
|
||||||
, SUM(
|
, SUM(
|
||||||
CASE WHEN "copies"."isFoil"
|
CASE WHEN "copies"."isFoil"
|
||||||
THEN "card_prices"."usd_foil"
|
THEN "cards"."price_usd_foil"
|
||||||
ELSE "card_prices"."usd"
|
ELSE "cards"."price_usd"
|
||||||
END
|
END
|
||||||
) AS value
|
) AS value
|
||||||
, COUNT(DISTINCT cards.set_code) AS sets
|
, COUNT(DISTINCT cards.set_code) AS sets
|
||||||
FROM "copies"
|
FROM "copies"
|
||||||
JOIN "cards" USING ("scryfall_id")
|
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()
|
return await db.fetchone()
|
||||||
|
|
|
@ -82,6 +82,7 @@ class Card:
|
||||||
oracle_id: uuid.UUID
|
oracle_id: uuid.UUID
|
||||||
name: str
|
name: str
|
||||||
set_code: str
|
set_code: str
|
||||||
|
set_name: str
|
||||||
collector_number: str
|
collector_number: str
|
||||||
rarity: str
|
rarity: str
|
||||||
color_identity: typing.List[Color]
|
color_identity: typing.List[Color]
|
||||||
|
|
|
@ -65,9 +65,9 @@ class JSONEncoder(json.JSONEncoder):
|
||||||
}
|
}
|
||||||
|
|
||||||
def _card(self, card: tutor.models.Card) -> dict:
|
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:
|
if amount is not None:
|
||||||
return str(amount)
|
return float(amount)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ class JSONEncoder(json.JSONEncoder):
|
||||||
"scryfall_id": str(card.scryfall_id),
|
"scryfall_id": str(card.scryfall_id),
|
||||||
"name": card.name,
|
"name": card.name,
|
||||||
"set_code": card.set_code,
|
"set_code": card.set_code,
|
||||||
|
"set_name": card.set_name,
|
||||||
"collector_number": card.collector_number,
|
"collector_number": card.collector_number,
|
||||||
"rarity": str(card.rarity),
|
"rarity": str(card.rarity),
|
||||||
"color_identity": tutor.models.Color.to_string(card.color_identity),
|
"color_identity": tutor.models.Color.to_string(card.color_identity),
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
"elm/regex": "1.0.0",
|
"elm/regex": "1.0.0",
|
||||||
"elm/url": "1.0.0",
|
"elm/url": "1.0.0",
|
||||||
"elm-community/maybe-extra": "5.2.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": {
|
"indirect": {
|
||||||
"elm/bytes": "1.0.8",
|
"elm/bytes": "1.0.8",
|
||||||
|
|
|
@ -5,11 +5,11 @@ import Json.Decode.Pipeline as JDP
|
||||||
|
|
||||||
|
|
||||||
type alias Prices =
|
type alias Prices =
|
||||||
{ usd : Maybe String
|
{ usd : Maybe Float
|
||||||
, usd_foil : Maybe String
|
, usd_foil : Maybe Float
|
||||||
, eur : Maybe String
|
, eur : Maybe Float
|
||||||
, eur_foil : Maybe String
|
, eur_foil : Maybe Float
|
||||||
, tix : Maybe String
|
, tix : Maybe Float
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,8 +91,8 @@ decodeCopy =
|
||||||
decodePrices : Json.Decode.Decoder Prices
|
decodePrices : Json.Decode.Decoder Prices
|
||||||
decodePrices =
|
decodePrices =
|
||||||
Json.Decode.succeed Prices
|
Json.Decode.succeed Prices
|
||||||
|> JDP.required "usd" (Json.Decode.nullable Json.Decode.string)
|
|> JDP.required "usd" (Json.Decode.nullable Json.Decode.float)
|
||||||
|> JDP.required "usd_foil" (Json.Decode.nullable Json.Decode.string)
|
|> JDP.required "usd_foil" (Json.Decode.nullable Json.Decode.float)
|
||||||
|> JDP.required "eur" (Json.Decode.nullable Json.Decode.string)
|
|> JDP.required "eur" (Json.Decode.nullable Json.Decode.float)
|
||||||
|> JDP.required "eur_foil" (Json.Decode.nullable Json.Decode.string)
|
|> JDP.required "eur_foil" (Json.Decode.nullable Json.Decode.float)
|
||||||
|> JDP.required "tix" (Json.Decode.nullable Json.Decode.string)
|
|> JDP.required "tix" (Json.Decode.nullable Json.Decode.float)
|
||||||
|
|
|
@ -495,7 +495,13 @@ viewCardBrowser model =
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
in
|
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
|
in
|
||||||
E.column attrs
|
E.column attrs
|
||||||
[ E.row
|
[ E.row
|
||||||
|
|
|
@ -20,6 +20,7 @@ import Element.Background as Background
|
||||||
import Element.Border as Border
|
import Element.Border as Border
|
||||||
import Element.Font as Font
|
import Element.Font as Font
|
||||||
import Maybe.Extra
|
import Maybe.Extra
|
||||||
|
import Round
|
||||||
import Spinner
|
import Spinner
|
||||||
import Symbol
|
import Symbol
|
||||||
import Task
|
import Task
|
||||||
|
@ -183,7 +184,7 @@ subtitle string =
|
||||||
E.el [ Font.size 16, Font.italic, Font.color colors.subtitle ] <| E.text 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 } =
|
priceBadge { currency, amount } =
|
||||||
E.el
|
E.el
|
||||||
[ Border.rounded 5
|
[ Border.rounded 5
|
||||||
|
@ -196,7 +197,7 @@ priceBadge { currency, amount } =
|
||||||
<|
|
<|
|
||||||
E.row [ E.width E.fill ]
|
E.row [ E.width E.fill ]
|
||||||
[ E.el [ E.width <| E.fillPortion 1 ] <| E.text <| String.toUpper currency
|
[ 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