Like any database worth its salt, SQLite supports transactions. Axiom
exposes these through the store's transact
method.
The transact method takes a function. That function will be run in a database transaction. The changes in the function happen atomically (that is: either they entirely do or entirely don't).
.. testsetup:: from axiom.store import Store from bunny import Bunny
>>> store = Store()
>>> thumper = Bunny(store=store)
>>> bugs = Bunny(store=store)
>>> def petBunny():
... bugs.timesPetted += 1
... thumper.timesPetted += 1
>>> store.transact(petBunny)
>>> assert thumper.timesPetted == bugs.timesPetted == 1
Any uncaught exception raised by the transacted function will be reraised. When this happens, the changes are reset to what they were before the transaction was initiated.
>>> assert thumper.timesPetted == 1
>>> def runIntoProblems():
... thumper.timesPetted += 1
... raise RuntimeError("fluffiness overload")
>>> store.transact(runIntoProblems)
Traceback (most recent call last):
...
RuntimeError: fluffiness overload
>>> assert thumper.timesPetted == 1
The transact
method takes any amount of arguments (which are
passed verbatim to the transacted function), and will return the
return value of the transacted function.
>>> def petBunnies(bunnies, times):
... totalPetsGiven = 0
... for bunny in bunnies:
... bunny.timesPetted += times
... totalPetsGiven += times
... return totalPetsGiven
>>> store.transact(petBunnies, [thumper, bugs], 2)
4