2

次のようなスナップレットがあります。

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

dbCacheそして、postgresql データベースから入力したいと思います。スナップレットの初期化中にこれを行うのは自然なことのようです。

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 PostgresInitializerで db からデータを読み取るためにどのように使用することが可能ですか?

4

1 に答える 1

2

snaplet-postgresql-simple によって提供される DB アクセス関数は、HasPostgres型クラスのインスタンスである任意のモナドで実行されます。通常、これはHandlerアプリケーションのモナドになります。

Handler内で関数を使用することはできませんInitializer。Initializer モナドの要点は、Web サーバーと Handler モナドを実行するために必要な初期状態のデータ型を設定することです。したがって、イニシャライザー内でハンドラーを実行することは本当に不可能です-もちろん、あるWebサーバーを別のWebサーバー内から実行している場合を除きます...いや。

したがって、2 つの選択肢があります。HasPostgresのインスタンスを作成できますInitializer。ただし、静的サーバーに接続していない限り、それはあまり意味がありません。デバッグを行っている場合、これは許容される場合があります。IO がデータベース機能を簡単にテストできるようにするために、時々これを行います。

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

しかし、一般に、実稼働コードで使用するためにこのようなインスタンスを作成することは意味がありません。これは、データベースにアクセスする場合Initializer、snaplet-postgresql-simple によって提供されるラッパーではなく、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で、この実際のライブの例を見ることができます。

アップデート:

ReaderT の HasPostgres インスタンスを提供する新しいバージョンの snaplet-postgresql-simple を hackage にアップロードしました。これにより、runReaderT を使用してこれをより簡単に実現できます。ドキュメントには、これの小さなコード スニペットがあります。

于 2012-07-03T14:39:04.037 に答える