hhe*_*sto 3 database haskell persistent yesod
这是我第二次尝试学习Haskell,而我一直听到的一件事就是不要重复自己(其他语言也是如此).
无论如何......我正在尝试实现一个博客并发现需要在数据库上实现CRUD操作,但是当我为评论,帖子和用户实现CRUD时,在我看来,我只是在重复自己.
问题是我看不出怎么不重复自己.
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Model where
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Logger (runStderrLoggingT)
import Database.Persist
import Database.Persist.Postgresql
import Database.Persist.TH
import Data.Time
import Data.Int
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Users
email String
password String
alias String
image_url String
show_email Bool
UniqueEmail email
date UTCTime default=CURRENT_TIMESTAMP
deriving Show
Post
atom Int
material String
processing String
params String
image_url String
reference String
owner UsersId
material_url String
date UTCTime default=CURRENT_TIMESTAMP
deriving Show
Comment
owner UsersId
post PostId
date UTCTime default=CURRENT_TIMESTAMP
text String
deriving Show
|]
connStr = "host=localhost dbname=communis-db user=communis password=facilderecordar789 port=5432"
--User CRUD
get_user :: Int64 -> IO(Maybe Users)
get_user i = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
get (toSqlKey i :: UsersId)
new_user :: Users -> IO ()
new_user(Users email pass alias image_url show_email _) = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
now <- liftIO getCurrentTime
usrid <- insert $ Users email pass alias image_url show_email now
usr <- get usrid
liftIO $ print usr
update_user :: String -> Users -> IO()
update_user em u = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
usr <- getBy $ UniqueEmail em
case usr of
Just (Entity userId user) -> replace userId user
delete_user :: Int64 -> IO ()
delete_user i = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
delete (toSqlKey i :: UsersId)
--Post CRUD
get_post :: Int64 -> IO(Maybe Post)
get_post i = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
get (toSqlKey i :: PostId)
new_post :: Post -> IO ()
new_post (Post atom material processing params image_url reference owner material_url _) = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
now <- liftIO getCurrentTime
postId <- insert $ Post atom material processing params image_url reference owner material_url now
post <- get postId
liftIO $ print post
update_post :: Int64 -> Post -> IO()
update_post id post = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
replace (toSqlKey id) post
delete_post :: Int64 -> IO ()
delete_post i = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
delete (toSqlKey i :: PostId)
-- Comments CRUD
get_comment :: Int64 -> IO(Maybe Comment)
get_comment i = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
get (toSqlKey i :: CommentId)
new_comment :: Comment -> IO ()
new_comment (Comment owner post _ text) = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
now <- liftIO getCurrentTime
commentId <- insert $ Comment owner post now text
comment <- get commentId
liftIO $ print comment
update_comment :: Int64 -> Comment -> IO()
update_comment id comment = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
replace (toSqlKey id) comment
delete_comment :: Int64 -> IO ()
delete_comment i = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
delete (toSqlKey i :: CommentId)
Run Code Online (Sandbox Code Playgroud)
ps堆栈规则.
首先,要认识到你正在重复的是什么.在这里
runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
<some-action>
Run Code Online (Sandbox Code Playgroud)
解决方案就是将其抽象出来,创建一个允许您指定的函数some-action:
inBackend :: ReaderT SqlBackend (NoLoggingT (ResourceT IO)) a-> IO a
inBackend action = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
action
Run Code Online (Sandbox Code Playgroud)
然后你的CRUD代码变得更干净和DRYer:
--User CRUD
get_user :: Int64 -> IO (Maybe User)
get_user = inBackend . get . toUserId
new_user :: User -> IO ()
new_user (User email pass alias image_url show_email _) = inBackend $ do
now <- liftIO getCurrentTime
usrid <- insert $ User email pass alias image_url show_email now
usr <- get usrid
liftIO $ print usr
update_user :: String -> User -> IO()
update_user em user = inBackend $ do
Just (Entity userId _) <- getBy $ UniqueEmail em
replace userId user
delete_user :: Int64 -> IO ()
delete_user = inBackend . delete . toUserId
--Post CRUD
get_post :: Int64 -> IO(Maybe Post)
get_post = inBackend . get . toPostId
new_post :: Post -> IO ()
new_post (Post atom material processing params image_url reference owner material_url _) = inBackend $ do
now <- liftIO getCurrentTime
postId <- insert $ Post atom material processing params image_url reference owner material_url now
post <- get postId
liftIO $ print post
update_post :: Int64 -> Post -> IO()
update_post id post = inBackend $ replace (toPostId id) post
delete_post :: Int64 -> IO ()
delete_post = inBackend . delete . toPostId
-- Comments CRUD
get_comment :: Int64 -> IO(Maybe Comment)
get_comment = inBackend . get . toCommentId
new_comment :: Comment -> IO ()
new_comment (Comment owner post _ text) = inBackend $ do
now <- liftIO getCurrentTime
commentId <- insert $ Comment owner post now text
comment <- get commentId
liftIO $ print comment
update_comment :: Int64 -> Comment -> IO()
update_comment id comment = inBackend $ replace (toCommentId id) comment
delete_comment :: Int64 -> IO ()
delete_comment = inBackend . delete . toCommentId
Run Code Online (Sandbox Code Playgroud)
为了完整性:
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Model where
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Logger (runStderrLoggingT, NoLoggingT)
import Control.Monad.Trans.Reader (ReaderT)
import Control.Monad.Trans.Resource (ResourceT)
import Database.Persist
import Database.Persist.Postgresql
import Database.Persist.TH
import Data.Time
import Data.Int
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
User
email String
password String
alias String
image_url String
show_email Bool
UniqueEmail email
date UTCTime default=CURRENT_TIMESTAMP
deriving Show
Post
atom Int
material String
processing String
params String
image_url String
reference String
owner UserId
material_url String
date UTCTime default=CURRENT_TIMESTAMP
deriving Show
Comment
owner UserId
post PostId
date UTCTime default=CURRENT_TIMESTAMP
text String
deriving Show
|]
connStr = "host=localhost dbname=communis-db user=communis password=facilderecordar789 port=5432"
-- this is the repeated code that can be factored out
inBackend :: ReaderT SqlBackend (NoLoggingT (ResourceT IO)) a-> IO a
inBackend action = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
flip runSqlPersistMPool pool $ do
runMigration migrateAll
action
-- I prefer this to (toSqlKey :: ...), but YMMV
toUserId :: Int64 -> UserId
toUserId = toSqlKey
toPostId :: Int64 -> PostId
toPostId = toSqlKey
toCommentId :: Int64 -> CommentId
toCommentId = toSqlKey
--User CRUD
get_user :: Int64 -> IO (Maybe User)
get_user = inBackend . get . toUserId
new_user :: User -> IO ()
new_user (User email pass alias image_url show_email _) = inBackend $ do
now <- liftIO getCurrentTime
usrid <- insert $ User email pass alias image_url show_email now
usr <- get usrid
liftIO $ print usr
update_user :: String -> User -> IO()
update_user em user = inBackend $ do
Just (Entity userId _) <- getBy $ UniqueEmail em
replace userId user
delete_user :: Int64 -> IO ()
delete_user = inBackend . delete . toUserId
--Post CRUD
get_post :: Int64 -> IO(Maybe Post)
get_post = inBackend . get . toPostId
new_post :: Post -> IO ()
new_post (Post atom material processing params image_url reference owner material_url _) = inBackend $ do
now <- liftIO getCurrentTime
postId <- insert $ Post atom material processing params image_url reference owner material_url now
post <- get postId
liftIO $ print post
update_post :: Int64 -> Post -> IO()
update_post id post = inBackend $ replace (toPostId id) post
delete_post :: Int64 -> IO ()
delete_post = inBackend . delete . toPostId
-- Comments CRUD
get_comment :: Int64 -> IO(Maybe Comment)
get_comment = inBackend . get . toCommentId
new_comment :: Comment -> IO ()
new_comment (Comment owner post _ text) = inBackend $ do
now <- liftIO getCurrentTime
commentId <- insert $ Comment owner post now text
comment <- get commentId
liftIO $ print comment
update_comment :: Int64 -> Comment -> IO()
update_comment id comment = inBackend $ replace (toCommentId id) comment
delete_comment :: Int64 -> IO ()
delete_comment = inBackend . delete . toCommentId
Run Code Online (Sandbox Code Playgroud)