Haskell, Snap: простая конструкция Snaplet. Когда мы используем snaplet и когда библиотеку?

Я пытаюсь понять простую конструкцию моментального снимка. Кроме того, когда мне действительно нужно сделать снаплет, а когда простую стороннюю библиотеку? И если мне это нужно, как мне сделать это из библиотеки?

Например, у меня есть несколько функций БД, в которые я оборачиваю код SQL, как показано ниже.

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

Каждая функция инициирует новое соединение и закрывает соединение после фиксации. Я предполагаю, что создание снимка - это способ избежать соединения в каждой функции? В своем обработчике я бы использовал это так:

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
           }

Пока работает. Мой вопрос (ы): Когда мне на самом деле нужно превратить библиотеку в снаплет? Нужно ли мне превращать мою простую библиотеку БД в снаплет только для инициализации соединения вместо того, чтобы устанавливать соединение в каждой функции?

Теперь, если я сделаю снимок... На веб-сайте Snap есть крошечный пример санаплета верхнего уровня, но нет и следа того, как сделать простой подключаемый снаплет самостоятельно.

Итак, я добавил функцию инициализации Snaplet в свою библиотеку БД

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

Это правильный способ сделать это? Это все, что мне нужно, чтобы превратить его в pluggble snaplet?

Затем я помещаю этот снимок базы данных в главное приложение.

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

Теперь все, что я получаю, — это соединение, доступное для моих обработчиков запросов, верно? Итак, мой обработчик принимает вид:

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
           }

Похоже, это не работает.Что я делаю неправильно? Это правильный способ извлечения соединения из дескриптора снимка (dbcon)? Является ли это правильным направлением для создания простого снимка? Мне действительно нужен snaplet здесь в моем случае?

Спасибо.

9
задан mightybyte 4 August 2012 в 15:20
поделиться