added transactional wrapper, and support for it

This commit is contained in:
Colin Henry 2025-03-10 22:59:03 -07:00
parent f88f00e78c
commit 6aa7788fd0
2 changed files with 33 additions and 2 deletions

View File

@ -7,7 +7,7 @@ import (
"git.sdf.org/jchenry/x"
)
type Func func(db *sql.DB)
type Func func(ctx context.Context, db *sql.DB) error
type Actor struct {
DB *sql.DB
@ -19,7 +19,9 @@ func (a *Actor) Run(ctx context.Context) error {
for {
select {
case f := <-a.ActionChan:
f(a.DB)
if err:= f(ctx, a.DB); err != nil{
return err
}
case <-ctx.Done():
return ctx.Err()
}

29
database/transactor.go Normal file
View File

@ -0,0 +1,29 @@
package database
import (
"context"
"database/sql"
"fmt"
)
// WithinTransaction is a functional equivalent of the Transactor interface created by Thibaut Rousseau's
// https://blog.thibaut-rousseau.com/blog/sql-transactions-in-go-the-good-way/
func WithinTransaction(f Func) Func {
return func(ctx context.Context, db *sql.DB) error {
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("failed to begin transaction: %w", err)
}
if err := f(ctx, db); err != nil {
_ = tx.Rollback()
return err
}
if err := tx.Commit(); err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
return nil
}
}