package database import ( "fmt" "os" "path/filepath" "sync" "time" "go.uber.org/zap" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" "uzdb/internal/config" "uzdb/internal/models" ) var ( sqliteDB *gorm.DB sqliteMu sync.RWMutex ) // InitSQLite initializes the SQLite database for application data func InitSQLite(dbPath string, cfg *config.DatabaseConfig) (*gorm.DB, error) { sqliteMu.Lock() defer sqliteMu.Unlock() // Ensure directory exists dir := filepath.Dir(dbPath) if err := os.MkdirAll(dir, 0755); err != nil { return nil, fmt.Errorf("failed to create database directory: %w", err) } // Configure GORM logger var gormLogger logger.Interface if config.Get().IsDevelopment() { gormLogger = logger.Default.LogMode(logger.Info) } else { gormLogger = logger.Default.LogMode(logger.Silent) } // Open SQLite connection db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{ Logger: gormLogger, }) if err != nil { return nil, fmt.Errorf("failed to open SQLite database: %w", err) } // Set connection pool settings sqlDB, err := db.DB() if err != nil { return nil, fmt.Errorf("failed to get underlying DB: %w", err) } sqlDB.SetMaxOpenConns(cfg.MaxOpenConns) sqlDB.SetMaxIdleConns(cfg.MaxIdleConns) sqlDB.SetConnMaxLifetime(time.Duration(cfg.MaxLifetime) * time.Minute) // Enable WAL mode for better concurrency if err := db.Exec("PRAGMA journal_mode=WAL").Error; err != nil { config.GetLogger().Warn("failed to enable WAL mode", zap.Error(err)) } // Run migrations if err := runMigrations(db); err != nil { return nil, fmt.Errorf("migration failed: %w", err) } sqliteDB = db config.GetLogger().Info("SQLite database initialized", zap.String("path", dbPath), zap.Int("max_open_conns", cfg.MaxOpenConns), zap.Int("max_idle_conns", cfg.MaxIdleConns), ) return db, nil } // runMigrations runs database migrations func runMigrations(db *gorm.DB) error { migrations := []interface{}{ &models.UserConnection{}, &models.QueryHistory{}, &models.SavedQuery{}, } for _, model := range migrations { if err := db.AutoMigrate(model); err != nil { return fmt.Errorf("failed to migrate %T: %w", model, err) } } config.GetLogger().Info("database migrations completed") return nil } // GetSQLiteDB returns the SQLite database instance func GetSQLiteDB() *gorm.DB { sqliteMu.RLock() defer sqliteMu.RUnlock() return sqliteDB } // CloseSQLite closes the SQLite database connection func CloseSQLite() error { sqliteMu.Lock() defer sqliteMu.Unlock() if sqliteDB == nil { return nil } sqlDB, err := sqliteDB.DB() if err != nil { return err } if err := sqlDB.Close(); err != nil { return fmt.Errorf("failed to close SQLite database: %w", err) } sqliteDB = nil config.GetLogger().Info("SQLite database closed") return nil }