2012-03-30 16 views
8

Próbuję zrozumieć prostą konstrukcję snaplet. Ponadto, kiedy rzeczywiście trzeba zrobić snaplet i kiedy prosta biblioteka boczna? A jeśli potrzebuję jednego, jak mogę zrobić to z biblioteki?Haskell, Snap: Prosta konstrukcja z trzonkami. Kiedy używamy biblioteki Snaplet i biblioteki?

Na przykład mam garść funkcji DB, w których zawijam mój kod SQL, jak poniżej.

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 

Każda funkcja inicjuje nowe połączenie i zamyka połączenie po zatwierdzeniu. Zgaduję, że tworzenie snapletów jest sposobem na uniknięcie połączenia w każdej funkcji? W moim obsługi użyłbym go tak:

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 
      } 

To działa tak daleko. Moje pytanie (pytania) jest/są: Kiedy faktycznie muszę zmienić bibliotekę w snaplet? Czy muszę zamienić moją prostą bibliotekę DB w snaplet tylko po to, aby zainicjować połączenie zamiast nawiązywać połączenie w każdej funkcji?

Teraz, jeśli zrobię snaplet ... Na stronie Snap znajduje się maleńki przykład sanapletu najwyższego poziomu, ale nie ma żadnego śladu, jak zrobić prosty pluggap z własnym snapletem.

Więc dodałem snaplet funkcję inicjalizacji do mojej biblioteki DB

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

Czy to jest poprawny sposób to zrobić? Czy to wszystko, czego potrzebuję, aby przekształcić go w pluggapowy snaplet?

Potem stos ten DB snaplet do głównej aplikacji

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 

Teraz wszystko zyskam jest połączenie dostępne na moją prośbę koparki, prawda? Więc moja obsługi staje:

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 
      } 

nie wydają się działać. Co ja robię źle? Czy jest to właściwy sposób na wyodrębnienie połączenia z uchwytu Snaplet (dbcon)? Czy ogólnie rzecz biorąc jest to właściwy kierunek, aby skonstruować prosty snaplet? Czy w moim przypadku potrzebuję tu snapletu?

Dzięki.

Odpowiedz

3

Handler jest instancją MonadState: MonadState v (Handler b v).

Handler jest wystąpienie MonadSnaplet, a zatem zapewnia metodę with:
with :: Lens v (Snaplet v') -> m b v' a -> m b v a

dbcon jest Lens App (Snaplet Connection).

więc aby dostać się do Connection możemy wykorzystać:
conn <- with dbcon get

Normalnie będzie stworzyć snaplet jeśli były zapewniając funkcjonalność, że każdy może korzystać. W twoim przypadku najlepiej jest skorzystać z HDBC snaplet, którego możesz użyć do połączenia z sqlite3 db.

Zamówienie http://norm2782.github.com/snaplet-hdbc.html za dobry samouczek dotyczący korzystania z snaplet HDBC.

+1

Dziękuję. Widziałem snaplet HDBC i grałem z nim. Chcę to zrobić od zera, to jedyny sposób, żeby się uczyć. Najpierw próbowałem dowiedzieć się, jak korzystać z prostej biblioteki w moich programach obsługi, a teraz chcę się nauczyć, jak skonstruować snaplet oput tego. Chcę zrozumieć, jak buduje się prosty snaplet, w jaki sposób wchodzą w interakcje i dlaczego/kiedy potrzebuję ... –

+0

Czy możesz mi powiedzieć, czy jest to właściwy kierunek, by skonstruować snaplet? Czy dbInit jest wszystkim czego potrzebuję? –

+0

@ r.sendecky Jako bardzo prosty snaplet powiedziałbym, że jest w porządku. Jednak snaplety są zwykle używane do uruchamiania akcji z monady, którą stworzyłeś. W twoim przypadku działa, ponieważ po prostu używasz działań IO. Polecam analizować mightybytes [AcidState snaplet] (http://hackage.haskell.org/packages/archive/snaplet-acid-state/0.2/doc/html/src/Snap-Snaplet-AcidState.html#Acid). Jest to dobry przykład jak/dlaczego zbudować snaplet. – qubital