const sqlite3 = require('sqlite3').verbose(); const path = require('path'); const dbPath = path.join(__dirname, '..', 'step_competition.db'); const db = new sqlite3.Database(dbPath); // Initialize database schema function initializeDatabase() { db.serialize(() => { // Teams table db.run(` CREATE TABLE IF NOT EXISTS teams ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) `); // Participants table db.run(` CREATE TABLE IF NOT EXISTS participants ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE, team_id INTEGER NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (team_id) REFERENCES teams(id) ) `); // Daily steps table db.run(` CREATE TABLE IF NOT EXISTS daily_steps ( id INTEGER PRIMARY KEY AUTOINCREMENT, participant_id INTEGER NOT NULL, date DATE NOT NULL, steps INTEGER NOT NULL DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (participant_id) REFERENCES participants(id), UNIQUE(participant_id, date) ) `); // Daily monsters table db.run(` CREATE TABLE IF NOT EXISTS daily_monsters ( id INTEGER PRIMARY KEY AUTOINCREMENT, date DATE NOT NULL UNIQUE, monster_name TEXT NOT NULL, monster_description TEXT, step_goal INTEGER NOT NULL, monster_icon TEXT DEFAULT '👹', created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) `); // Monster catches view - derived from actual step data // Drop the old table if it exists and recreate as a view db.run(`DROP TABLE IF EXISTS monster_catches`); db.run(` CREATE VIEW IF NOT EXISTS monster_catches AS SELECT dm.id as monster_id, dm.date, t.id as team_id, t.name as team_name, COALESCE(SUM(ds.steps), 0) as final_steps, dm.step_goal FROM daily_monsters dm CROSS JOIN teams t LEFT JOIN participants p ON t.id = p.team_id LEFT JOIN daily_steps ds ON p.id = ds.participant_id AND ds.date = dm.date GROUP BY dm.id, dm.date, t.id, t.name, dm.step_goal HAVING final_steps >= dm.step_goal `); // Create indexes for better query performance db.run(`CREATE INDEX IF NOT EXISTS idx_daily_steps_date ON daily_steps(date)`); db.run(`CREATE INDEX IF NOT EXISTS idx_daily_steps_participant ON daily_steps(participant_id)`); db.run(`CREATE INDEX IF NOT EXISTS idx_participants_team ON participants(team_id)`); db.run(`CREATE INDEX IF NOT EXISTS idx_daily_monsters_date ON daily_monsters(date)`); console.log('Database initialized successfully'); }); } // Helper function to run queries with promises function runQuery(sql, params = []) { return new Promise((resolve, reject) => { db.run(sql, params, function(err) { if (err) reject(err); else resolve({ id: this.lastID, changes: this.changes }); }); }); } function getQuery(sql, params = []) { return new Promise((resolve, reject) => { db.get(sql, params, (err, row) => { if (err) reject(err); else resolve(row); }); }); } function allQuery(sql, params = []) { return new Promise((resolve, reject) => { db.all(sql, params, (err, rows) => { if (err) reject(err); else resolve(rows); }); }); } module.exports = { db, initializeDatabase, runQuery, getQuery, allQuery };