// Filename: internal/db/db.go package db import ( "gemini-balancer/internal/config" "gemini-balancer/internal/db/dialect" 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 }