139 lines
3.6 KiB
Go
139 lines
3.6 KiB
Go
package database
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"go.uber.org/zap"
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/gorm"
|
|
|
|
"api_bb/pkg/logger"
|
|
)
|
|
|
|
type Database struct {
|
|
DB *gorm.DB
|
|
cfg *Config
|
|
}
|
|
|
|
type Config struct {
|
|
URL string
|
|
}
|
|
|
|
func NewDatabase(cfg *Config) *Database {
|
|
return &Database{
|
|
cfg: cfg,
|
|
}
|
|
}
|
|
|
|
// Connect устанавливает соединение с базой данных
|
|
func (d *Database) Connect() error {
|
|
zapLogger := logger.Get()
|
|
|
|
// Логирование попытки подключения к БД
|
|
zapLogger.Info("attempting to connect to database",
|
|
zap.String("host", ExtractHostFromDSN(d.cfg.URL)),
|
|
zap.String("database", ExtractDBNameFromDSN(d.cfg.URL)),
|
|
)
|
|
|
|
db, err := gorm.Open(postgres.Open(d.cfg.URL), &gorm.Config{})
|
|
if err != nil {
|
|
zapLogger.Error("failed to connect to database",
|
|
zap.Error(err),
|
|
zap.String("database_url", MaskPassword(d.cfg.URL)),
|
|
)
|
|
return fmt.Errorf("failed to connect to database: %w", err)
|
|
}
|
|
|
|
d.DB = db
|
|
|
|
// Логирование успешного подключения к БД
|
|
zapLogger.Info("successfully connected to database",
|
|
zap.String("host", ExtractHostFromDSN(d.cfg.URL)),
|
|
zap.String("database", ExtractDBNameFromDSN(d.cfg.URL)),
|
|
)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Ping проверяет соединение с базой данных
|
|
func (d *Database) Ping() error {
|
|
zapLogger := logger.Get()
|
|
|
|
sqlDB, err := d.DB.DB()
|
|
if err != nil {
|
|
zapLogger.Error("failed to get database instance", zap.Error(err))
|
|
return fmt.Errorf("failed to get database instance: %w", err)
|
|
}
|
|
|
|
if err := sqlDB.Ping(); err != nil {
|
|
zapLogger.Error("database ping failed", zap.Error(err))
|
|
return fmt.Errorf("database ping failed: %w", err)
|
|
}
|
|
|
|
zapLogger.Info("database ping successful")
|
|
return nil
|
|
}
|
|
|
|
// Close закрывает соединение с базой данных
|
|
func (d *Database) Close() error {
|
|
zapLogger := logger.Get()
|
|
|
|
if d.DB == nil {
|
|
return nil
|
|
}
|
|
|
|
sqlDB, err := d.DB.DB()
|
|
if err != nil {
|
|
zapLogger.Error("failed to get database instance for closing", zap.Error(err))
|
|
return fmt.Errorf("failed to get database instance: %w", err)
|
|
}
|
|
|
|
zapLogger.Info("closing database connection")
|
|
if err := sqlDB.Close(); err != nil {
|
|
zapLogger.Error("failed to close database connection", zap.Error(err))
|
|
return fmt.Errorf("failed to close database connection: %w", err)
|
|
}
|
|
|
|
zapLogger.Info("database connection closed successfully")
|
|
return nil
|
|
}
|
|
|
|
// Вспомогательные функции для работы с DSN
|
|
|
|
// ExtractHostFromDSN извлекает хост из DSN строки
|
|
func ExtractHostFromDSN(dsn string) string {
|
|
// Простая реализация для PostgreSQL DSN
|
|
parts := strings.Split(dsn, " ")
|
|
for _, part := range parts {
|
|
if strings.HasPrefix(part, "host=") {
|
|
return strings.TrimPrefix(part, "host=")
|
|
}
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
// ExtractDBNameFromDSN извлекает имя базы данных из DSN строки
|
|
func ExtractDBNameFromDSN(dsn string) string {
|
|
// Простая реализация для PostgreSQL DSN
|
|
parts := strings.Split(dsn, " ")
|
|
for _, part := range parts {
|
|
if strings.HasPrefix(part, "dbname=") {
|
|
return strings.TrimPrefix(part, "dbname=")
|
|
}
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
// MaskPassword маскирует пароль в DSN строке для безопасного логирования
|
|
func MaskPassword(dsn string) string {
|
|
// Простая реализация - заменяет пароль на ***
|
|
parts := strings.Split(dsn, " ")
|
|
for i, part := range parts {
|
|
if strings.HasPrefix(part, "password=") {
|
|
parts[i] = "password=***"
|
|
break
|
|
}
|
|
}
|
|
return strings.Join(parts, " ")
|
|
} |