使用 PostGreSQL 和 Persistent 将条目插入数据库
Inserting entry into database using PostGreSQL & Persistent
我正在尝试学习持久库。
我有两个文件,其中一个包含我为我的项目(饮食追踪器)定义的所有类型
Report.hs
data FoodEntry = FoodEntry { report :: Report
, date :: UTCTime
}
data Report = Report { ...
...
}
和另一个用于生成表格的文件
Storage.hs
import Database.Persist.Sql
import qualified Database.Persist.TH as PTH
PTH.share [ PTH.mkPersist PTH.sqlSettings
, PTH.mkMigrate "migrateAll"
]
[PTH.persistLowerCase|
FoodEntry sql=entries
report Report
date UTCTime default=now()
UniqueDate date
Report sql=reports
name Text
reportingUnit Text
nutrients [Nutrient]
Nutrient sql=nutrients
nutrientName Text
nutrientUnit Text
nutrientValue Double Maybe
deriving Show Read
|]
和处理迁移的文件
import Control.Monad.Logger
import Database.Persist
import Database.Persist.Postgresql
import Types.Storage
connString :: ConnectionString
connString = "host=127.0.0.1 port=5432 user=postgres dbname=postgres password=password"
runAction
:: (MonadUnliftIO m, IsPersistBackend r,
BaseBackend r ~ SqlBackend) =>
ConnectionString -> ReaderT r (LoggingT m) a -> m a
runAction connectionString action = runStdoutLoggingT
$ withPostgresqlConn connectionString
$ \backend ->
runReaderT action backend
migrateDB :: IO ()
migrateDB = runAction connString (runMigration migrateAll)
在我的 [ProjectName.hs]
文件中 main
调用
args <- parseArgs -- args - optparse-applicative
if generateDB args == Just True
then migrateDB
else case (...) of
... -> ...
... -> ...
(s, n, p, Just True) -> undefined
对于最后一种情况,我想将用户条目添加到数据库中。
我还有一个函数 searchReport
,它使用 s
、n
& p
到 returns 一个 Report
类型。
我想做这样的事情
insertReport :: (MonadIO m) => UTCTime -> Report -> SqlPersistT m (Key FoodEntry)
insertReport time report' = insert (FoodEntry report' time)
do date' <- Data.Time.Clock.getCurrentTime :: IO UTCTime
report' <- searchReport s n p :: IO Report
insertReport $ date' report'
但是(据我所知)这有两个问题
Report.FoodEntry
的类型与类型不匹配
Storage.FoodEntry
我可以编写一个函数将一个转换为
另一个,但我想知道是否有更好的方法。
如果我要像这样测试 do 块中的函数
(s, n, p, Just True) -> insertReport undefined undefined
我收到错误
• Couldn't match type ‘ReaderT
Database.Persist.Sql.Types.Internal.SqlBackend m0’
with ‘IO’
Expected type: IO ()
Actual type: persistent-2.9.2:Database.Persist.Sql.Types.SqlPersistT
m0
(persistent-2.9.2:Database.Persist.Class.PersistEntity.Key
Types.Storage.FoodEntry)
从 IO
monad 到 运行 insertReport
你必须调用 runAction connectionString insertReport
。这实际上是将 SqlPersistT
转换为 IO
.
至于 Report.FoodEntry
和 Storage.FoodEntry
之间的区别 - 为什么首先要有两种数据类型?您在 PTH.share
quasiquoter 中声明的实体也是一个有效的 Haskell 数据类型,因此您可以像使用任何其他数据类型一样使用它。
但是,如果您真的需要 2 个不同的 FoodEntry
es,那么是的,您需要编写一个函数在它们之间进行转换。
我正在尝试学习持久库。
我有两个文件,其中一个包含我为我的项目(饮食追踪器)定义的所有类型
Report.hs
data FoodEntry = FoodEntry { report :: Report
, date :: UTCTime
}
data Report = Report { ...
...
}
和另一个用于生成表格的文件
Storage.hs
import Database.Persist.Sql
import qualified Database.Persist.TH as PTH
PTH.share [ PTH.mkPersist PTH.sqlSettings
, PTH.mkMigrate "migrateAll"
]
[PTH.persistLowerCase|
FoodEntry sql=entries
report Report
date UTCTime default=now()
UniqueDate date
Report sql=reports
name Text
reportingUnit Text
nutrients [Nutrient]
Nutrient sql=nutrients
nutrientName Text
nutrientUnit Text
nutrientValue Double Maybe
deriving Show Read
|]
和处理迁移的文件
import Control.Monad.Logger
import Database.Persist
import Database.Persist.Postgresql
import Types.Storage
connString :: ConnectionString
connString = "host=127.0.0.1 port=5432 user=postgres dbname=postgres password=password"
runAction
:: (MonadUnliftIO m, IsPersistBackend r,
BaseBackend r ~ SqlBackend) =>
ConnectionString -> ReaderT r (LoggingT m) a -> m a
runAction connectionString action = runStdoutLoggingT
$ withPostgresqlConn connectionString
$ \backend ->
runReaderT action backend
migrateDB :: IO ()
migrateDB = runAction connString (runMigration migrateAll)
在我的 [ProjectName.hs]
文件中 main
调用
args <- parseArgs -- args - optparse-applicative
if generateDB args == Just True
then migrateDB
else case (...) of
... -> ...
... -> ...
(s, n, p, Just True) -> undefined
对于最后一种情况,我想将用户条目添加到数据库中。
我还有一个函数 searchReport
,它使用 s
、n
& p
到 returns 一个 Report
类型。
我想做这样的事情
insertReport :: (MonadIO m) => UTCTime -> Report -> SqlPersistT m (Key FoodEntry)
insertReport time report' = insert (FoodEntry report' time)
do date' <- Data.Time.Clock.getCurrentTime :: IO UTCTime
report' <- searchReport s n p :: IO Report
insertReport $ date' report'
但是(据我所知)这有两个问题
Report.FoodEntry
的类型与类型不匹配Storage.FoodEntry
我可以编写一个函数将一个转换为 另一个,但我想知道是否有更好的方法。如果我要像这样测试 do 块中的函数
(s, n, p, Just True) -> insertReport undefined undefined
我收到错误
• Couldn't match type ‘ReaderT Database.Persist.Sql.Types.Internal.SqlBackend m0’ with ‘IO’ Expected type: IO () Actual type: persistent-2.9.2:Database.Persist.Sql.Types.SqlPersistT m0 (persistent-2.9.2:Database.Persist.Class.PersistEntity.Key Types.Storage.FoodEntry)
从 IO
monad 到 运行 insertReport
你必须调用 runAction connectionString insertReport
。这实际上是将 SqlPersistT
转换为 IO
.
至于 Report.FoodEntry
和 Storage.FoodEntry
之间的区别 - 为什么首先要有两种数据类型?您在 PTH.share
quasiquoter 中声明的实体也是一个有效的 Haskell 数据类型,因此您可以像使用任何其他数据类型一样使用它。
但是,如果您真的需要 2 个不同的 FoodEntry
es,那么是的,您需要编写一个函数在它们之间进行转换。