2

我有一些这样的 snaplet:

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

我希望dbCache从 postgresql 数据库中填写。似乎在 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

所以,问题是:如何pgs :: Snaplet PostgresInitializermonad 中使用从 db 读取数据?

4

1 回答 1

2

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

您不能HandlerInitializer. Initializer monad 的重点是设置运行 Web 服务器和 Handler monad 所需的初始状态数据类型。因此,在初始化程序中运行处理程序确实是不可能的——当然,除非你是从另一个 Web 服务器内部运行一个 Web 服务器...ick。

所以你有两个可能的选择。您可以HasPostgres为您的Initializer. 但这没有多大意义,除非您连接到静态服务器。如果您正在进行调试,这可能是可以接受的。有时我会为 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 backend中看到一个真实的例子。

更新:

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

于 2012-07-03T14:39:04.037 回答