// copied from one of my older projects import { createPool } from 'mysql2/promise'; function getEnvVar(name) { const value = process.env[name]; if (value == null) { throw new Error(`Environment variable ${name} is not defined`); } return value; } const pool = createPool({ host: getEnvVar('MYSQL_HOST'), user: getEnvVar('MYSQL_USER'), password: getEnvVar('MYSQL_PASSWORD'), database: getEnvVar('MYSQL_DB'), }); const migrations = [ { name: "init", up: async (conn) => { await conn.query(` CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(64) NOT NULL UNIQUE ) `); // max length is double the actual max length cause of unicode stuff await conn.query(` CREATE TABLE games ( id INT PRIMARY KEY AUTO_INCREMENT, winner INT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (winner) REFERENCES users(id) ) `); await conn.query(` CREATE TABLE current_games ( id INT PRIMARY KEY AUTO_INCREMENT, is_open BOOL, is_local BOOL, current_playing_user INT, turn_order JSON DEFAULT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (current_playing_user) REFERENCES users(id) ) `); await conn.query(` CREATE TABLE game_players ( id INT PRIMARY KEY AUTO_INCREMENT, game INT, user INT, is_creator BOOL, FOREIGN KEY (game) REFERENCES current_games(id), FOREIGN KEY (user) REFERENCES users(id) ) `) await conn.query(` CREATE TABLE turns ( id INT PRIMARY KEY AUTO_INCREMENT, game INT, user INT, round_number INT, start_points INT, first_throw INT, second_throw INT, third_throw INT, end_points INT, FOREIGN KEY (game) REFERENCES current_games(id), FOREIGN KEY (user) REFERENCES users(id) ) `) } } ]; async function initDB() { await pool.query(` CREATE TABLE IF NOT EXISTS migrations ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL UNIQUE ); `); for (const m of migrations) { const conn = await pool.getConnection(); try { await conn.beginTransaction(); const [rows] = await conn.query( `SELECT 1 FROM migrations WHERE name = ? LIMIT 1 FOR UPDATE`, [m.name] ); if (rows.length === 0) { console.log(`Running migration: ${m.name}`); await m.up(conn); await conn.query(`INSERT INTO migrations (name) VALUES (?)`, [m.name]); } await conn.commit(); } catch (err) { await conn.rollback(); throw err; } finally { conn.release(); } } } export { pool, initDB };