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.
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ę ... –
Czy możesz mi powiedzieć, czy jest to właściwy kierunek, by skonstruować snaplet? Czy dbInit jest wszystkim czego potrzebuję? –
@ 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