package goblocks import ( "context" "log/slog" "math" "math/big" "strconv" "sync" _ "github.com/jackc/pgconn" _ "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgxpool" _ "github.com/jackc/pgx/v5/stdlib" ) var ( pgxPools = make(map[string]*pgxpool.Pool) pgxMutex sync.RWMutex ) func (a *App) newPGXPool(name string) *pgxpool.Pool { slog.Debug("newPGXPool", "name", name, "datasource", a.Datasource(name)) pgxMutex.Lock() defer pgxMutex.Unlock() if pool, exists := pgxPools[name]; exists { return pool } dbPool, err := pgxpool.New(context.Background(), a.Datasource(name)) if err != nil { slog.Error("error connecting to database", "error", err, "name", name) panic(err) } if err := dbPool.Ping(context.Background()); err != nil { slog.Error("error pinging database, maybe incorrect datasource", "error", err, "name", name) panic(err) } pgxPools[name] = dbPool slog.Info("connected to database", "name", name) return dbPool } func (a *App) GetPGXPool(name string) *pgxpool.Pool { pgxMutex.RLock() defer pgxMutex.RUnlock() pool, exists := pgxPools[name] if !exists { slog.Error("database connection not found", "name", name) return nil } return pool } func (a *App) ClosePGXPool(name string) { pgxMutex.Lock() defer pgxMutex.Unlock() pool, exists := pgxPools[name] if !exists { slog.Error("database connection not found", "name", name) return } pool.Close() delete(pgxPools, name) slog.Info("closed database connection", "name", name) } func NumericToFloat64(n pgtype.Numeric) float64 { val, err := n.Value() if err != nil { slog.Error("error getting numeric value", "error", err) return 0 } strValue, ok := val.(string) if !ok { slog.Error("error converting numeric value to string") return 0 } floatValue, err := strconv.ParseFloat(strValue, 64) if err != nil { slog.Error("error converting string to float", "error", err) return 0 } return floatValue } func NumericToInt64(n pgtype.Numeric) int64 { return n.Int.Int64() * int64(math.Pow(10, float64(n.Exp))) } func FloatToNumeric(number float64, precision int) (value pgtype.Numeric) { parse := strconv.FormatFloat(number, 'f', precision, 64) slog.Debug("parse", "parse", parse) if err := value.Scan(parse); err != nil { slog.Error("error scanning numeric", "error", err) } return value } func AddNumeric(a, b pgtype.Numeric) pgtype.Numeric { minExp := min(a.Exp, b.Exp) aInt := new(big.Int).Set(a.Int) bInt := new(big.Int).Set(b.Int) for a.Exp > minExp { aInt.Mul(aInt, big.NewInt(10)) a.Exp-- } for b.Exp > minExp { bInt.Mul(bInt, big.NewInt(10)) b.Exp-- } resultado := new(big.Int).Add(aInt, bInt) return pgtype.Numeric{ Int: resultado, Exp: minExp, Valid: true, } } func SubtractNumeric(a, b pgtype.Numeric) pgtype.Numeric { minExp := a.Exp if b.Exp < minExp { minExp = b.Exp } aInt := new(big.Int).Set(a.Int) bInt := new(big.Int).Set(b.Int) for a.Exp > minExp { aInt.Mul(aInt, big.NewInt(10)) a.Exp-- } for b.Exp > minExp { bInt.Mul(bInt, big.NewInt(10)) b.Exp-- } resultado := new(big.Int).Sub(aInt, bInt) return pgtype.Numeric{ Int: resultado, Exp: minExp, Valid: true, } }