在snaplet初始化过程中使用subsnaplet? [英] Use subsnaplet during snaplet initialization?
问题描述
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屋!