refactor
This commit is contained in:
101
pkg/transaction/transaction.go
Normal file
101
pkg/transaction/transaction.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package transaction
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/TelegramExchange/pkg/postgres"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var (
|
||||
errMissingInit = errors.New("missing `transaction.Init' call before `transaction.Begin'")
|
||||
errMissingBegin = errors.New("missing `transaction.Begin' call before 'transaction.Get'")
|
||||
)
|
||||
|
||||
var (
|
||||
pool *pgxpool.Pool
|
||||
IsUnitTest bool
|
||||
)
|
||||
|
||||
type ctxKey struct{}
|
||||
|
||||
func Init(p *postgres.Pool) {
|
||||
pool = p.Pool
|
||||
}
|
||||
|
||||
type Transaction struct {
|
||||
pgx.Tx
|
||||
}
|
||||
|
||||
func Begin(ctx context.Context) (context.Context, error) {
|
||||
if IsUnitTest {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
if pool == nil {
|
||||
return nil, errMissingInit
|
||||
}
|
||||
|
||||
tx, err := pool.Begin(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pool.Begin: %w", err)
|
||||
}
|
||||
|
||||
ctx = context.WithValue(ctx, ctxKey{}, &Transaction{tx})
|
||||
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func Rollback(ctx context.Context) {
|
||||
if IsUnitTest {
|
||||
return
|
||||
}
|
||||
|
||||
tx, ok := ctx.Value(ctxKey{}).(*Transaction)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error().Err(err).Msg("transaction: Rollback")
|
||||
}
|
||||
}
|
||||
|
||||
func Commit(ctx context.Context) error {
|
||||
if IsUnitTest {
|
||||
return nil
|
||||
}
|
||||
|
||||
tx, ok := ctx.Value(ctxKey{}).(*Transaction)
|
||||
if !ok {
|
||||
return errMissingBegin
|
||||
}
|
||||
|
||||
err := tx.Commit(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("tx.Commit: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Executor interface {
|
||||
Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
|
||||
Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
|
||||
QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
|
||||
}
|
||||
|
||||
func TryExtractTX(ctx context.Context) Executor {
|
||||
tx, ok := ctx.Value(ctxKey{}).(*Transaction)
|
||||
if !ok {
|
||||
return pool
|
||||
}
|
||||
|
||||
return tx
|
||||
}
|
||||
38
pkg/transaction/wrap.go
Normal file
38
pkg/transaction/wrap.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package transaction
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func Wrap(ctx context.Context, fn func(context.Context) error) error {
|
||||
tx, err := pool.Begin(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("pool.Begin: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err = tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error().Err(err).Msg("transaction: Rollback")
|
||||
}
|
||||
}()
|
||||
|
||||
ctx = context.WithValue(ctx, ctxKey{}, &Transaction{tx})
|
||||
|
||||
err = fn(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fn: %w", err)
|
||||
}
|
||||
|
||||
err = tx.Commit(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("tx.Commit: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user