134 lines
5.4 KiB
TypeScript
134 lines
5.4 KiB
TypeScript
import Database, { Database as DatabaseType } from 'better-sqlite3';
|
|
import { readFileSync, mkdirSync } from 'fs';
|
|
import { dirname, join } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const DB_PATH = process.env.DATABASE_PATH || join(__dirname, '../../../data/kaboot.db');
|
|
|
|
mkdirSync(dirname(DB_PATH), { recursive: true });
|
|
|
|
export const db: DatabaseType = new Database(DB_PATH);
|
|
|
|
db.pragma('journal_mode = WAL');
|
|
db.pragma('foreign_keys = ON');
|
|
|
|
const schema = readFileSync(join(__dirname, 'schema.sql'), 'utf-8');
|
|
db.exec(schema);
|
|
|
|
const runMigrations = () => {
|
|
const tableInfo = db.prepare("PRAGMA table_info(quizzes)").all() as { name: string }[];
|
|
const hasGameConfig = tableInfo.some(col => col.name === 'game_config');
|
|
|
|
if (!hasGameConfig) {
|
|
db.exec("ALTER TABLE quizzes ADD COLUMN game_config TEXT");
|
|
console.log("Migration: Added game_config to quizzes");
|
|
}
|
|
|
|
const userTableInfo = db.prepare("PRAGMA table_info(users)").all() as { name: string }[];
|
|
const hasDefaultConfig = userTableInfo.some(col => col.name === 'default_game_config');
|
|
|
|
if (!hasDefaultConfig) {
|
|
db.exec("ALTER TABLE users ADD COLUMN default_game_config TEXT");
|
|
console.log("Migration: Added default_game_config to users");
|
|
}
|
|
|
|
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='game_sessions'").get();
|
|
if (!tables) {
|
|
db.exec(`
|
|
CREATE TABLE game_sessions (
|
|
pin TEXT PRIMARY KEY,
|
|
host_peer_id TEXT NOT NULL,
|
|
host_secret TEXT NOT NULL,
|
|
quiz_data TEXT NOT NULL,
|
|
game_config TEXT NOT NULL,
|
|
game_state TEXT NOT NULL DEFAULT 'LOBBY',
|
|
current_question_index INTEGER NOT NULL DEFAULT 0,
|
|
players_data TEXT NOT NULL DEFAULT '[]',
|
|
first_correct_player_id TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
CREATE INDEX idx_game_sessions_updated ON game_sessions(updated_at);
|
|
`);
|
|
console.log("Migration: Created game_sessions table");
|
|
}
|
|
|
|
const sessionTableInfo = db.prepare("PRAGMA table_info(game_sessions)").all() as { name: string }[];
|
|
const hasFirstCorrect = sessionTableInfo.some(col => col.name === "first_correct_player_id");
|
|
if (!hasFirstCorrect) {
|
|
db.exec("ALTER TABLE game_sessions ADD COLUMN first_correct_player_id TEXT");
|
|
console.log("Migration: Added first_correct_player_id to game_sessions");
|
|
}
|
|
|
|
const userTableInfo2 = db.prepare("PRAGMA table_info(users)").all() as { name: string }[];
|
|
const hasColorScheme = userTableInfo2.some(col => col.name === "color_scheme");
|
|
if (!hasColorScheme) {
|
|
db.exec("ALTER TABLE users ADD COLUMN color_scheme TEXT DEFAULT 'blue'");
|
|
console.log("Migration: Added color_scheme to users");
|
|
}
|
|
const hasGeminiKey = userTableInfo2.some(col => col.name === "gemini_api_key");
|
|
if (!hasGeminiKey) {
|
|
db.exec("ALTER TABLE users ADD COLUMN gemini_api_key TEXT");
|
|
console.log("Migration: Added gemini_api_key to users");
|
|
}
|
|
|
|
const hasAiProvider = userTableInfo2.some(col => col.name === "ai_provider");
|
|
if (!hasAiProvider) {
|
|
db.exec("ALTER TABLE users ADD COLUMN ai_provider TEXT DEFAULT 'gemini'");
|
|
console.log("Migration: Added ai_provider to users");
|
|
}
|
|
|
|
const hasOpenRouterKey = userTableInfo2.some(col => col.name === "openrouter_api_key");
|
|
if (!hasOpenRouterKey) {
|
|
db.exec("ALTER TABLE users ADD COLUMN openrouter_api_key TEXT");
|
|
console.log("Migration: Added openrouter_api_key to users");
|
|
}
|
|
|
|
const hasOpenRouterModel = userTableInfo2.some(col => col.name === "openrouter_model");
|
|
if (!hasOpenRouterModel) {
|
|
db.exec("ALTER TABLE users ADD COLUMN openrouter_model TEXT");
|
|
console.log("Migration: Added openrouter_model to users");
|
|
}
|
|
|
|
const hasOpenAIKey = userTableInfo2.some(col => col.name === "openai_api_key");
|
|
if (!hasOpenAIKey) {
|
|
db.exec("ALTER TABLE users ADD COLUMN openai_api_key TEXT");
|
|
console.log("Migration: Added openai_api_key to users");
|
|
}
|
|
|
|
const hasOpenAIModel = userTableInfo2.some(col => col.name === "openai_model");
|
|
if (!hasOpenAIModel) {
|
|
db.exec("ALTER TABLE users ADD COLUMN openai_model TEXT");
|
|
console.log("Migration: Added openai_model to users");
|
|
}
|
|
|
|
const hasGeminiModel = userTableInfo2.some(col => col.name === "gemini_model");
|
|
if (!hasGeminiModel) {
|
|
db.exec("ALTER TABLE users ADD COLUMN gemini_model TEXT");
|
|
console.log("Migration: Added gemini_model to users");
|
|
}
|
|
|
|
const quizTableInfo = db.prepare("PRAGMA table_info(quizzes)").all() as { name: string }[];
|
|
const hasShareToken = quizTableInfo.some(col => col.name === "share_token");
|
|
if (!hasShareToken) {
|
|
db.exec("ALTER TABLE quizzes ADD COLUMN share_token TEXT");
|
|
console.log("Migration: Added share_token to quizzes");
|
|
}
|
|
|
|
const hasIsShared = quizTableInfo.some(col => col.name === "is_shared");
|
|
if (!hasIsShared) {
|
|
db.exec("ALTER TABLE quizzes ADD COLUMN is_shared INTEGER DEFAULT 0");
|
|
console.log("Migration: Added is_shared to quizzes");
|
|
}
|
|
|
|
const shareTokenIndex = db.prepare("SELECT name FROM sqlite_master WHERE type='index' AND name='idx_quizzes_share_token'").get();
|
|
if (!shareTokenIndex) {
|
|
db.exec("CREATE UNIQUE INDEX idx_quizzes_share_token ON quizzes(share_token)");
|
|
console.log("Migration: Created unique index on quizzes.share_token");
|
|
}
|
|
};
|
|
|
|
runMigrations();
|
|
|
|
console.log(`Database initialized at ${DB_PATH}`);
|