我正在尝试学习持久性库。
我有两个文件,其中一个具有为项目定义的所有类型(饮食跟踪器)
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
返回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'
但是(AFAIK)有两个问题
Report.FoodEntry
的类型与该类型不匹配
Storage.FoodEntry
我可以编写一个函数,将其转换为
另一个,但我想知道是否还有更好的方法。
如果我要像这样测试该功能块
(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)
答案 0 :(得分:1)
要从insertReport
monad运行IO
,您必须调用runAction connectionString insertReport
。这实际上就是将SqlPersistT
转换为IO
的原因。
对于Report.FoodEntry
和Storage.FoodEntry
之间的区别-为什么您首先要使用两种数据类型?您在PTH.share
准引用中声明的实体也是有效的Haskell数据类型,因此您可以像其他任何类型一样使用它。
但是,如果您确实需要两个不同的FoodEntry
,那么可以,您需要编写一个在它们之间转换的函数。