package main import ( "database/sql" "fmt" "os" "path/filepath" _ "modernc.org/sqlite" ) func initDB(cfg Config) (*sql.DB, error) { if err := os.MkdirAll(filepath.Dir(cfg.DBPath), 0o755); err != nil { return nil, fmt.Errorf("create data dir: %w", err) } db, err := sql.Open("sqlite", cfg.DBPath) if err != nil { return nil, fmt.Errorf("open sqlite: %w", err) } db.SetMaxOpenConns(1) db.SetMaxIdleConns(1) if _, err := db.Exec(` PRAGMA foreign_keys = ON; PRAGMA journal_mode = WAL; PRAGMA busy_timeout = 5000; `); err != nil { return nil, fmt.Errorf("sqlite pragmas: %w", err) } schema := ` CREATE TABLE IF NOT EXISTS players ( id INTEGER PRIMARY KEY AUTOINCREMENT, name_ar TEXT NOT NULL, name_en TEXT NOT NULL, group_code TEXT NOT NULL DEFAULT '', image_data TEXT NOT NULL DEFAULT '', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS scores ( stage TEXT NOT NULL, player_id INTEGER NOT NULL, score INTEGER NOT NULL DEFAULT 0, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(stage, player_id), FOREIGN KEY(player_id) REFERENCES players(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS score_attachments ( stage TEXT NOT NULL, player_id INTEGER NOT NULL, image_data TEXT NOT NULL DEFAULT '', updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(stage, player_id), FOREIGN KEY(player_id) REFERENCES players(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS app_settings ( key TEXT PRIMARY KEY, value TEXT NOT NULL DEFAULT '', updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); INSERT OR IGNORE INTO app_settings(key, value) VALUES ('view_proof_in_view', '0'); ` if _, err := db.Exec(schema); err != nil { return nil, fmt.Errorf("apply schema: %w", err) } return db, nil }