104 lines
3.0 KiB
Go
104 lines
3.0 KiB
Go
// Filename: internal/db/db.go
|
|
package db
|
|
|
|
import (
|
|
"fmt"
|
|
"gemini-balancer/internal/config"
|
|
"gemini-balancer/internal/db/dialect"
|
|
"gemini-balancer/internal/db/migrations"
|
|
stdlog "log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/glebarez/sqlite"
|
|
"github.com/sirupsen/logrus"
|
|
"gorm.io/driver/mysql"
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
)
|
|
|
|
func NewDB(cfg *config.Config, appLogger *logrus.Logger) (*gorm.DB, dialect.DialectAdapter, error) {
|
|
Logger := appLogger.WithField("component", "db")
|
|
Logger.Info("Initializing database connection and dialect adapter...")
|
|
dbConfig := cfg.Database
|
|
dsn := dbConfig.DSN
|
|
var gormLogger logger.Interface
|
|
if cfg.Log.Level == "debug" {
|
|
gormLogger = logger.New(
|
|
stdlog.New(os.Stdout, "\r\n", stdlog.LstdFlags),
|
|
logger.Config{
|
|
SlowThreshold: 1 * time.Second,
|
|
LogLevel: logger.Info,
|
|
IgnoreRecordNotFoundError: true,
|
|
Colorful: true,
|
|
},
|
|
)
|
|
Logger.Info("Debug mode enabled, GORM SQL logging is active.")
|
|
}
|
|
|
|
var dialector gorm.Dialector
|
|
var adapter dialect.DialectAdapter
|
|
switch {
|
|
case strings.HasPrefix(dsn, "postgres://"), strings.HasPrefix(dsn, "postgresql://"):
|
|
Logger.Info("Detected PostgreSQL database.")
|
|
dialector = postgres.Open(dsn)
|
|
adapter = dialect.NewPostgresAdapter()
|
|
case strings.Contains(dsn, "@tcp"):
|
|
Logger.Info("Detected MySQL database.")
|
|
if !strings.Contains(dsn, "parseTime=true") {
|
|
if strings.Contains(dsn, "?") {
|
|
dsn += "&parseTime=true"
|
|
} else {
|
|
dsn += "?parseTime=true"
|
|
}
|
|
}
|
|
dialector = mysql.Open(dsn)
|
|
adapter = dialect.NewPostgresAdapter()
|
|
default:
|
|
Logger.Info("Using SQLite database.")
|
|
if err := os.MkdirAll(filepath.Dir(dsn), 0755); err != nil {
|
|
Logger.Errorf("Failed to create SQLite directory: %v", err)
|
|
return nil, nil, err
|
|
}
|
|
dialector = sqlite.Open(dsn + "?_busy_timeout=5000")
|
|
adapter = dialect.NewSQLiteAdapter()
|
|
}
|
|
db, err := gorm.Open(dialector, &gorm.Config{
|
|
Logger: gormLogger,
|
|
PrepareStmt: true,
|
|
})
|
|
if err != nil {
|
|
Logger.Errorf("Failed to open database connection: %v", err)
|
|
return nil, nil, err
|
|
}
|
|
|
|
sqlDB, err := db.DB()
|
|
if err != nil {
|
|
Logger.Errorf("Failed to get underlying sql.DB: %v", err)
|
|
return nil, nil, err
|
|
}
|
|
sqlDB.SetMaxIdleConns(dbConfig.MaxIdleConns)
|
|
sqlDB.SetMaxOpenConns(dbConfig.MaxOpenConns)
|
|
sqlDB.SetConnMaxLifetime(dbConfig.ConnMaxLifetime)
|
|
Logger.Infof("Connection pool configured: MaxIdle=%d, MaxOpen=%d, MaxLifetime=%v",
|
|
dbConfig.MaxIdleConns, dbConfig.MaxOpenConns, dbConfig.ConnMaxLifetime)
|
|
Logger.Info("Database connection established successfully.")
|
|
return db, adapter, nil
|
|
}
|
|
|
|
func NewDBWithMigrations(cfg *config.Config, logger *logrus.Logger) (*gorm.DB, dialect.DialectAdapter, error) {
|
|
gormDB, adapter, err := NewDB(cfg, logger)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
if err := migrations.RunVersionedMigrations(gormDB, cfg, logger); err != nil {
|
|
return nil, nil, fmt.Errorf("failed to run versioned migrations: %w", err)
|
|
}
|
|
|
|
return gormDB, adapter, nil
|
|
}
|