// Package database wires up GORM against SQLite (WAL mode) and exposes the // auto-migration entry point used at startup. package database import ( "fmt" "path/filepath" "github.com/glebarez/sqlite" "go.uber.org/zap" "gorm.io/gorm" "gorm.io/gorm/logger" "github.com/ShukeBta/MediaStationGo/internal/config" "github.com/ShukeBta/MediaStationGo/internal/model" ) // Open initialises the SQLite database file applying WAL pragmas for // better concurrent read performance — same defaults as nowen-video. func Open(cfg *config.Config, log *zap.Logger) (*gorm.DB, error) { dsn := buildDSN(cfg) gormLogger := logger.New( zapStdLogger{log: log}, logger.Config{ SlowThreshold: 0, LogLevel: logger.Warn, IgnoreRecordNotFoundError: true, Colorful: false, }, ) db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{ Logger: gormLogger, PrepareStmt: true, DisableForeignKeyConstraintWhenMigrating: false, }) if err != nil { return nil, fmt.Errorf("gorm open: %w", err) } sqlDB, err := db.DB() if err != nil { return nil, fmt.Errorf("gorm sqldb: %w", err) } if cfg.Database.MaxOpenConns > 0 { sqlDB.SetMaxOpenConns(cfg.Database.MaxOpenConns) } if cfg.Database.MaxIdleConns > 0 { sqlDB.SetMaxIdleConns(cfg.Database.MaxIdleConns) } return db, nil } func buildDSN(cfg *config.Config) string { dbPath := cfg.Database.DBPath if !filepath.IsAbs(dbPath) { // keep as-is to respect user-provided relative paths. dbPath = filepath.Clean(dbPath) } dsn := dbPath + "?_pragma=foreign_keys(1)" if cfg.Database.WALMode { dsn += "&_pragma=journal_mode(WAL)" } if cfg.Database.BusyTimeout > 0 { dsn += fmt.Sprintf("&_pragma=busy_timeout(%d)", cfg.Database.BusyTimeout) } if cfg.Database.CacheSize != 0 { dsn += fmt.Sprintf("&_pragma=cache_size(%d)", cfg.Database.CacheSize) } return dsn } // AutoMigrate creates tables for every model registered in the model package. func AutoMigrate(db *gorm.DB) error { return db.AutoMigrate(model.AllModels()...) } // zapStdLogger adapts a *zap.Logger to GORM's tiny logger interface. type zapStdLogger struct{ log *zap.Logger } func (z zapStdLogger) Printf(format string, args ...interface{}) { z.log.Sugar().Infof(format, args...) }