2012-03-30 4 views
8

Ich versuche, einfache Snaplet-Konstruktion zu verstehen. Auch, wann muss ich eigentlich ein Snaplet machen und wenn eine einfache Seitenbibliothek? Und wenn ich brauche, wie mache ich es aus einer Bibliothek?Haskell, Snap: Einfache Snaplet-Konstruktion. Wann verwenden wir Snaplet und wann Bibliothek?

Zum Beispiel habe ich eine Reihe von DB-Funktionen, wo ich meinen SQL-Code wie folgt einpacken.

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 

Jede Funktion initiiert eine neue Verbindung und schließt die Verbindung nach dem Festschreiben. Ich denke, ein Snaplet ist die Möglichkeit, Verbindung in jeder Funktion zu vermeiden? In meinem Handler würde ich es wie folgt verwenden:

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 
      } 

Es bisher funktioniert. Meine Frage (n) ist/sind: Wann muss ich eigentlich eine Bibliothek in einen Snaplet verwandeln? Muss ich meine einfache DB-Bibliothek in einen Snaplet umwandeln, nur um die Verbindung zu initialisieren, anstatt die Verbindung in jeder Funktion herzustellen?

Jetzt, wenn ich die Snaplet ... Auf der Snap-Website gibt es ein winziges Beispiel für eine Top-Level-Sanaplet, aber es gibt keine Spur davon, wie Sie einfach Pluggble Snaplet Ihre eigenen machen.

So habe ich snaplet Initialisierungsfunktion meine DB-Bibliothek

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

Ist dies der richtige Weg, es zu tun? Ist das alles, was ich brauche, um es zu einem Pluggble Snaplet zu machen?

Dann stapeln ich diese DB snaplet in die Haupt App

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 

nun alles, was ich gewinnen die Verbindung zur Verfügung zu meinen Request-Handler ist, nicht wahr? Also mein Handler wird:

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 
      } 

Dies nicht zu funktionieren scheint. Was mache ich falsch? Ist dies der richtige Weg, um die Verbindung aus dem Snapleet-Handle (dbcon) zu extrahieren? Ist das in der Regel die richtige Richtung, um ein einfaches Snaplet zu konstruieren? Brauche ich in meinem Fall tatsächlich einen Snaplet?

Danke.

Antwort

3

Handler ist eine Instanz von MonadState: MonadState v (Handler b v).

Handler ist auch eine Instanz von MonadSnaplet und deshalb liefert die with Methode:
with :: Lens v (Snaplet v') -> m b v' a -> m b v a

dbcon ist ein Lens App (Snaplet Connection).

So zum Connection bekommen wir verwenden können:
conn <- with dbcon get

Sie würden eine snaplet normalerweise erstellen, wenn Sie die Funktionalität bereitstellt wurden, die jeder profitieren könnten. In Ihrem Fall ist es wahrscheinlich am besten, die HDBC snaplet zu nutzen, die Sie verwenden können, um eine Verbindung zu einer sqlite3 db herzustellen.

Checkout http://norm2782.github.com/snaplet-hdbc.html für ein gutes Tutorial zur Verwendung der HDBC Snaplet.

+1

Vielen Dank. Ich habe den HDBC Snaplet gesehen und ich habe damit gespielt. Ich möchte es von Grund auf selbst machen, das ist der einzige Weg, um für mich zu lernen. Zuerst habe ich versucht herauszufinden, wie ich eine einfache Bibliothek in meinen Handlern verwenden kann und nun möchte ich lernen, wie man eine Snaplet-Datei daraus erstellt. Ich möchte verstehen, wie ein einfacher Snaplet konstruiert wird, wie sie interagieren und warum/wann ich einen brauche ... –

+0

Kannst du mir sagen, ob das die richtige Richtung ist, um einen Snaplet zu konstruieren? Ist das dbInit alles was ich brauche? –

+0

@ r.sendecky Als ein sehr einfaches Snaplet würde ich sagen, dass es in Ordnung ist. Snapaps werden normalerweise verwendet, um Aktionen von einer Monade auszuführen, die Sie erstellt haben. In Ihrem Fall funktioniert es, weil Sie nur IO-Aktionen verwenden. Ich empfehle die Analyse von mightybytes [AcidState snaplet] (http://hackage.haskell.org/packages/archive/snaplet-acid-state/0.2/doc/html/src/Snap-Snaplet-AcidState.html#Acid). Es ist ein gutes Beispiel dafür, wie/warum man ein Snaplet konstruiert. – qubital