mtx

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 25, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package mtx provides a flexible transaction management system with support for nested transactions, panic recovery, and context-based transaction propagation. It allows working with different database/sql implementations through interfaces

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNilTxBeginner indicates that the provided TxBeginner is nil.
	// This error is returned when trying to use a Transactor with an uninitialized beginner.
	ErrNilTxBeginner = fmt.Errorf("tx beginner is nil")

	// ErrNilTxOperator indicates that the provided CtxOperator is nil.
	// This error is returned when trying to use a Transactor with an uninitialized operator.
	ErrNilTxOperator = fmt.Errorf("tx operator is nil")

	// ErrBeginTx indicates that starting a new transaction has failed.
	// This error wraps the underlying error from the database driver.
	ErrBeginTx = fmt.Errorf("begin tx")

	// ErrCommitFailed indicates that committing a transaction has failed.
	// This error wraps the underlying error from the database driver during commit
	ErrCommitFailed = fmt.Errorf("commit failed")

	// ErrRollbackFailed indicates that rolling back a transaction has failed.
	// This error wraps the underlying error from the database driver during rollback.
	ErrRollbackFailed = fmt.Errorf("rollback failed")

	// ErrRollbackSuccess indicates that a transaction was successfully rolled back.
	// Despite being an error type, it signals a successful rollback operation.
	ErrRollbackSuccess = fmt.Errorf("rollback tx")

	// ErrPanicRecovered indicates that a panic was recovered and converted to an error.
	// It wraps the original panic value to provide context about what caused the panic.
	ErrPanicRecovered = fmt.Errorf("panic recovered")
)

Functions

This section is empty.

Types

type ContextOperator

type ContextOperator[K comparable, T Tx] struct {
	// contains filtered or unexported fields
}

ContextOperator implements transaction injection and extraction from context.Context. It uses a type-safe approach with comparable keys to store and retrieve transactions from context, avoiding global string keys and providing compile-time type safety.

The type parameters:

  • K: a comparable type used as the context key (typically a custom type or iota)
  • T: the transaction type that satisfies the Tx interface

func NewContextOperator

func NewContextOperator[K comparable, T Tx](key K) *ContextOperator[K, T]

NewContextOperator returns a pointer to a new ContextOperator instance.

It accepts a key of a comparable type that will be used for both injecting and extracting transactions from context.Context.

The key should be unique to avoid collisions.

func (*ContextOperator[K, T]) Extract

func (o *ContextOperator[K, T]) Extract(ctx context.Context) (T, bool)

Extract retrieves a transaction from the context if one exists. It performs a type assertion to convert the context value to the expected transaction type. The boolean return value indicates whether a transaction was found and successfully type-asserted.

This method is used by Transactor to check if a transaction already exists in the context, enabling nested transaction support.

Parameters:

  • ctx: the context to extract the transaction from

Returns:

  • T: the extracted transaction (zero value if not found)
  • bool: true if a transaction was found and is of the correct type

Example:

tx, ok := operator.Extract(ctx)
if ok {
    // Use existing transaction
    result := tx.QueryRow(...)
} else {
    // No transaction in context, create new one
}

func (*ContextOperator[K, T]) Inject

func (o *ContextOperator[K, T]) Inject(ctx context.Context, tx T) context.Context

Inject stores a transaction in the context and returns a new context containing it. It uses context.WithValue internally, associating the transaction with the operator's key. The original context remains unchanged.

This method is typically used by Transactor when creating a new transaction to make it available to nested function calls.

Parameters:

  • ctx: the parent context
  • tx: the transaction to store

type Transactor

type Transactor[B TxBeginner[T], T Tx] struct {
	// contains filtered or unexported fields
}

Transactor manages transactions for a single TxBeginner instance. It provides a high-level API for executing functions within a transaction context, with support for nested transactions, automatic rollback on error/panic, and proper transaction propagation through context.

The type parameters B and T allow working with any transaction implementation that satisfies the TxBeginner and Tx interfaces respectively.

func NewTransactor

func NewTransactor[B TxBeginner[T], T Tx](
	beginner B,
	operator СtxOperator[T]) *Transactor[B, T]

NewTransactor returns new Transactor.

func (*Transactor[B, T]) TryGetTx

func (t *Transactor[B, T]) TryGetTx(ctx context.Context) (T, bool)

TryGetTx attempts to retrieve a transaction from the given context. It returns the transaction and true if found, or a zero value and false otherwise.

func (*Transactor[B, T]) TxBeginner

func (t *Transactor[B, T]) TxBeginner() B

TxBeginner returns the underlying TxBeginner used by this Transactor. This can be useful for creating transactions manually.

func (*Transactor[B, T]) WithinTx

func (t *Transactor[B, T]) WithinTx(ctx context.Context, fn func(ctx context.Context) error) (err error)

WithinTx executes the provided function within a transaction context. It handles transaction creation, propagation, and automatic cleanup (commit/rollback).

Key features:

  • Nested transaction support: When called recursively, only the top-level call creates and manages the actual transaction. Inner calls reuse the existing transaction from the context.
  • Automatic rollback: If the function returns an error or panics, the transaction is automatically rolled back.
  • Automatic commit: If the function completes without error, the transaction is automatically committed (only at the top level).
  • Panic recovery: Panics are recovered and converted to errors with ErrPanicRecovered. Higher-level panics override lower-level ones.
  • Context propagation: The transaction is injected into the context for inner function calls.

The function follows these rules:

  • If a transaction exists in the context, it is reused (nested call)
  • Otherwise, a new transaction is created (top-level call)
  • Errors from the function or from commit/rollback are properly wrapped
  • Panics are handled gracefully without crashing the application

Example:

// Top-level transaction
err := transactor.WithinTx(ctx, func(ctx context.Context) error {
    // This operation runs in a transaction
    if err := someOperation(ctx); err != nil {
        return err // Will trigger rollback
    }

    // Nested call - reuses the same transaction
    err := transactor.WithinTx(ctx, func(ctx context.Context) error {
        return anotherOperation(ctx) // Same transaction
    })

    return err
}) // Auto-commits on success, rolls back on error

Note:

  • A processed error returns to the highest level for commit or rollback
  • Panics are transformed to errors with the same message
  • Higher level panics override lower level panics or errors

Examples:

type Tx

type Tx interface {
	Rollback(ctx context.Context) error
	Commit(ctx context.Context) error
}

Tx represent transaction contract.

type TxBeginner

type TxBeginner[T Tx] interface {
	comparable
	BeginTx(ctx context.Context) (T, error)
}

TxBeginner is responsible for creating new Tx.

type СtxOperator

type СtxOperator[T Tx] interface {
	Inject(ctx context.Context, tx T) context.Context
	Extract(ctx context.Context) (T, bool)
}

СtxOperator is responsible for transaction propagation through context.Context. It provides methods to inject a transaction into context and extract it back.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL