Add a transaction decorator that allows to execute nested database functions in one transaction using thread local storage as a function call stack. It's very useful in situations when one of the called function is failed we can rollback all changes that have been made through that transaction.
Add DatabaseError exception which is inherited by SqlAlchemyDatabaseError that wraps all common SQLAlchemy errors, and UserDatabaseError which user can raise in one of the database functions (for example create_user). Briefly, it allows as to handle errors in more reliable and consistent way
Fix and add new tests to cover new functionality
Concerns: db_execute requires the Connection obj as an argument, and it seems to me that it looks too complicated when we pass a statement object and a connection object in database functions (like db_execute(select_stmt, db_conn=db_conn), and there is the way to solve this in more pythonic style: get the connection object from the decorated function
create_user
). Briefly, it allows as to handle errors in more reliable and consistent wayConcerns: db_execute requires the Connection obj as an argument, and it seems to me that it looks too complicated when we pass a statement object and a connection object in database functions (like
db_execute(select_stmt, db_conn=db_conn)
, and there is the way to solve this in more pythonic style: get the connection object from the decorated function