Cleanup type signatures and start working on debug env run
This commit is contained in:
parent
0808fe130a
commit
ffec891f26
21
src/Core.hs
21
src/Core.hs
@ -32,22 +32,23 @@ data AppEnv = AppEnv { pool :: Pool Connection }
|
|||||||
newtype UserId = UserId Int
|
newtype UserId = UserId Int
|
||||||
deriving (Show, Generic, FromField, ToField, FromHttpApiData, ToHttpApiData)
|
deriving (Show, Generic, FromField, ToField, FromHttpApiData, ToHttpApiData)
|
||||||
|
|
||||||
instance ToJSON UserId
|
|
||||||
instance FromJSON UserId
|
|
||||||
instance ToRow UserId
|
|
||||||
instance FromRow UserId
|
|
||||||
|
|
||||||
data User = User { userId :: UserId, userName :: T.Text}
|
data User = User { userId :: UserId, userName :: T.Text}
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic)
|
||||||
|
|
||||||
instance FromRow User where
|
instance ToJSON UserId
|
||||||
fromRow = User <$> field <*> field
|
instance FromJSON UserId
|
||||||
instance ToRow User where
|
|
||||||
toRow (User uid name) = toRow (uid, name)
|
instance ToRow UserId
|
||||||
|
instance FromRow UserId
|
||||||
|
|
||||||
instance ToJSON User
|
instance ToJSON User
|
||||||
instance FromJSON User
|
instance FromJSON User
|
||||||
|
|
||||||
|
instance ToRow User where
|
||||||
|
toRow (User uid name) = toRow (uid, name)
|
||||||
|
instance FromRow User where
|
||||||
|
fromRow = User <$> field <*> field
|
||||||
|
|
||||||
data Database :: Effect where
|
data Database :: Effect where
|
||||||
DatabaseInit
|
DatabaseInit
|
||||||
:: Database (Eff es) ()
|
:: Database (Eff es) ()
|
||||||
@ -58,7 +59,7 @@ data Database :: Effect where
|
|||||||
DatabaseWrite
|
DatabaseWrite
|
||||||
:: (ToRow a, Show a) => (Query, a) -> Database (Eff es) ()
|
:: (ToRow a, Show a) => (Query, a) -> Database (Eff es) ()
|
||||||
|
|
||||||
data Logger :: Effect where
|
data Logger :: Effect where
|
||||||
WriteLog :: LogLevel -> String -> Logger (Eff es) ()
|
WriteLog :: LogLevel -> String -> Logger (Eff es) ()
|
||||||
|
|
||||||
data LogLevel = Info | Warning | Error
|
data LogLevel = Info | Warning | Error
|
||||||
|
@ -23,25 +23,54 @@ type DatabaseExeEffects es = ( Reader AppEnv :> es
|
|||||||
, IOE :> es
|
, IOE :> es
|
||||||
)
|
)
|
||||||
|
|
||||||
databaseInit
|
databaseInit :: (Database :> es, Error ServerError :> es)
|
||||||
:: (Database :> es, Error ServerError :> es) => Eff es ()
|
=> Eff es ()
|
||||||
databaseInit = send DatabaseInit
|
databaseInit = send DatabaseInit
|
||||||
|
|
||||||
databaseRead
|
databaseRead :: (ToField a, Show a, Database :> es, Error ServerError :> es)
|
||||||
:: (ToField a, Show a, Database :> es, Error ServerError :> es)
|
=> (Query, a) -> Eff es [User]
|
||||||
=> (Query, a) -> Eff es [User]
|
|
||||||
databaseRead = send . DatabaseRead
|
databaseRead = send . DatabaseRead
|
||||||
|
|
||||||
databaseRead_
|
databaseRead_ :: (Database :> es, Error ServerError :> es)
|
||||||
:: (Database :> es, Error ServerError :> es) => Query -> Eff es [User]
|
=> Query -> Eff es [User]
|
||||||
databaseRead_ = send . DatabaseRead_
|
databaseRead_ = send . DatabaseRead_
|
||||||
|
|
||||||
databaseWrite
|
databaseWrite :: (ToRow a, Show a, Database :> es, Error ServerError :> es)
|
||||||
:: (ToRow a, Show a, Database :> es, Error ServerError :> es)
|
=> (Query, a) -> Eff es ()
|
||||||
=> (Query, a) -> Eff es ()
|
|
||||||
databaseWrite = send . DatabaseWrite
|
databaseWrite = send . DatabaseWrite
|
||||||
|
|
||||||
runDatabaseDebug :: DatabaseExeEffects es => Eff (Database : es) a -> Eff es a
|
runDatabaseIO :: DatabaseExeEffects es
|
||||||
|
=> Eff (Database : es) a -> Eff es a
|
||||||
|
runDatabaseIO = interpret $ \_ -> \case
|
||||||
|
DatabaseInit -> do
|
||||||
|
AppEnv { pool } <- ask
|
||||||
|
liftWithPool pool $ \conn -> do
|
||||||
|
execute_ conn createUsersTable
|
||||||
|
execute_ conn createLogsTable
|
||||||
|
pure ()
|
||||||
|
|
||||||
|
DatabaseRead (statement, values) -> do
|
||||||
|
AppEnv { pool } <- ask
|
||||||
|
liftWithPool pool $ \conn ->
|
||||||
|
query conn statement (Only values)
|
||||||
|
|
||||||
|
DatabaseRead_ statement -> do
|
||||||
|
AppEnv { pool } <- ask
|
||||||
|
liftWithPool pool $ \conn ->
|
||||||
|
query_ conn statement
|
||||||
|
|
||||||
|
DatabaseWrite (statement, values) -> do
|
||||||
|
AppEnv { pool } <- ask
|
||||||
|
liftWithPool pool $ \conn -> do
|
||||||
|
execute conn statement values
|
||||||
|
pure ()
|
||||||
|
where
|
||||||
|
liftWithPool :: (IOE :> es, Error ServerError :> es)
|
||||||
|
=> (Pool Connection) -> (Connection -> IO a) -> Eff es a
|
||||||
|
liftWithPool p f = liftIOE $ withResource p f
|
||||||
|
|
||||||
|
runDatabaseDebug :: DatabaseExeEffects es
|
||||||
|
=> Eff (Database : es) a -> Eff es a
|
||||||
runDatabaseDebug = interpret $ \_ -> \case
|
runDatabaseDebug = interpret $ \_ -> \case
|
||||||
DatabaseInit -> do
|
DatabaseInit -> do
|
||||||
liftIOE $ putStrLn "Mocked setup of the database"
|
liftIOE $ putStrLn "Mocked setup of the database"
|
||||||
@ -49,7 +78,7 @@ runDatabaseDebug = interpret $ \_ -> \case
|
|||||||
liftIOE $ putStrLn
|
liftIOE $ putStrLn
|
||||||
$ "Mocked a READ database operation with statement:\n"
|
$ "Mocked a READ database operation with statement:\n"
|
||||||
++ show statement
|
++ show statement
|
||||||
++ " and values:\n"
|
++ "\nValues:\n"
|
||||||
++ show values
|
++ show values
|
||||||
pure []
|
pure []
|
||||||
DatabaseRead_ statement -> do
|
DatabaseRead_ statement -> do
|
||||||
@ -57,44 +86,10 @@ runDatabaseDebug = interpret $ \_ -> \case
|
|||||||
pure []
|
pure []
|
||||||
DatabaseWrite (statement, values) -> do
|
DatabaseWrite (statement, values) -> do
|
||||||
liftIOE $ putStrLn
|
liftIOE $ putStrLn
|
||||||
$ "Mocked a WRITE database operation with a user named " ++ show values
|
$ "Mocked a WRITE database operation with statement:\n"
|
||||||
|
++ show statement
|
||||||
runDatabaseIO :: DatabaseExeEffects es => Eff (Database : es) a -> Eff es a
|
++ "\nValues:\n"
|
||||||
runDatabaseIO = interpret $ \_ -> \case
|
++ show values
|
||||||
DatabaseInit -> init
|
|
||||||
DatabaseRead (statement, values) -> read statement values
|
|
||||||
DatabaseRead_ statement -> read_ statement
|
|
||||||
DatabaseWrite (statement, values) -> write statement values
|
|
||||||
where
|
|
||||||
init :: DatabaseExeEffects es => Eff es ()
|
|
||||||
init = do
|
|
||||||
AppEnv { pool } <- ask
|
|
||||||
liftWithPool pool $ \conn -> do
|
|
||||||
execute_ conn createUsersTable
|
|
||||||
execute_ conn createLogsTable
|
|
||||||
pure ()
|
|
||||||
|
|
||||||
read :: (ToField a, FromRow b, DatabaseExeEffects es)
|
|
||||||
=> Query -> a -> Eff es [b]
|
|
||||||
read statement values = do
|
|
||||||
AppEnv { pool } <- ask
|
|
||||||
liftWithPool pool $ \conn ->
|
|
||||||
query conn statement (Only values)
|
|
||||||
|
|
||||||
read_ :: (FromRow b, DatabaseExeEffects es) => Query -> Eff es [b]
|
|
||||||
read_ statement = do
|
|
||||||
AppEnv { pool } <- ask
|
|
||||||
liftWithPool pool $ \conn ->
|
|
||||||
query_ conn statement
|
|
||||||
|
|
||||||
write :: (DatabaseExeEffects es, ToRow a) => Query -> a -> Eff es ()
|
|
||||||
write statement values = do
|
|
||||||
AppEnv { pool } <- ask
|
|
||||||
liftWithPool pool $ \conn -> do
|
|
||||||
execute conn statement values
|
|
||||||
pure ()
|
|
||||||
|
|
||||||
liftWithPool p f = liftIOE $ withResource p f
|
|
||||||
|
|
||||||
createConnectionPool :: IO (Pool Connection)
|
createConnectionPool :: IO (Pool Connection)
|
||||||
createConnectionPool = newPool $ defaultPoolConfig
|
createConnectionPool = newPool $ defaultPoolConfig
|
||||||
|
@ -14,24 +14,29 @@ import qualified Servant as S
|
|||||||
|
|
||||||
type CRUD es = ( Database :> es, Logger :> es, Error ServerError :> es )
|
type CRUD es = ( Database :> es, Logger :> es, Error ServerError :> es )
|
||||||
|
|
||||||
rootHandler :: (Logger :> es, Error ServerError :> es) => Eff es T.Text
|
rootHandler :: (Logger :> es, Error ServerError :> es)
|
||||||
|
=> Eff es T.Text
|
||||||
rootHandler = (writeLog Info "Hit the root!") >>= \_ ->
|
rootHandler = (writeLog Info "Hit the root!") >>= \_ ->
|
||||||
return "Hello, World!"
|
return "Hello, World!"
|
||||||
|
|
||||||
userListHandler :: CRUD es => Eff es [User]
|
userListHandler :: CRUD es
|
||||||
|
=> Eff es [User]
|
||||||
userListHandler = (writeLog Info "Selected all users!") >>= \_ ->
|
userListHandler = (writeLog Info "Selected all users!") >>= \_ ->
|
||||||
databaseRead_ "SELECT id, name FROM users"
|
databaseRead_ "SELECT id, name FROM users"
|
||||||
|
|
||||||
userGetHandler :: CRUD es => UserId -> Eff es User
|
userGetHandler :: CRUD es
|
||||||
|
=> UserId -> Eff es User
|
||||||
userGetHandler userId = databaseRead (queryUser userId) >>= \mUser ->
|
userGetHandler userId = databaseRead (queryUser userId) >>= \mUser ->
|
||||||
case mUser of
|
case mUser of
|
||||||
(a:_) -> pure a
|
(a:_) -> pure a
|
||||||
[] -> pure (User (UserId 0) "No user found")
|
[] -> pure (User (UserId 0) "No user found")
|
||||||
|
|
||||||
userPostHandler :: CRUD es => T.Text -> Eff es NoContent
|
userPostHandler :: CRUD es
|
||||||
|
=> T.Text -> Eff es NoContent
|
||||||
userPostHandler name =
|
userPostHandler name =
|
||||||
databaseWrite (writeUser name) >>= \_ -> return NoContent
|
databaseWrite (writeUser name) >>= \_ -> return NoContent
|
||||||
|
|
||||||
userDeleteHandler :: CRUD es => UserId -> Eff es NoContent
|
userDeleteHandler :: CRUD es
|
||||||
|
=> UserId -> Eff es NoContent
|
||||||
userDeleteHandler userId =
|
userDeleteHandler userId =
|
||||||
databaseWrite (deleteUser userId) >>= \_ -> return NoContent
|
databaseWrite (deleteUser userId) >>= \_ -> return NoContent
|
||||||
|
@ -19,8 +19,8 @@ writeLog :: (Logger :> es, Error ServerError :> es)
|
|||||||
=> LogLevel -> String -> Eff es ()
|
=> LogLevel -> String -> Eff es ()
|
||||||
writeLog level msg = send (WriteLog level msg)
|
writeLog level msg = send (WriteLog level msg)
|
||||||
|
|
||||||
runLoggerConsole :: (Error ServerError :> es, IOE :> es) =>
|
runLoggerConsole :: (Error ServerError :> es, IOE :> es)
|
||||||
Eff (Logger : es) a -> Eff es a
|
=> Eff (Logger : es) a -> Eff es a
|
||||||
runLoggerConsole = interpret $ \_ -> \case
|
runLoggerConsole = interpret $ \_ -> \case
|
||||||
WriteLog level msg -> do
|
WriteLog level msg -> do
|
||||||
time <- liftIOE getCurrentTime
|
time <- liftIOE getCurrentTime
|
||||||
@ -29,19 +29,9 @@ runLoggerConsole = interpret $ \_ -> \case
|
|||||||
++ "LEVEL: " ++ show level ++ "\n"
|
++ "LEVEL: " ++ show level ++ "\n"
|
||||||
++ "MESSAGE: " ++ msg
|
++ "MESSAGE: " ++ msg
|
||||||
|
|
||||||
runLoggerPSQL :: LogToDatabase es => Eff (Logger : es) a -> Eff es a
|
runLoggerPSQL :: LogToDatabase es
|
||||||
|
=> Eff (Logger : es) a -> Eff es a
|
||||||
runLoggerPSQL = interpret $ \_ -> \case
|
runLoggerPSQL = interpret $ \_ -> \case
|
||||||
WriteLog level msg ->
|
WriteLog level msg ->
|
||||||
databaseWrite
|
databaseWrite
|
||||||
("INSERT INTO logs (level, message) VALUES (?,?);", (level, msg))
|
("INSERT INTO logs (level, message) VALUES (?,?);", (level, msg))
|
||||||
|
|
||||||
{-
|
|
||||||
CREATE TABLE logs (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
level VARCHAR(10) NOT NULL,
|
|
||||||
message TEXT NOT NULL,
|
|
||||||
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
||||||
source VARCHAR(100),
|
|
||||||
context JSONB
|
|
||||||
);
|
|
||||||
-}
|
|
||||||
|
@ -42,6 +42,13 @@ runAppEff env = runEff
|
|||||||
. runDatabaseIO
|
. runDatabaseIO
|
||||||
. runLoggerPSQL
|
. runLoggerPSQL
|
||||||
|
|
||||||
|
runAppDebug :: AppEnv -> AppEff a -> IO (Either ServerError a)
|
||||||
|
runAppDebug env = runEff
|
||||||
|
. runErrorNoCallStack
|
||||||
|
. runReader env
|
||||||
|
. runDatabaseDebug
|
||||||
|
. runLoggerConsole
|
||||||
|
|
||||||
port :: Int
|
port :: Int
|
||||||
port = 8080
|
port = 8080
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user