Sto cercando di capire la semplice costruzione di snaplet. Inoltre, quando devo effettivamente creare uno snaplet e una semplice libreria laterale? E se ne ho bisogno uno come faccio a uscire da una biblioteca?Haskell, Snap: semplice costruzione a scatto. Quando usiamo lo snaplet e quando la libreria?
Ad esempio, ho un sacco di funzioni DB in cui avvolgo il mio codice SQL come di seguito.
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
Ogni funzione avvia una nuova connessione e chiude la connessione dopo il commit. Immagino che creare uno snaplet sia il modo per evitare la connessione in ogni funzione? Nel mio gestore vorrei utilizzare in questo modo:
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
}
Funziona così lontano. Le mie domande sono/sono: Quando devo effettivamente trasformare una libreria in uno snaplet? Devo trasformare la mia libreria DB semplice in uno snaplet solo per inizializzare la connessione invece di effettuare la connessione in ogni funzione?
Ora, se si crea lo snaplet ... Sul sito Web di Snap vi è un piccolo esempio di un sanaplet di livello superiore ma non c'è traccia di come realizzare un semplice snaplet pluggble.
così ho aggiunto la funzione di inizio snaplet alla mia biblioteca DB
dbInit :: SnapletInit b Connection
dbInit = makeSnaplet "DB" "My DB Snaplet" Nothing $ do
dbc <- liftIO $ connectSqlite3 "/somepath/db.sqlite3"
onUnload $ disconnect dbc
return $ dbc
E 'questo il modo corretto di farlo? È tutto ciò di cui ho bisogno per trasformarlo in uno snaplet pluggble?
Poi ho impilare questo DB snaplet in app principale
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
Ora, tutto quello che guadagno è disponibile la connessione alla mia richiesta gestori, giusto? Quindi il mio gestore diventa:
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
}
Questo non sembra funzionare. Che cosa sto facendo di sbagliato? È questo il modo corretto per estrarre la connessione dall'impugnatura dello snaplet (dbcon)? Questa è generalmente la direzione corretta per costruire un semplice snaplet? Ho davvero bisogno di uno snaplet qui nel mio caso?
Grazie.
Grazie. Ho visto lo snaplet HDBC e ci ho giocato. Voglio farlo io stesso da zero, questo è l'unico modo per imparare per me. Per prima cosa ho cercato di capire come utilizzare una semplice libreria all'interno dei miei gestori e ora voglio imparare come costruirne uno snaplet oput. Voglio capire come viene costruito un semplice snaplet, come interagiscono e perché/quando ne ho bisogno ... –
Puoi dirmi se questa è la direzione corretta per costruire uno snaplet? Il dbInit è tutto ciò di cui ho bisogno? –
@ r.sendecky Come uno snaplet molto semplice, direi che va bene. Tuttavia gli snaplet sono normalmente usati per eseguire azioni da una monade che hai creato. Nel tuo caso funziona perché usi solo azioni IO. Raccomando di analizzare mightybytes [AcidState snaplet] (http://hackage.haskell.org/packages/archive/snaplet-acid-state/0.2/doc/html/src/Snap-Snaplet-AcidState.html#Acid). È un buon esempio di come/perché costruire uno snaplet. – qubital