9

シンプルなスナップレットの構造を理解しようとしています。また、実際にスナップレットを作成する必要があるのはいつですか?また、単純なサイド ライブラリはいつ作成する必要がありますか? また、ライブラリが必要な場合は、どうすればライブラリから作成できますか?

たとえば、以下のように SQL コードをラップする一連の DB 関数があります。

data Person = Person {personName :: ByteString, personAge :: Int}

connect :: IO Connection
connect = connectSqlite3 "/somepath/db.sqlite3"

savePerson :: Person -> IO ()
savePerson p = do
c <- connect
run c "INSERT INTO persons (name, age) \
      \VALUES (?, ?)"
      [toSql (personName p), toSql (personAge p)]
commit c
disconnect c

すべての関数は新しい接続を開始し、コミット後に接続を閉じます。スナップレットを作成することは、すべての機能で接続を回避する方法だと思いますか? 私のハンドラーでは、次のように使用します。

insertPerson :: Handler App App ()
insertPerson = do
  par <- getPostParams
  let p = top par
  liftIO $ savePerson p
where
  top m =
    Person {personName = head (m ! (B.pack "name"))
           ,personAge  = read (B.unpack (head (m ! (B.pack "age")))) :: Int
           }

これまでのところ動作します。私の質問は次のとおりです。実際にライブラリをスナップレットに変更する必要があるのはいつですか? すべての関数で接続を確立するのではなく、接続を初期化するためだけに、単純な DB ライブラリをスナップレットに変換する必要がありますか?

さて、スナップレットを作成すると... Snap の Web サイトには、トップレベルのサナプレットの小さな例がありますが、独自の単純なプラグブル スナップレットを作成する方法の痕跡はありません。

そこで、スナップレットの初期化関数を DB ライブラリに追加しました

dbInit :: SnapletInit b Connection
dbInit = makeSnaplet "DB" "My DB Snaplet" Nothing $ do
  dbc <- liftIO $ connectSqlite3 "/somepath/db.sqlite3"
  onUnload $ disconnect dbc
  return $ dbc

これは正しい方法ですか?プラグ可能なスナップレットに変換するために必要なのはこれだけですか?

次に、この DB スナップレットをメイン アプリにスタックします。

data App = App
  { _heist :: Snaplet (Heist App),
    _dbcon :: Snaplet (Connection)
  }

makeLens ''App

app :: SnapletInit App App
app = makeSnaplet "app" "My app" Nothing $ do
  h <- nestSnaplet "heist" heist $ heistInit "templates"
  d <- nestSnaplet "" dbcon dbInit
  addRoutes routes
  return $ App h d

これで、取得できるのは、リクエスト ハンドラーが利用できる接続だけですよね? したがって、私のハンドラーは次のようになります。

insertPerson :: Handler App App ()
insertPerson = do
  par <- getPostParams
  let person = top par
  connection <- gets _dbcon
  liftIO $ savePerson connection person
where
  top m =
    Person {personName = head (m ! (B.pack "name"))
           ,personAge  = read (B.unpack (head (m ! (B.pack "age")))) :: Int
           }

これはうまくいかないようです。私は何を間違っていますか?これは、スナップレット ハンドル (dbcon) から接続を抽出する正しい方法ですか? これは一般的に、単純なスナップレットを作成する正しい方向ですか? 私の場合、ここで実際にスナップレットが必要ですか?

ありがとう。

4

1 に答える 1

4

Handler:のインスタンスMonadStateですMonadState v (Handler b v)

Handlerのインスタンスでもあるため、次のメソッドMonadSnapletを提供します。with
with :: Lens v (Snaplet v') -> m b v' a -> m b v a

dbconですLens App (Snaplet Connection)

したがって、に到達するには、Connection次を使用できます。
conn <- with dbcon get

誰もが恩恵を受ける可能性のある機能を提供する場合は、通常、スナップレットを作成します。あなたの場合、sqlite3 db に接続するために使用できる HDBC snapletを利用するのがおそらく最善です。

HDBC スナップレットの使用に関する優れたチュートリアルについては、http://norm2782.github.com/snaplet-hdbc.html を参照してください

于 2012-03-30T04:06:06.797 に答える