package rbac import ( "database/sql" "log/slog" "slices" ) type Txn struct { SQLTx *sql.Tx undos []func() error committed bool } func NewTxn(sqlTx *sql.Tx) *Txn { return &Txn{SQLTx: sqlTx} } func (t *Txn) AddUndo(undo func() error) { t.undos = append(t.undos, undo) } func (t *Txn) Commit() error { if err := t.SQLTx.Commit(); err != nil { return err } t.committed = true return nil } func (t *Txn) Cleanup(l *slog.Logger) { if t.committed { return } t.SQLTx.Rollback() for _, undo := range slices.Backward(t.undos) { if err := undo(); err != nil { l.Error("failed to reverse ACL change", "err", err) } } }