mirror of https://github.com/mickael-menu/zk
Refactor transaction usage
parent
4ca1595f1f
commit
8467f1aa3a
@ -0,0 +1,63 @@
|
||||
package sqlite
|
||||
|
||||
import "database/sql"
|
||||
|
||||
// Inspired by https://pseudomuto.com/2018/01/clean-sql-transactions-in-golang/
|
||||
|
||||
// Transaction is an interface that models the standard transaction in
|
||||
// database/sql.
|
||||
//
|
||||
// To ensure TxFn funcs cannot commit or rollback a transaction (which is
|
||||
// handled by `WithTransaction`), those methods are not included here.
|
||||
type Transaction interface {
|
||||
Exec(query string, args ...interface{}) (sql.Result, error)
|
||||
ExecStmts(stmts []string) error
|
||||
Prepare(query string) (*sql.Stmt, error)
|
||||
Query(query string, args ...interface{}) (*sql.Rows, error)
|
||||
QueryRow(query string, args ...interface{}) *sql.Row
|
||||
}
|
||||
|
||||
// txWrapper wraps a native sql.Tx to fully implement the Transaction interface.
|
||||
type txWrapper struct {
|
||||
*sql.Tx
|
||||
}
|
||||
|
||||
func (tx *txWrapper) ExecStmts(stmts []string) error {
|
||||
var err error
|
||||
for _, stmt := range stmts {
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
_, err = tx.Exec(stmt)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// A Txfn is a function that will be called with an initialized Transaction
|
||||
// object that can be used for executing statements and queries against a
|
||||
// database.
|
||||
type TxFn func(tx Transaction) error
|
||||
|
||||
// WithTransaction creates a new transaction and handles rollback/commit based
|
||||
// on the error object returned by the TxFn closure.
|
||||
func (db *DB) WithTransaction(fn TxFn) error {
|
||||
tx, err := db.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
// A panic occurred, rollback and repanic.
|
||||
tx.Rollback()
|
||||
panic(p)
|
||||
} else if err != nil {
|
||||
tx.Rollback()
|
||||
} else {
|
||||
err = tx.Commit()
|
||||
}
|
||||
}()
|
||||
|
||||
err = fn(&txWrapper{tx})
|
||||
return err
|
||||
}
|
Loading…
Reference in New Issue