使用 Persistent 输入与数据库的关系

Entering relations to database using Persistent

从 Haskell 和 Yesod 开始,Yesod 相对于 Haskell 可能有点过头了:)

我通过

使用 Persistent 构建实体
share [mkPersist sqlSettings, mkMigrate "migrateAll"][persistLowerCase|
Game
  title String
  company String
  UniqueTitle title
  deriving Show
Tag
  label String
  description String Maybe
  UniqueLabel label
  deriving Show
GameTag
  gameId GameId
  tagId TagId
  UniqueGameTag gameId tagId
|]

-- Yesod related code ...

主要我有

main :: IO ()
main = do
let taggings = fromFile :: [(Game, Tag)] -- fromFile code not included
runStderrLoggingT $ withSqlitePool ":inmemory:" 10 $ λpool →  liftIO $ do
runResourceT $ flip runSqlPool pool $ do
  runMigration migrateAll
  let (g, t) = head taggings
  gid ←  insert g
  tid ←  insert t
  insert (GameTag gid tid)
warp 3000 $ App pool

这样做我得到了数据库中的第一个关系,通过从列表中选择元素我可以添加更多 'by hand',但我不知道如何将所有关系放入数据库中以某种方式迭代 taggings。我如何定义一个函数,我可以映射到 taggings ::[(Game, Tag)] 并插入类型为 GameTag 的游戏标签 通过坚持不懈?

这里的主要技巧不是提取函数,这很简单:

f (g, t) = do
  gid <- insert g
  tid <- insert t
  insert (GameTag gid tid)

诀窍是知道如何使用它....标准 map 不会单独工作,因为函数是在 monad 中定义的(你可以使用它,它只会给你一个列表没有 运行ning 的动作返回)。

map f taggings -- returns just a list, type [ResourceT IO a], doesn't run anything

这里有两种方法可以实际 运行 main 中的操作。

sequence (map f taggings) --sequentially runs the actions in the list

或者,更具可读性

forM taggings f

或者,在稍微冗长的

forM taggings $ \tagging -> do
  f tagging

您可能还想看看 mapM。还应该了解 forM_sequence_ 来抑制(通常无用的)return 值。