transactor

package
v0.0.7 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package transactor provides a decorator for r3.CRUD[T, ID] that surfaces transaction capabilities from the underlying driver.

It follows the same decorator pattern as features/softdelete and features/history: the decorator wraps any r3.CRUD[T, ID] and transparently satisfies the same interface, passing all six CRUD methods through to the inner implementation.

Transaction support in r3 is opt-in. Drivers that support transactions implement the r3.Transactor interface (BeginTx). The decorator delegates to the inner CRUD if it satisfies Transactor; otherwise r3.ErrTransactionsNotSupported is returned.

Supported drivers

All SQL-based drivers support transactions out of the box:

  • r3pgx (PostgreSQL via pgx)
  • r3pq (PostgreSQL via lib/pq)
  • r3mysql (MySQL)
  • r3sqlite3 (SQLite)
  • r3gorm (GORM)
  • r3bun (Bun)
  • r3gopg (go-pg)

MongoDB (r3mongo) does not currently implement Transactor.

Usage

inner := r3pgx.NewPgxCRUD[User, int64](db)
repo := transactor.WithTransactor[User, int64](inner)

// repo satisfies r3.CRUD[User, int64] — all methods pass through.
// Additionally:
repo.SupportsTransactions() // true for SQL drivers

// Start a transaction manually:
tx, err := repo.BeginTx(ctx)
if err != nil { ... }
defer tx.Rollback()
tx.Create(ctx, user)
tx.Commit()

// Or use the convenience helper:
err := repo.InTx(ctx, func(tx r3.CRUD[User, int64]) error {
    _, err := tx.Create(ctx, user)
    return err
})

Composability

The decorator can be stacked with other feature decorators:

repo := transactor.WithTransactor(
    history.WithHistory(
        softdelete.WithSoftDelete(inner), store, ...opts),
)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CRUD

type CRUD[T any, ID comparable] struct {
	// contains filtered or unexported fields
}

CRUD is a decorator that wraps any r3.CRUD[T, ID] and adds transaction capabilities. All six standard CRUD methods are passed through to the inner implementation unchanged.

Transaction operations (BeginTx) are delegated to the inner CRUD if it implements the r3.Transactor interface. Otherwise, r3.ErrTransactionsNotSupported is returned.

func WithTransactor

func WithTransactor[T any, ID comparable](inner r3.CRUD[T, ID]) *CRUD[T, ID]

WithTransactor wraps an existing r3.CRUD with transaction capabilities. All standard CRUD methods pass through unchanged.

func (*CRUD[T, ID]) Aggregate added in v0.0.3

func (c *CRUD[T, ID]) Aggregate(ctx context.Context, qarg ...r3.Query) ([]r3.AggregateRow, error)

Aggregate passes through to the inner CRUD's Aggregate.

func (*CRUD[T, ID]) AggregateThroughRelation added in v0.0.5

func (c *CRUD[T, ID]) AggregateThroughRelation(
	ctx context.Context, relation string, qarg ...r3.Query,
) ([]r3.AggregateRow, error)

AggregateThroughRelation passes through to the inner CRUD.

func (*CRUD[T, ID]) BeginTx

func (c *CRUD[T, ID]) BeginTx(ctx context.Context) (r3.TxCRUD[T, ID], error)

BeginTx starts a transaction if the underlying backend supports it.

It walks the decorator chain below the transactor to the backend, begins the transaction there, and re-applies the same decorator stack on top of it — so the returned r3.TxCRUD is fully decorated and writes inside the transaction are still validated, audited, permission-checked, etc.

Returns r3.ErrTransactionsNotSupported if no layer in the chain implements r3.Transactor.

func (*CRUD[T, ID]) Count

func (c *CRUD[T, ID]) Count(ctx context.Context, qarg ...r3.Query) (int64, error)

Count passes through to the inner CRUD.

func (*CRUD[T, ID]) Create

func (c *CRUD[T, ID]) Create(ctx context.Context, entity T) (T, error)

Create passes through to the inner CRUD.

func (*CRUD[T, ID]) Delete

func (c *CRUD[T, ID]) Delete(ctx context.Context, id ID) error

Delete passes through to the inner CRUD.

func (*CRUD[T, ID]) Get

func (c *CRUD[T, ID]) Get(ctx context.Context, id ID, qarg ...r3.Query) (T, error)

Get passes through to the inner CRUD.

func (*CRUD[T, ID]) InTx

func (c *CRUD[T, ID]) InTx(ctx context.Context, fn func(tx r3.CRUD[T, ID]) error) error

InTx runs fn inside a transaction if the inner CRUD supports it. It begins a transaction, calls fn with a transactional CRUD, and:

  • commits if fn returns nil
  • rolls back if fn returns an error or panics

Returns r3.ErrTransactionsNotSupported if the inner CRUD does not implement r3.Transactor.

func (*CRUD[T, ID]) Inner

func (c *CRUD[T, ID]) Inner() r3.CRUD[T, ID]

Inner returns the wrapped CRUD (for advanced usage / unwrapping).

func (*CRUD[T, ID]) List

func (c *CRUD[T, ID]) List(ctx context.Context, qarg ...r3.Query) ([]T, int64, error)

List passes through to the inner CRUD.

func (*CRUD[T, ID]) Patch

func (c *CRUD[T, ID]) Patch(ctx context.Context, entity T, fields r3.Fields) (T, error)

Patch passes through to the inner CRUD.

func (*CRUD[T, ID]) PatchWhere added in v0.0.4

func (c *CRUD[T, ID]) PatchWhere(
	ctx context.Context, filters r3.Filters, entity T, fields r3.Fields,
) (int64, error)

PatchWhere passes through to the inner CRUD's BulkPatcher capability.

func (*CRUD[T, ID]) SupportsTransactions

func (c *CRUD[T, ID]) SupportsTransactions() bool

SupportsTransactions reports whether the underlying backend supports transactions (seen through any decorators between the transactor and the backend), and can therefore be used with BeginTx / InTx.

func (*CRUD[T, ID]) Unwrap

func (c *CRUD[T, ID]) Unwrap() r3.CRUD[T, ID]

Unwrap returns the wrapped CRUD so capability detection and transaction propagation can walk the decorator chain.

func (*CRUD[T, ID]) Update

func (c *CRUD[T, ID]) Update(ctx context.Context, entity T) (T, error)

Update passes through to the inner CRUD.

func (*CRUD[T, ID]) Upsert added in v0.0.4

func (c *CRUD[T, ID]) Upsert(ctx context.Context, entity T, opts ...r3.UpsertOption) (T, error)

Upsert passes through to the inner CRUD's Upserter capability, so an upsert run inside InTx participates in the transaction like any other write.

Jump to

Keyboard shortcuts

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