在小快照初始化期间使用子快照



我有一些这样的小鲷鱼:

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

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

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

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

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

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

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

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

但一般来说,制作这样的实例用于生产代码是没有意义的。 这意味着,如果你想在Initializer中访问数据库,你必须直接使用 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后端中看到一个真实的例子。

更新:

我刚刚上传了一个新版本的snaplet-postgresql-simple到hackage,它为ReaderT提供了一个HasPostgres实例。 这使您可以使用runReaderT更轻松地完成此操作。 文档中有一个小的代码片段。

最新更新