[haskell] abstracted away common database access patterns
This commit is contained in:
parent
24f6c8eb90
commit
dcd0a7a9b2
6 changed files with 85 additions and 50 deletions
30
haskell/src/SpaceTraders/APIClient/Contracts.hs
Normal file
30
haskell/src/SpaceTraders/APIClient/Contracts.hs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{-# LANGUAGE DeriveAnyClass #-}
|
||||||
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
module SpaceTraders.APIClient.Contracts
|
||||||
|
( myContracts
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Network.HTTP.Simple
|
||||||
|
|
||||||
|
import SpaceTraders
|
||||||
|
import SpaceTraders.APIClient.Client
|
||||||
|
import SpaceTraders.APIClient.Pagination
|
||||||
|
import SpaceTraders.Database.Contracts
|
||||||
|
import SpaceTraders.Model.Contract(Contract)
|
||||||
|
|
||||||
|
myContracts :: SpaceTradersT (APIResponse [Contract])
|
||||||
|
myContracts = do
|
||||||
|
listContracts' Pagination{limit=20, page=1, total=0}
|
||||||
|
where
|
||||||
|
listContracts' :: Pagination -> SpaceTradersT (APIResponse [Contract])
|
||||||
|
listContracts' p = do
|
||||||
|
resp <- sendPaginated (Just p) $ setRequestPath "/v2/my/contracts" :: SpaceTradersT (APIPaginatedResponse [Contract])
|
||||||
|
case resp of
|
||||||
|
Left e -> return $ Left e
|
||||||
|
Right (APIMessage r (Just p')) -> do
|
||||||
|
mapM_ setContract r
|
||||||
|
if (limit p' * page p' < total p') then listContracts' (nextPage p')
|
||||||
|
else Right <$> getContracts
|
||||||
|
_ -> undefined
|
|
@ -8,7 +8,6 @@ module SpaceTraders.Database.Agents
|
||||||
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Maybe
|
|
||||||
import qualified Database.SQLite.Simple as S
|
import qualified Database.SQLite.Simple as S
|
||||||
|
|
||||||
import SpaceTraders
|
import SpaceTraders
|
||||||
|
@ -16,17 +15,10 @@ import SpaceTraders.Model.Agent
|
||||||
import SpaceTraders.Utils
|
import SpaceTraders.Utils
|
||||||
|
|
||||||
addAgent :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Agent -> m ()
|
addAgent :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Agent -> m ()
|
||||||
addAgent agent = do
|
addAgent agent = execute "INSERT INTO agents(data) VALUES (json(?));" (S.Only (encode agent))
|
||||||
env <- ask
|
|
||||||
liftIO $ S.execute (getConn env) "INSERT INTO agents(data) VALUES (json(?));" (S.Only (encode agent))
|
|
||||||
|
|
||||||
getAgent :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m Agent
|
getAgent :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m Agent
|
||||||
getAgent = do
|
getAgent = one_ "SELECT data FROM agents";
|
||||||
env <- ask
|
|
||||||
ret <- liftIO $ S.query_ (getConn env) "SELECT data FROM agents;"
|
|
||||||
return . head . catMaybes $ map (decodeText . head) ret
|
|
||||||
|
|
||||||
setAgent :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Agent -> m ()
|
setAgent :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Agent -> m ()
|
||||||
setAgent agent = do
|
setAgent agent = execute "UPDATE agents SET data = json(?);" (S.Only (encode agent))
|
||||||
env <- ask
|
|
||||||
liftIO $ S.execute (getConn env) "UPDATE agents SET data = json(?);" (S.Only (encode agent))
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ module SpaceTraders.Database.Contracts
|
||||||
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Maybe
|
|
||||||
import qualified Database.SQLite.Simple as S
|
import qualified Database.SQLite.Simple as S
|
||||||
|
|
||||||
import SpaceTraders
|
import SpaceTraders
|
||||||
|
@ -17,24 +16,16 @@ import SpaceTraders.Model.Contract
|
||||||
import SpaceTraders.Utils
|
import SpaceTraders.Utils
|
||||||
|
|
||||||
addContract :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Contract -> m ()
|
addContract :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Contract -> m ()
|
||||||
addContract contract = do
|
addContract contract = execute "INSERT INTO contracts(data) VALUES (json(?));" (S.Only (encode contract))
|
||||||
env <- ask
|
|
||||||
liftIO $ S.execute (getConn env) "INSERT INTO contracts(data) VALUES (json(?));" (S.Only (encode contract))
|
|
||||||
|
|
||||||
getContracts :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m [Contract]
|
getContracts :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m [Contract]
|
||||||
getContracts = do
|
getContracts = query_ "SELECT data FROM contracts;"
|
||||||
env <- ask
|
|
||||||
ret <- liftIO $ S.query_ (getConn env) "SELECT data FROM contracts;"
|
|
||||||
return . catMaybes $ map (decodeText . head) ret
|
|
||||||
|
|
||||||
setContract :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Contract -> m ()
|
setContract :: (HasDatabaseConn env, MonadFail m, MonadIO m, MonadReader env m) => Contract -> m ()
|
||||||
setContract contract = do
|
setContract contract = do
|
||||||
env <- ask
|
c <- count "SELECT count(id) FROM contracts WHERE data->>'contractId' = ?;" (S.Only $ contractId contract)
|
||||||
count <- liftIO (S.query (getConn env) "SELECT count(id) FROM contracts WHERE data->>'contractId' = ?;" (S.Only $ contractId contract) :: IO [[Int]])
|
if c == 0 then addContract contract
|
||||||
if count == [[0]] then addContract contract
|
else updateContract contract
|
||||||
else updateContract contract
|
|
||||||
|
|
||||||
updateContract :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Contract -> m ()
|
updateContract :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Contract -> m ()
|
||||||
updateContract contract = do
|
updateContract contract = execute "UPDATE contracts SET data = json(?) WHERE data->>'contractId' = ?;" (encode contract, contractId contract)
|
||||||
env <- ask
|
|
||||||
liftIO $ S.execute (getConn env) "UPDATE contracts SET data = json(?) WHERE data->>'contractId' = ?;" (encode contract, contractId contract)
|
|
||||||
|
|
|
@ -7,10 +7,8 @@ module SpaceTraders.Database.Ships
|
||||||
, updateShip
|
, updateShip
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.Except
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Maybe
|
|
||||||
import qualified Database.SQLite.Simple as S
|
import qualified Database.SQLite.Simple as S
|
||||||
|
|
||||||
import SpaceTraders
|
import SpaceTraders
|
||||||
|
@ -18,24 +16,16 @@ import SpaceTraders.Model.Ship
|
||||||
import SpaceTraders.Utils
|
import SpaceTraders.Utils
|
||||||
|
|
||||||
addShip :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Ship -> m ()
|
addShip :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Ship -> m ()
|
||||||
addShip ship = do
|
addShip ship = execute "INSERT INTO ships(data) VALUES (json(?));" (S.Only $ encode ship)
|
||||||
env <- ask
|
|
||||||
liftIO $ S.execute (getConn env) "INSERT INTO ships(data) VALUES (json(?));" (S.Only $ encode ship)
|
|
||||||
|
|
||||||
getShips :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m [Ship]
|
getShips :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m [Ship]
|
||||||
getShips = do
|
getShips = query_ "SELECT data FROM ships;"
|
||||||
env <- ask
|
|
||||||
ret <- liftIO $ S.query_ (getConn env) "SELECT data FROM ships;"
|
|
||||||
return . catMaybes $ map (decodeText . head) ret
|
|
||||||
|
|
||||||
setShip :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Ship -> m ()
|
setShip :: (HasDatabaseConn env, MonadFail m, MonadIO m, MonadReader env m) => Ship -> m ()
|
||||||
setShip ship = do
|
setShip ship = do
|
||||||
env <- ask
|
c <- count "SELECT count(id) FROM ships WHERE data->>'symbol' = ?;" (S.Only $ symbol ship)
|
||||||
count <- liftIO (S.query (getConn env) "SELECT count(id) FROM ships WHERE data->>'symbol' = ?;" (S.Only $ symbol ship) :: IO [[Int]])
|
if c == 0 then addShip ship
|
||||||
if count == [[0]] then addShip ship
|
else updateShip ship
|
||||||
else updateShip ship
|
|
||||||
|
|
||||||
updateShip :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Ship -> m ()
|
updateShip :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Ship -> m ()
|
||||||
updateShip ship = do
|
updateShip ship = execute "UPDATE ships SET data = json(?) WHERE data->>'symbol' = ?;" (encode ship, symbol ship)
|
||||||
env <- ask
|
|
||||||
liftIO $ S.execute (getConn env) "UPDATE ships SET data = json(?) WHERE data->>'symbol' = ?;" (encode ship, symbol ship)
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ module SpaceTraders.Database.Systems
|
||||||
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Maybe
|
|
||||||
import qualified Database.SQLite.Simple as S
|
import qualified Database.SQLite.Simple as S
|
||||||
|
|
||||||
import SpaceTraders
|
import SpaceTraders
|
||||||
|
@ -21,7 +20,4 @@ addSystems systems = do
|
||||||
liftIO $ S.withTransaction conn $ S.executeMany conn "INSERT INTO systems(data) VALUES (json(?));" $ S.Only <$> map encode systems
|
liftIO $ S.withTransaction conn $ S.executeMany conn "INSERT INTO systems(data) VALUES (json(?));" $ S.Only <$> map encode systems
|
||||||
|
|
||||||
getSystems :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m [System]
|
getSystems :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m [System]
|
||||||
getSystems = do
|
getSystems = query_ "SELECT data FROM systems;"
|
||||||
env <- ask
|
|
||||||
ret <- liftIO $ S.query_ (getConn env) "SELECT data FROM systems;"
|
|
||||||
return . catMaybes $ map (decodeText . head) ret
|
|
||||||
|
|
|
@ -1,22 +1,58 @@
|
||||||
module SpaceTraders.Utils
|
module SpaceTraders.Utils
|
||||||
( decodeText
|
( count
|
||||||
|
, decodeText
|
||||||
|
, execute
|
||||||
, fromJSONValue
|
, fromJSONValue
|
||||||
, int2ByteString
|
, int2ByteString
|
||||||
|
, one_
|
||||||
|
, query
|
||||||
|
, query_
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Control.Monad.Reader
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Aeson.Types
|
import Data.Aeson.Types
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
import qualified Data.ByteString.Builder as B
|
import qualified Data.ByteString.Builder as B
|
||||||
import qualified Data.ByteString.Internal as B
|
import qualified Data.ByteString.Internal as B
|
||||||
|
import Data.Maybe
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as T
|
import qualified Data.Text.Encoding as T
|
||||||
|
import qualified Database.SQLite.Simple as S
|
||||||
|
|
||||||
|
import SpaceTraders
|
||||||
|
|
||||||
decodeText :: FromJSON a => T.Text -> Maybe a
|
decodeText :: FromJSON a => T.Text -> Maybe a
|
||||||
decodeText = decode . B.toLazyByteString . T.encodeUtf8Builder
|
decodeText = decode . B.toLazyByteString . T.encodeUtf8Builder
|
||||||
|
|
||||||
|
execute :: (HasDatabaseConn env, MonadReader env m, MonadIO m, S.ToRow t) => S.Query -> t -> m ()
|
||||||
|
execute q t = do
|
||||||
|
env <- ask
|
||||||
|
liftIO $ S.execute (getConn env) q t
|
||||||
|
|
||||||
fromJSONValue :: FromJSON a => Value -> Either String a
|
fromJSONValue :: FromJSON a => Value -> Either String a
|
||||||
fromJSONValue = parseEither parseJSON
|
fromJSONValue = parseEither parseJSON
|
||||||
|
|
||||||
int2ByteString :: Int -> B.ByteString
|
int2ByteString :: Int -> B.ByteString
|
||||||
int2ByteString = B.pack . map B.c2w . show
|
int2ByteString = B.pack . map B.c2w . show
|
||||||
|
|
||||||
|
one_ :: (FromJSON b, HasDatabaseConn env, MonadReader env m, MonadIO m) => S.Query -> m b
|
||||||
|
one_ q = query_ q >>= pure . head
|
||||||
|
|
||||||
|
count :: (HasDatabaseConn env, MonadFail m, MonadReader env m, MonadIO m, S.ToRow t) => S.Query -> t -> m Int
|
||||||
|
count q t = do
|
||||||
|
env <- ask
|
||||||
|
[[ret]] <- liftIO (S.query (getConn env) q t :: IO [[Int]])
|
||||||
|
return ret
|
||||||
|
|
||||||
|
query :: (FromJSON b, HasDatabaseConn env, MonadReader env m, MonadIO m, S.ToRow t) => S.Query -> t -> m [b]
|
||||||
|
query q t = do
|
||||||
|
env <- ask
|
||||||
|
ret <- liftIO $ S.query (getConn env) q t
|
||||||
|
return . catMaybes $ map (decodeText . head) ret
|
||||||
|
|
||||||
|
query_ :: (FromJSON b, HasDatabaseConn env, MonadReader env m, MonadIO m) => S.Query -> m [b]
|
||||||
|
query_ q = do
|
||||||
|
env <- ask
|
||||||
|
ret <- liftIO $ S.query_ (getConn env) q
|
||||||
|
return . catMaybes $ map (decodeText . head) ret
|
||||||
|
|
Loading…
Add table
Reference in a new issue