I'm using Yesod as the framework, postgresql as the DB, and have the following definition of runDB
. Looking at the docs on the Yesod site, I have a hunch that using runDB
in the following manner will cause a rollback of the first insert
upon the failure of the second. Am I right. If not, how do I invoke a rollback?
instance YesodPersist App where
<snip>
runDB action = do
master <- getYesod
runSqlPool action $ appConnPool master
addKitteh :: Kitteh -> Handler (Either StoreError StoreResult)
addKitteh (Kitteh desc color size photo) = do
data_key <- runDB $ do
data_key <- insert (KittehDesc desc color size)
insert (KittehPic data_key photo)
...
edit - Also, what happens if the first insert
fails?
edit - I thought the model might be significant
KittehDesc json
blurb Text
color Color
size KittehSize
deriving Show
KittehPic
kittehId KittehDescId Eq
kittehPic Base64
UniqueKittehId kittehId
Yes, everything in runDB
is wrapped in a transaction. If the first insert fails an exception will be thrown, and the code won't reach the second insert.
I think this is documented somewhere, but I just traced the code to come to this conclusion: runDB
is implemented with defaultRunDB
, which calls into runPool
, which calls runSqlPool
, which calls into runSqlConn
, whic you can see is handling rollbacks when an exception occurs:
runSqlConn :: MonadBaseControl IO m => SqlPersistT m a -> SqlBackend -> m a
runSqlConn r conn = control $ \runInIO -> mask $ \restore -> do
let getter = getStmtConn conn
restore $ connBegin conn getter
x <- onException
(restore $ runInIO $ runReaderT r conn)
(restore $ connRollback conn getter)
restore $ connCommit conn getter
return x