2023-04-29 19:36:42 +00:00
{- # LANGUAGE OverloadedStrings # -}
module Algorithm.BaseQuery
( superType ,
2023-04-30 16:48:50 +00:00
Card ( .. ) ,
cmcLT ,
cmcMT ,
cmcEQ ,
Tree ( .. )
2023-04-29 19:36:42 +00:00
) where
import qualified Data.Text as T
import Database.SQLite.Simple
import Config ( getDbPath )
import Data.Text ( Text , isInfixOf )
import Control.Monad.IO.Class ( MonadIO ( liftIO ) )
2023-04-30 16:48:50 +00:00
import Algorithm.Lex ( Operator )
2023-05-04 18:34:12 +00:00
import GHC.Generics ( Generic )
2023-04-30 16:48:50 +00:00
2023-05-04 18:34:12 +00:00
{-
In this module w e h a n d l e t h e " b o t t o m " r e q u e s t s , t h e s e a r e m a d e u s i n g Joins with only the minimum amount of data needed
Then the ID of the valid cards is used to fetch a full " Card " with all fields needed to show to the user
- }
2023-04-30 16:48:50 +00:00
data Tree = Funct Operator Tree Tree | Holder [ Card ]
2023-05-04 18:34:12 +00:00
data ImageUris = ImageUris
Int
2023-04-29 19:36:42 +00:00
Int
T . Text
T . Text
T . Text
2023-05-04 18:34:12 +00:00
T . Text
T . Text
T . Text
instance FromRow ImageUris where
fromRow = ImageUris <$> field <*> field <*> field <*> field <*> field <*> field <*> field <*> field
data TempCardFace = TempCardFace
Int
Int
T . Text
( Maybe Int )
2023-04-29 19:36:42 +00:00
( Maybe T . Text )
( Maybe T . Text )
2023-05-04 18:34:12 +00:00
( Maybe T . Text )
instance FromRow TempCardFace where
fromRow = TempCardFace <$> field <*> field <*> field <*> field <*> field <*> field <*> field
data TempCard = TempCard
Int
2023-04-29 19:36:42 +00:00
T . Text
2023-05-04 18:34:12 +00:00
T . Text
T . Text
( Maybe Int )
( Maybe T . Text )
T . Text
( Maybe T . Text )
instance FromRow TempCard where
fromRow = TempCard <$> field <*> field <*> field <*> field <*> field <*> field <*> field <*> field
data CardFace = CardFace
2023-04-30 16:48:50 +00:00
Int
2023-05-04 18:34:12 +00:00
Int
T . Text
( Maybe Int )
( Maybe T . Text )
( Maybe T . Text )
( Maybe T . Text )
ImageUris
data Card = Card
Int
T . Text
T . Text
T . Text
( Maybe Int )
( Maybe T . Text )
T . Text
( Maybe T . Text )
[ CardFace ]
2023-04-29 19:36:42 +00:00
2023-04-29 21:35:43 +00:00
instance Eq Card where
2023-05-04 18:34:12 +00:00
( == ) ( Card id_ _ _ _ _ _ _ _ _ ) ( Card id2_ _ _ _ _ _ _ _ _ ) = id_ == id2_
2023-04-29 21:35:43 +00:00
2023-05-04 18:34:12 +00:00
fetchCardsWithIds :: [ ID ] -> IO [ Card ]
fetchCardsWithIds = mapM fetchCardWithId
2023-04-29 19:36:42 +00:00
2023-05-04 18:34:12 +00:00
fetchCardWithId :: ID -> IO Card
fetchCardWithId ( ID id ) = do
tempCardFaces <- runQueryNamed " select id, card_id, name, cmc, oracle_text, type_line, mana_cost from card_face where card_id = :val " [ " :val " := id ] :: IO [ TempCardFace ]
--We are fetchinig based on primary key, so we know the result is a single data
[ TempCard id scryfall_id lang name cmc oracle_text type_line mana_cost ] <- runQueryNamed " select id, scryfall_id, lang, name, cmc, oracle_text,type_line, mana_cost from card where id = :val " [ " :val " := id ] :: IO [ TempCard ]
cardFaces <- mapM fetchImageUris tempCardFaces
return $ Card id scryfall_id lang name cmc oracle_text type_line mana_cost cardFaces
2023-04-29 19:36:42 +00:00
2023-05-04 18:34:12 +00:00
fetchImageUris :: TempCardFace -> IO ( CardFace )
fetchImageUris ( TempCardFace id card_id name cmc oracle_text type_line mana_cost ) = do
--We can do this only because a ImageUri row is 1:1 with CardFace in the database
[ imageUri ] <- runQueryNamed " select id, card_face_id, small, normal, large, png, art_crop, border_crop from image_uris where card_face_id = :val " [ " :val " := id ] :: IO [ ImageUris ]
return $ CardFace id card_id name cmc oracle_text type_line mana_cost imageUri
2023-04-29 19:36:42 +00:00
2023-05-04 18:34:12 +00:00
runQuerySimple :: ( FromRow a ) => Query -> IO [ a ]
2023-04-30 16:48:50 +00:00
runQuerySimple str = do
2023-04-29 19:36:42 +00:00
dbPath <- getDbPath
conn <- open dbPath
2023-05-04 18:34:12 +00:00
query_ conn str :: ( FromRow a ) => IO [ a ] ;
2023-04-30 16:48:50 +00:00
2023-05-04 18:34:12 +00:00
runQueryNamed :: ( FromRow a ) => Query -> [ NamedParam ] -> IO [ a ]
2023-04-30 16:48:50 +00:00
runQueryNamed qur parm = do
dbPath <- getDbPath
conn <- open dbPath
2023-05-04 18:34:12 +00:00
queryNamed conn qur parm :: ( FromRow a ) => IO [ a ]
2023-04-30 16:48:50 +00:00
2023-05-04 18:34:12 +00:00
--------------------------------------------------------------
data CardTypeLine = CardTypeLine
Int
T . Text
instance FromRow CardTypeLine where
fromRow = CardTypeLine <$> field <*> field
2023-04-30 16:48:50 +00:00
superType :: String -> IO Tree
superType qry = do
2023-05-04 18:34:12 +00:00
res <- runQuerySimple " select card.id, card_face.oracle_text from card inner join card_face where card.id = card_face.card_id and card_face.oracle_text is not null " :: IO [ CardTypeLine ]
cards <- fetchCardsWithIds ( typeLineFilter res ( T . pack qry ) )
return $ Holder cards
2023-04-29 19:36:42 +00:00
2023-05-04 18:34:12 +00:00
typeLineFilter :: [ CardTypeLine ] -> Text -> [ ID ]
typeLineFilter ( card @ ( CardTypeLine id type_line ) : cards ) qry = if qry ` isInfixOf ` type_line then ID id : typeLineFilter cards qry else typeLineFilter cards qry
2023-04-30 16:48:50 +00:00
typeLineFilter [] _ = []
2023-05-04 18:34:12 +00:00
--------------------------------------------------------------
newtype ID = ID Int
instance FromRow ID where
fromRow = ID <$> field
2023-04-30 16:48:50 +00:00
cmcLT :: Int -> IO Tree
cmcLT value = do
2023-05-04 18:34:12 +00:00
res <- runQueryNamed " select card.id from card inner join card_face where card.id = card_face.card_id and (card.cmc < :val or card_face.cmc < :val) " [ " :val " := value ] :: IO [ ID ]
cards <- fetchCardsWithIds res
return $ Holder cards
2023-04-30 16:48:50 +00:00
cmcMT :: Int -> IO Tree
cmcMT value = do
2023-05-04 18:34:12 +00:00
res <- runQueryNamed " select card.id from card inner join card_face where card.id = card_face.card_id and (card.cmc > :val or card_face.cmc > :val) " [ " :val " := value ] :: IO [ ID ]
cards <- fetchCardsWithIds res
return $ Holder cards
2023-04-29 19:36:42 +00:00
2023-04-30 16:48:50 +00:00
cmcEQ :: Int -> IO Tree
cmcEQ value = do
2023-05-04 18:34:12 +00:00
res <- runQueryNamed " select card.id from card inner join card_face where card.id = card_face.card_id and (card.cmc = :val or card_face.cmc = :val) " [ " :val " := value ] :: IO [ ID ]
cards <- fetchCardsWithIds res
return $ Holder cards