110 lines
2.4 KiB
Go
110 lines
2.4 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"math"
|
|
|
|
"allaboutapps.dev/aw/go-starter/internal/util"
|
|
"github.com/aarondl/null/v8"
|
|
"github.com/aarondl/sqlboiler/v4/boil"
|
|
)
|
|
|
|
type TxFn func(boil.ContextExecutor) error
|
|
|
|
func WithTransaction(ctx context.Context, db *sql.DB, txHandler TxFn) error {
|
|
return WithConfiguredTransaction(ctx, db, nil, txHandler)
|
|
}
|
|
|
|
func WithConfiguredTransaction(ctx context.Context, db *sql.DB, options *sql.TxOptions, txHandler TxFn) error {
|
|
tx, err := db.BeginTx(ctx, options)
|
|
if err != nil {
|
|
util.LogFromContext(ctx).Warn().Err(err).Msg("Failed to start transaction")
|
|
return fmt.Errorf("failed to start transaction: %w", err)
|
|
}
|
|
|
|
defer func() {
|
|
cause := recover()
|
|
|
|
switch {
|
|
case cause != nil:
|
|
util.LogFromContext(ctx).Error().Interface("cause", cause).Msg("Recovered from panic, rolling back transaction and panicking again")
|
|
|
|
if txErr := tx.Rollback(); txErr != nil {
|
|
util.LogFromContext(ctx).Warn().Err(txErr).Msg("Failed to roll back transaction after recovering from panic")
|
|
}
|
|
|
|
panic(cause)
|
|
case err != nil:
|
|
util.LogFromContext(ctx).Warn().Err(err).Msg("Received error, rolling back transaction")
|
|
|
|
if txErr := tx.Rollback(); txErr != nil {
|
|
util.LogFromContext(ctx).Warn().Err(txErr).Msg("Failed to roll back transaction after receiving error")
|
|
}
|
|
default:
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
util.LogFromContext(ctx).Warn().Err(err).Msg("Failed to commit transaction")
|
|
}
|
|
}
|
|
}()
|
|
|
|
err = txHandler(tx)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to execute transaction: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func NullIntFromInt64Ptr(i *int64) null.Int {
|
|
if i == nil {
|
|
return null.NewInt(0, false)
|
|
}
|
|
|
|
return null.NewInt(int(*i), true)
|
|
}
|
|
|
|
func NullFloat32FromFloat64Ptr(f *float64) null.Float32 {
|
|
if f == nil {
|
|
return null.NewFloat32(0.0, false)
|
|
}
|
|
|
|
return null.NewFloat32(float32(*f), true)
|
|
}
|
|
|
|
func NullIntFromInt16Ptr(i *int16) null.Int {
|
|
if i == nil {
|
|
return null.NewInt(0, false)
|
|
}
|
|
|
|
return null.NewInt(int(*i), true)
|
|
}
|
|
|
|
func Int16PtrFromNullInt(i null.Int) *int16 {
|
|
if !i.Valid || i.Int > math.MaxInt16 || i.Int < math.MinInt16 {
|
|
return nil
|
|
}
|
|
|
|
res := int16(i.Int)
|
|
return &res
|
|
}
|
|
|
|
func Int16PtrFromInt(i int) *int16 {
|
|
if i > math.MaxInt16 || i < math.MinInt16 {
|
|
return nil
|
|
}
|
|
|
|
res := int16(i)
|
|
return &res
|
|
}
|
|
|
|
func NullStringIfEmpty(s string) null.String {
|
|
if len(s) == 0 {
|
|
return null.String{}
|
|
}
|
|
|
|
return null.StringFrom(s)
|
|
}
|