在snaplet初始化过程中使用subsnaplet? [英] Use subsnaplet during snaplet initialization?

查看:157
本文介绍了在snaplet初始化过程中使用subsnaplet?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我想填写 dbCache 来自postgresql数据库。看起来在snaplet初始化过程中这样做是很自然的。

  initDB :: SnapletInit b(DB b)
initDB = makeSnaplet DB 缓存的数据库 没什么$做
PGS< - nestSnaplet 的pgsql 的pgsql pgsInit
缓存< - getSomeDataPlease PGS
返回$ DB PGS缓存

所以问题是:如何使用 pgs :: Snaplet Postgres 初始化程序中 monad从db读取数据?

解决方案

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



您不能使用 Handler 函数在初始化程序中。初始化程序monad的全部要点是设置运行Web服务器和Handler monad所需的初始状态数据类型。因此,在初始化程序中运行处理程序是不可能的 - 除非你从另一个web服务器中运行一个web服务器...... ick。

所以你有两种可能的选择。你可以为你的 Initializer 创建一个 HasPostgres 实例。但是,除非你连接到静态服务器,否则这没有什么意义。如果您正在进行调试,这可能是可以接受的。有时候我会为IO做这件事,以便测试我的数据库函数:

  instance HasPostgres IO where 
getPostgresState = do
pool< - createPool(connect $ ConnectInfo127.0.0.1...)...
return $ Postgres pool

但是通常在生产代码中使用这样的实例是没有意义的。这意味着如果你想访问 Initializer 中的数据库,你必须直接使用postgresql-simple函数,而不是snaplet-postgresql-simple提供的包装器。这就是我导出pgPool访问器函数的原因。它看起来像这样:

pre $ init $ db $ b $ initDB = makeSnapletdb 高速缓存数据库 没什么$做
PGS< - nestSnaplet pgsql的 pgsql的pgsInit
设池= pgPool $提取PGS
。结果与LT; - liftIO $ withResource池(\conn - > ; query_conn myQuery)

你可以在snaplet-postgresql-simple的< A HREF = https://github.com/mightybyte/snaplet-postgresql-simple/blob/master/src/Snap/Snaplet/Auth/Backends/PostgresqlSimple.hs#L79 相对= nofollow> AUTH后端。

更新:

我刚刚上传了一个新版本的snaplet-postgresql-simple来骇客提供了一种 ReaderT的HasPostgres实例。这使您可以使用runReaderT更简单地完成此操作。在文档中有一小段代码片段。


I have some snaplet like this:

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

And I wish to fill dbCache from postgresql database. Seems that it is natural to do this during snaplet initialization.

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

So, the question is: How is it possible to use pgs :: Snaplet Postgres within Initializer monad to read data from db?

解决方案

The DB access functions provided by snaplet-postgresql-simple run in any monad that is an instance of the HasPostgres type class. Typically, this will be the Handler monad for your application.

You can't use Handler functions inside an Initializer. The whole point of the Initializer monad is to set up the initial state data type that is needed to run the web server and the Handler monad. So it's truly impossible to run handlers inside an initializer--unless of course you're running one web server from inside another web server...ick.

So you have two possible options. You could create a HasPostgres instance for your Initializer. But that doesn't make much sense unless you're connecting to a static server. This might be acceptable if you're doing debugging. Sometimes I'll do that for IO to make it trivial to test my database functions:

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

But in general it won't make sense to make an instance like this for use in production code. This means that if you want to access the database in an Initializer you have to use the postgresql-simple functions directly rather than the wrappers provided by snaplet-postgresql-simple. That's why I exported the pgPool accessor function. It will look something like this:

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)

You can see a real live example of this in snaplet-postgresql-simple's auth backend.

Update:

I just uploaded a new version of snaplet-postgresql-simple to hackage that provides a HasPostgres instance for ReaderT. This allows you to accomplish this more simply with runReaderT. There's a small code snippet of this in the documentation.

这篇关于在snaplet初始化过程中使用subsnaplet?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆