package database import ( "context" "fmt" "log/slog" "bunker/client/internal/services/core" "github.com/jmoiron/sqlx" ) type transaction struct { transaction *sqlx.Tx logger *slog.Logger } func (d *database) Transaction(ctx context.Context) (core.DatabaseTransaction, error) { txn, err := d.db.BeginTxx(ctx, nil) if err != nil { return nil, fmt.Errorf("%w: starting transaction: %w", core.ErrDatabase, err) } txHandler := &transaction{ transaction: txn, logger: d.logger.With("module", "transactioner"), } return txHandler, nil } func (t *transaction) Apply(steps ...core.TransactionFunc) error { for stepNumber, stepFunc := range steps { if err := stepFunc(t.transaction); err != nil { t.logger.Error( "Error occurred.", "step", stepNumber, "error", err.Error(), "module", "core/database", "subsystem", "transaction", ) if rollbackErr := t.transaction.Rollback(); rollbackErr != nil { t.logger.Error( "Transaction rollback failed.", "error", err.Error(), "module", "core/database", "subsystem", "transaction", ) return fmt.Errorf("%w: transaction rollback: %w", core.ErrDatabase, rollbackErr) } return err } } if err := t.transaction.Commit(); err != nil { t.logger.Error( "Transaction commit failed.", "error", err.Error(), "module", "core/database", "subsystem", "transaction", ) if rollbackErr := t.transaction.Rollback(); rollbackErr != nil { t.logger.Error( "Transaction rollback failed.", "error", err.Error(), "module", "core/database", "subsystem", "transaction", ) return fmt.Errorf("%w: transaction rollback: %w", core.ErrDatabase, rollbackErr) } return fmt.Errorf("%w: transaction commit: %w", core.ErrDatabase, err) } return nil }