Compare commits
3 commits
82868b28c6
...
fba63c1e1f
Author | SHA1 | Date | |
---|---|---|---|
fba63c1e1f | |||
fc5c212db5 | |||
d74b4db4e7 |
10 changed files with 110 additions and 5 deletions
62
postgres/006-card-artists.sql
Normal file
62
postgres/006-card-artists.sql
Normal 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");
|
10
tutor/cli.py
10
tutor/cli.py
|
@ -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")
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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*")
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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 "")
|
||||||
|
|
|
@ -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)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -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 ]
|
||||||
|
|
Loading…
Reference in a new issue