Я пытаюсь понять простую конструкцию моментального снимка. Кроме того, когда мне действительно нужно сделать снаплет, а когда простую стороннюю библиотеку? И если мне это нужно, как мне сделать это из библиотеки?
Например, у меня есть несколько функций БД, в которые я оборачиваю код 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 здесь в моем случае?
Спасибо.