2012-03-30 11 views
8

Estoy tratando de entender la construcción simple de snaplet. Además, ¿cuándo realmente necesito hacer una instantánea y cuándo una biblioteca auxiliar simple? Y si lo necesito, ¿cómo puedo salir de una biblioteca?Haskell, Ajustar: construcción sencilla snaplet. ¿Cuándo usamos snaplet y cuándo biblioteca?

Por ejemplo, tengo un montón de funciones de base de datos donde envuelvo mi código SQL como a continuación.

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 

Cada función inicia una nueva conexión y cierra la conexión después de la confirmación. Supongo que hacer un snaplet es la forma de evitar la conexión en todas las funciones. En mi manejador lo usaría como esto:

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 
      } 

Funciona hasta ahora. Mi pregunta (s) es/are: ¿Cuándo realmente necesito convertir una biblioteca en una instantánea? ¿Debo convertir mi simple biblioteca de bases de datos en una instantánea solo para inicializar la conexión en lugar de hacer la conexión en todas las funciones?

Ahora, si hago el snaplet ... En el sitio web de Snap hay un pequeño ejemplo de un sangrado de nivel superior pero no hay ningún rastro de cómo hacer un snaplet de pluggble propio.

por lo que añade la función de inicialización snaplet a mi 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 

Es esta la forma correcta de hacerlo? ¿Es esto todo lo que necesito para convertirlo en un snaplet pluggble?

Entonces Stack snaplet DB en la aplicación principal

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 

Ahora, todo lo que gano es la conexión disponible a mis controladores de solicitudes, ¿verdad? Así que mi controlador se convierte en:

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 
      } 

Esto no parece funcionar. ¿Qué estoy haciendo mal? ¿Es esta la forma correcta de extraer la conexión del controlador de snaplet (dbcon)? ¿Esta es, en general, la dirección correcta para construir un simple snaplet? ¿Realmente necesito un snaplet aquí en mi caso?

Gracias.

Respuesta

3

es una instancia de MonadState: MonadState v (Handler b v).

Handler es también una instancia de MonadSnaplet y por lo tanto proporciona la with método:
with :: Lens v (Snaplet v') -> m b v' a -> m b v a

dbcon es una Lens App (Snaplet Connection).

Así que para llegar a la Connection podemos utilizar:
conn <- with dbcon get

Que normalmente crear un snaplet si se proporciona una funcionalidad que todo el mundo podría beneficiarse. En su caso, probablemente sea mejor aprovechar el HDBC snaplet, que puede usar para conectarse a un sqlite3 db.

Consulte http://norm2782.github.com/snaplet-hdbc.html para obtener un buen tutorial sobre el uso de la snake de HDBC.

+1

Gracias. He visto el snaplet de HDBC y he jugado con él. Quiero hacerlo desde cero, esta es la única forma de aprender para mí. Primero traté de encontrar la forma de usar una biblioteca simple dentro de mis manejadores y ahora quiero aprender cómo construir una opción de snaplet. Quiero entender cómo se construye un simple snaplet, cómo interactúan y por qué/cuándo necesito uno ... –

+0

¿Puede decirme si esta es la dirección correcta para construir un snaplet? ¿Es el dbInit todo lo que necesito? –

+0

@ r.sendecky Como un snaplet muy simple, diría que está bien. Sin embargo, los snaplets normalmente se utilizan para ejecutar acciones desde una mónada que ha creado. En tu caso, funciona porque solo usas acciones IO. Recomiendo analizar mightybytes [AcidState snaplet] (http://hackage.haskell.org/packages/archive/snaplet-acid-state/0.2/doc/html/src/Snap-Snaplet-AcidState.html#Acid). Es un buen ejemplo de cómo/por qué construir un snaplet. – qubital

Cuestiones relacionadas