haskell - 在 snaplet 初始化期间使用 subsnaplet?

标签 haskell haskell-snap-framework

我有一些像这样的 snaplet:

data DB b = DB
  {_pgsql :: Snaplet Postgresql
  ,dbCache :: Map Text Text
  }

我希望从 postgresql 数据库填充dbCache。似乎在 snaplet 初始化期间执行此操作是很自然的。

initDB :: SnapletInit b (DB b)
initDB = makeSnaplet "db" "cached database" Nothing $ do
  pgs <- nestSnaplet "pgsql" pgsql pgsInit
  cache <- getSomeDataPlease pgs 
  return $ DB pgs cache

所以,问题是:如何在 Initializer monad 中使用 pgs::Snaplet Postgres 从数据库读取数据?

最佳答案

snaplet-postgresql-simple 提供的数据库访问函数可以在作为 HasPostgres 类型类的实例的任何 monad 中运行。通常,这将是您的应用程序的 Handler monad。

您不能在Initializer 中使用Handler 函数。 Initializer monad 的全部要点是设置运行 Web 服务器和 Handler monad 所需的初始状态数据类型。因此,在初始值设定项内运行处理程序确实是不可能的——当然,除非您从另一个 Web 服务器内部运行一个 Web 服务器……哎呀。

所以你有两个可能的选择。您可以为您的Initializer 创建一个HasPostgres 实例。但除非您连接到静态服务器,否则这没有多大意义。如果您正在进行调试,这可能是可以接受的。有时我会为 IO 执行此操作,以便轻松测试我的数据库功能:

instance HasPostgres IO where
    getPostgresState = do
        pool <- createPool (connect $ ConnectInfo "127.0.0.1" ...) ...
        return $ Postgres pool

但一般来说,制作这样的实例用于生产代码是没有意义的。这意味着,如果您想在初始化程序中访问数据库,则必须直接使用 postgresql-simple 函数,而不是 snaplet-postgresql-simple 提供的包装器。这就是我导出 pgPool 访问器函数的原因。它看起来像这样:

initDB :: SnapletInit b (DB b)
initDB = makeSnaplet "db" "cached database" Nothing $ do
    pgs <- nestSnaplet "pgsql" pgsql pgsInit
    let pool = pgPool $ extract pgs
    results <- liftIO $ withResource pool (\conn -> query_ conn myQuery)

您可以在 snaplet-postgresql-simple 的 auth backend 中看到一个真实的例子。 .

更新:

我刚刚将新版本的 snaplet-postgresql-simple 上传到 hackage,它提供了 HasPostgres instance for ReaderT 。这使您可以使用 runReaderT 更简单地完成此任务。文档中有一小段代码。

关于haskell - 在 snaplet 初始化期间使用 subsnaplet?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11308326/

相关文章:

macos - 在 Mac 上安装 Haskell 软件包

haskell - 快照教程和建议

haskell - 部署使用 Snap 框架的 Haskell 代码

haskell - 了解 Haskell 类型签名

haskell - Haskell 中 type 和 newtype 的区别

haskell - 为什么使用具有重叠实例的类型类的此函数在 GHCi 中表现不同?

haskell - 如何通过内容确定文件的 MIME 类型?

haskell - Monad 理论和 Haskell

haskell - Snap Monad、LiftIO 和 ghc 7.4.1

haskell - 如何在 snaplet 中使用 Network.WebSockets.Snap?