I need to write a reusable function where part of it can be run before and after its invoked.
For example:
isNewTnx, rollback, beginErr := DbConnectionManager.Begin(req)
if beginErr != nil {
return nil, beginErr
}
if isNewTnx {
defer rollback()
}
Above code starts a transaction and if its a new transaction it controls it, meaning it can either commit or rollback. I'm forced to write this code in a lot of services. Any way to make this more reusable? I know function currying is an option, any other alternatives?
The following code uses types from
github.com/jmoiron/sqlxas example. Given a data structure that wraps your database driver (mainly for interface implementation):You declare a method on it:
Here the trick is to always rollback with
defer tx.Rollback(). If the transaction was successfully completed, rolling back does nothing. If an error occurred, it rolls back the transaction.And then you use is as:
For functions that need to return something along with a possible error, you can use a generic wrapper around
InTransactionfunction. Unfortunately this must be a top-level function that takes the datastore struct (or whatever appropriate interface) because methods can't have type parameters that weren't already defined on the receiver type:And then you use it as: