2023-04-29 19:36:42 +00:00
{- # LANGUAGE DeriveGeneric, OverloadedStrings # -}
module Seed
2023-05-04 18:34:12 +00:00
( seedDataFile , seedDataWeb , DbCard ( .. )
2023-04-29 19:36:42 +00:00
) where
2023-05-04 18:34:12 +00:00
import Data.Aeson ( eitherDecode , FromJSON ( parseJSON ) , ToJSON ( toJSON ) , Value ( Object ) , ( .: ) , fromJSON , Key , ( .:? ) )
import Data.Text as T
2023-04-29 19:36:42 +00:00
import qualified Data.ByteString.Lazy as B
import Database.SQLite.Simple
import Config
import GHC.Generics
2023-04-30 16:48:50 +00:00
import DataFetcher ( fetchData )
2023-05-04 18:34:12 +00:00
import Prelude hiding ( id )
import Control.Exception ( IOException , try , SomeException )
import Data.Aeson.KeyMap ( keys , insert )
import Data.Aeson.Types ( toJSONKeyKey , Parser )
data CardFace = CardFace {
id :: Maybe Int ,
card_id :: Maybe Int ,
name :: Text ,
cmc :: Maybe Float ,
oracle_text :: Maybe Text ,
image_uris :: Maybe ImageUris ,
type_line :: Maybe Text ,
mana_cost :: Maybe Text
} deriving ( Show , Generic )
instance FromJSON CardFace
instance ToJSON CardFace
2023-04-29 19:36:42 +00:00
data ImageUris = ImageUris {
2023-05-04 18:34:12 +00:00
card_face_id :: Maybe Int ,
2023-04-29 19:36:42 +00:00
small :: Text ,
normal :: Text ,
large :: Text ,
png :: Text ,
art_crop :: Text ,
border_crop :: Text
} deriving ( Show , Generic )
instance FromJSON ImageUris
instance ToJSON ImageUris
2023-05-04 18:34:12 +00:00
data Legalities = Legalities {
cardId :: Maybe Int ,
standard :: Text ,
future :: Text ,
historic :: Text ,
gladiator :: Text ,
pioneer :: Text ,
explorer :: Text ,
modern :: Text ,
legacy :: Text ,
2023-05-05 13:29:09 +00:00
pauper :: Text ,
2023-05-04 18:34:12 +00:00
vintage :: Text ,
penny :: Text ,
commander :: Text ,
brawl :: Text ,
historicbrawl :: Text ,
alchemy :: Text ,
paupercommander :: Text ,
duel :: Text ,
oldschool :: Text ,
premodern :: Text ,
predh :: Text
} deriving ( Show , Generic )
instance FromJSON Legalities
2023-05-06 15:25:08 +00:00
data DbLegality = DbLegality Int Text Bool
2023-04-29 19:36:42 +00:00
data Card = Card {
2023-05-04 18:34:12 +00:00
c_id :: Text ,
2023-04-29 19:36:42 +00:00
lang :: Text ,
2023-05-04 18:34:12 +00:00
c_name :: Text ,
layout :: Text ,
c_cmc :: Maybe Float ,
c_oracle_text :: Maybe Text ,
c_type_line :: Maybe Text ,
c_mana_cost :: Maybe Text ,
card_faces :: Maybe [ CardFace ] ,
c_image_uris :: Maybe ImageUris ,
legalities :: Legalities
2023-04-29 19:36:42 +00:00
} deriving ( Show , Generic )
2023-05-04 18:34:12 +00:00
instance FromJSON Card where
parseJSON ( Object v ) = do
c_name <- v .: " name "
c_id <- v .: " id "
lang <- v .: " lang "
2023-05-05 13:29:09 +00:00
c_cmc <- v .:? " cmc "
2023-05-04 18:34:12 +00:00
c_oracle_text <- v .:? " oracle_text "
c_type_line <- v .:? " type_line "
c_mana_cost <- v .:? " mana_cost "
card_faces <- v .:? " card_faces "
layout <- v .: " layout "
c_image_uris <- v .:? " image_uris "
legalities <- v .: " legalities "
return ( Card {
c_id = c_id ,
lang = lang ,
c_name = c_name ,
c_cmc = c_cmc ,
c_oracle_text = c_oracle_text ,
c_type_line = c_type_line ,
c_mana_cost = c_mana_cost ,
card_faces = card_faces ,
layout = layout ,
c_image_uris = c_image_uris ,
legalities = legalities
} )
parseJSON a = error $ " could not parse card " ++ ( show a )
data DbCard = DbCard Int Text Text Text Text ( Maybe Float ) ( Maybe Text ) ( Maybe Text ) ( Maybe Text )
2023-05-06 15:25:08 +00:00
instance ToRow DbLegality where
toRow ( DbLegality id format legalStatus ) =
toRow ( id , format , legalStatus )
2023-05-04 18:34:12 +00:00
instance ToRow DbCard where
toRow ( DbCard id scryfall_id lang name layout cmc oracle_text type_line mana_cost ) =
toRow ( id , scryfall_id , lang , name , cmc , oracle_text , type_line , mana_cost )
2023-04-29 19:36:42 +00:00
2023-05-04 18:34:12 +00:00
instance ToRow CardFace where
toRow ( CardFace c_id card_id name cmc oracle_text image_uris type_line mana_cost ) =
toRow ( c_id , card_id , name , cmc , oracle_text , type_line , mana_cost )
instance ToRow ImageUris where
toRow ( ImageUris card_face_id small normal large png art_crop border_crop ) =
toRow ( card_face_id , small , normal , large , png , art_crop , border_crop )
2023-04-29 19:36:42 +00:00
2023-04-30 16:48:50 +00:00
seedDataFile :: IO ()
seedDataFile = do
-- Get JSON data and decode it
2023-04-29 19:36:42 +00:00
2023-04-30 16:48:50 +00:00
d <- getDataSeedPath
2023-04-29 19:36:42 +00:00
2023-04-30 16:48:50 +00:00
dat <- ( eitherDecode <$> getJSON d ) :: IO ( Either String [ Card ] )
seedData dat
2023-04-29 19:36:42 +00:00
2023-04-30 16:48:50 +00:00
seedDataWeb :: IO ()
seedDataWeb = do
dat <- ( eitherDecode <$> getJSONWeb ) :: IO ( Either String [ Card ] )
seedData dat
2023-05-04 18:34:12 +00:00
cardToDbCard :: Int -> Card -> DbCard
cardToDbCard id ( Card scryfall_id lang c_name layout c_cmc c_oracle_text c_type_line c_mana_cost _ _ _ ) =
DbCard id scryfall_id lang c_name layout c_cmc c_oracle_text c_type_line c_mana_cost
2023-04-30 16:48:50 +00:00
seedData d = do
2023-04-29 19:36:42 +00:00
dbPath <- getDbPath
conn <- open dbPath
2023-05-04 18:34:12 +00:00
execute_ conn " DROP TABLE IF EXISTS card "
execute_ conn " DROP TABLE IF EXISTS image_uris "
execute_ conn " DROP TABLE IF EXISTS card_face "
execute_ conn " DROP TABLE IF EXISTS legalities "
execute_ conn " CREATE TABLE IF NOT EXISTS card (id INTEGER PRIMARY KEY, scryfall_id TEXT, lang TEXT, name TEXT, cmc INT, oracle_text TEXT, type_line TEXT, mana_cost TEXT) "
execute_ conn " CREATE TABLE IF NOT EXISTS card_face (id INTEGER PRIMARY KEY,card_id INT, name TEXT, cmc INT, oracle_text TEXT, type_line TEXT, mana_cost TEXT) "
execute_ conn " CREATE TABLE IF NOT EXISTS image_uris (id INTEGER PRIMARY KEY, card_face_id INT, small TEXT, normal TEXT, large TEXT, png TEXT, art_crop TEXT, border_crop TEXT) "
2023-05-06 15:25:08 +00:00
execute_ conn " CREATE TABLE IF NOT EXISTS legalities (id INTEGER PRIMARY KEY,card_id INT, format TEXT, is_legal BOOL) "
2023-05-04 18:34:12 +00:00
2023-04-29 19:36:42 +00:00
case d of
Left err -> putStrLn err
2023-05-05 13:29:09 +00:00
Right ps -> do
collectedCards <- collectCards conn 0 0 ps
fillDb conn collectedCards
return ()
2023-05-04 18:34:12 +00:00
2023-04-29 19:36:42 +00:00
2023-04-30 16:48:50 +00:00
getJSON :: String -> IO B . ByteString
getJSON = B . readFile
getJSONWeb :: IO B . ByteString
getJSONWeb = fetchData
2023-05-04 18:34:12 +00:00
---------------------------------------------------------------------------------------------------------
2023-05-06 15:25:08 +00:00
collectCards :: Connection -> Int -> Int -> [ Card ] -> IO ( [ DbCard ] , [ DbLegality ] , [ ( CardFace , ImageUris ) ] )
2023-05-04 18:34:12 +00:00
--Skip illegal card types that are not relevant (These are difficult to parse as they contain non standard card formats)
2023-05-05 13:29:09 +00:00
collectCards conn card_id card_face_id ( ( Card _ _ _ layout _ _ _ _ _ _ _ ) : cards ) | unpack layout ` Prelude . elem ` [ " scheme " , " token " , " double_faced_token " , " emblem " , " art_series " , " vanguard " , " host " ] =
collectCards conn card_id card_face_id cards
2023-05-04 18:34:12 +00:00
--This should in theory never happen, however it is here for full coverage
2023-05-05 13:29:09 +00:00
collectCards _ _ _ ( card @ ( Card _ _ _ _ _ _ _ _ Nothing Nothing _ ) : _ ) = do
2023-05-04 18:34:12 +00:00
error $ " This cannot happen! No card can not have cardfaces as well as no image_uris on top level. Please fix ur data! "
--This will be ran when the card is single face (most cards)
2023-05-05 13:29:09 +00:00
collectCards conn card_id card_face_id ( card @ ( Card _ _ c_name _ c_cmc c_oracle_text c_type_line c_mana_cost Nothing image_uris @ ( Just ( ImageUris _ small normal large png art_crop border_crop ) ) legal ) : cards ) = do
let legalities = insertIdLegalities legal card_id
2023-05-04 18:34:12 +00:00
let cardFace = CardFace ( Just card_face_id ) ( Just card_id ) c_name c_cmc c_oracle_text Nothing c_type_line c_mana_cost
let imageUris = ImageUris ( Just card_face_id ) small normal large png art_crop border_crop
let dbCard = cardToDbCard card_id card
2023-05-05 13:29:09 +00:00
--insertRows conn dbCard legalities [(cardFace, imageUris)]
( dbCards , legalitiesRest , cfius ) <- collectCards conn ( card_id + 1 ) ( card_face_id + 1 ) cards
2023-05-06 15:25:08 +00:00
return ( dbCard : dbCards , legalities ++ legalitiesRest , ( cardFace , imageUris ) : cfius )
2023-05-04 18:34:12 +00:00
--This will be ran when a card is multi face
2023-05-05 13:29:09 +00:00
collectCards conn card_id card_face_id ( card @ ( Card _ _ _ _ _ _ _ _ ( Just card_faces ) Nothing legal ) : cards ) = do
let legalities = insertIdLegalities legal card_id
2023-05-04 18:34:12 +00:00
let dbCard = cardToDbCard card_id card
let cardFacesAndImageUris = addCardIdToCardFaces card_id card_face_id card_faces
2023-05-05 13:29:09 +00:00
--insertRows conn dbCard legalities cardFacesAndImageUris
( dbCards , legalitiesRest , cfius ) <- collectCards conn ( card_id + 1 ) ( card_face_id + Prelude . length cardFacesAndImageUris + 1 ) cards
2023-05-06 15:25:08 +00:00
return ( dbCard : dbCards , legalities ++ legalitiesRest , cardFacesAndImageUris ++ cfius )
2023-05-04 18:34:12 +00:00
--This will be ran when a card contains multiple cards on the front
2023-05-05 13:29:09 +00:00
collectCards conn card_id card_face_id ( card @ ( Card _ _ _ _ _ _ _ _ ( Just card_faces ) ( Just image_uris ) legal ) : cards ) = do
let legalities = insertIdLegalities legal card_id
2023-05-04 18:34:12 +00:00
let dbCard = cardToDbCard card_id card
let cardFacesAndImageUris = addCardIdAndImageUrisToCardFaces card_id card_face_id image_uris card_faces
2023-05-05 13:29:09 +00:00
--insertRows conn dbCard legalities cardFacesAndImageUris
( dbCards , legalitiesRest , cfius ) <- collectCards conn ( card_id + 1 ) ( card_face_id + Prelude . length cardFacesAndImageUris + 1 ) cards
2023-05-06 15:25:08 +00:00
return ( dbCard : dbCards , legalities ++ legalitiesRest , cardFacesAndImageUris ++ cfius )
2023-05-04 18:34:12 +00:00
2023-05-05 13:29:09 +00:00
collectCards _ _ _ [] = return ( [] , [] , [] )
2023-05-04 18:34:12 +00:00
2023-05-05 13:29:09 +00:00
-- Helper functions for collectCards
2023-05-04 18:34:12 +00:00
2023-05-06 15:25:08 +00:00
--God help me i know this is garbage
insertIdLegalities :: Legalities -> Int -> [ DbLegality ]
insertIdLegalities ( Legalities Nothing a b c d e f g h i j k l m n o p q r s t ) id =
[ DbLegality id " standard " ( a == " legal " ) , DbLegality id " future " ( b == " legal " ) , DbLegality id " historic " ( c == " legal " ) , DbLegality id " gladiator " ( d == " legal " ) , DbLegality id " pioneer " ( e == " legal " ) , DbLegality id " explorer " ( f == " legal " ) , DbLegality id " modern " ( g == " legal " ) , DbLegality id " legacy " ( h == " legal " ) , DbLegality id " pauper " ( i == " legal " ) , DbLegality id " vintage " ( j == " legal " ) , DbLegality id " penny " ( k == " legal " ) , DbLegality id " commander " ( l == " legal " ) , DbLegality id " brawl " ( m == " legal " ) , DbLegality id " historicBrawl " ( n == " legal " ) , DbLegality id " alchemy " ( o == " legal " ) , DbLegality id " paupercommander " ( p == " legal " ) , DbLegality id " duel " ( q == " legal " ) , DbLegality id " oldschool " ( r == " legal " ) , DbLegality id " premodern " ( s == " legal " ) , DbLegality id " predh " ( t == " legal " ) ]
2023-05-04 18:34:12 +00:00
insertIdLegalities _ _ = error $ " Illegal id insert into data legality "
2023-05-05 13:29:09 +00:00
2023-05-04 18:34:12 +00:00
addCardIdAndImageUrisToCardFaces :: Int -> Int -> ImageUris -> [ CardFace ] -> [ ( CardFace , ImageUris ) ]
addCardIdAndImageUrisToCardFaces card_id card_face_id image_uri ( card_face : faces ) = addCardIdAndImageUrisToCardFace card_id card_face_id image_uri card_face : addCardIdAndImageUrisToCardFaces card_id ( card_face_id + 1 ) image_uri faces
addCardIdAndImageUrisToCardFaces _ _ _ [] = []
addCardIdAndImageUrisToCardFace :: Int -> Int -> ImageUris -> CardFace -> ( CardFace , ImageUris )
addCardIdAndImageUrisToCardFace card_id card_face_id ( ImageUris _ small normal large png art_crop border_crop ) ( CardFace Nothing Nothing c_name c_cmc c_oracle_text Nothing c_type_line c_mana_cost ) =
( CardFace ( Just card_face_id ) ( Just card_id ) c_name c_cmc c_oracle_text Nothing c_type_line c_mana_cost , ImageUris ( Just card_face_id ) small normal large png art_crop border_crop )
addCardIdAndImageUrisToCardFace _ _ _ _ = error $ " This cardface and imageUris are not compatible "
addCardIdToCardFace :: Int -> Int -> CardFace -> ( CardFace , ImageUris )
addCardIdToCardFace card_id card_face_id ( CardFace Nothing Nothing c_name c_cmc c_oracle_text ( Just ( ImageUris i_card_face_id small normal large png art_crop border_crop ) ) c_type_line c_mana_cost ) =
( CardFace ( Just card_face_id ) ( Just card_id ) c_name c_cmc c_oracle_text Nothing c_type_line c_mana_cost , ImageUris ( Just card_face_id ) small normal large png art_crop border_crop )
addCardIdToCardFace _ _ _ = error $ " This cardface already has an id associated with it! "
addCardIdToCardFaces :: Int -> Int -> [ CardFace ] -> [ ( CardFace , ImageUris ) ]
addCardIdToCardFaces card_id card_face_id ( card : cards ) = addCardIdToCardFace card_id card_face_id card : addCardIdToCardFaces card_id ( card_face_id + 1 ) cards
addCardIdToCardFaces _ _ [] = []
2023-05-05 13:29:09 +00:00
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
2023-05-06 15:25:08 +00:00
fillDb :: Connection -> ( [ DbCard ] , [ DbLegality ] , [ ( CardFace , ImageUris ) ] ) -> IO ()
2023-05-05 13:29:09 +00:00
fillDb conn ( dbCards , legalities , combo ) = do
let ( cardFaces , imageUris ) = unzip combo
executeMany conn " INSERT INTO card (id, scryfall_id, lang, name, cmc, oracle_text, type_line, mana_cost ) VALUES (?,?,?,?,?,?,?,?) " dbCards
executeMany conn " INSERT INTO card_face (id, card_id, name, cmc, oracle_text, type_line, mana_cost) VALUES (?,?,?,?,?,?,?) " cardFaces
executeMany conn " INSERT INTO image_uris (card_face_id, small , normal , large , png , art_crop, border_crop) VALUES (?,?,?,?,?,?,?) " imageUris
2023-05-06 15:25:08 +00:00
executeMany conn " INSERT INTO legalities (card_id, format, is_legal) VALUES (?,?,?) " legalities