monquigrid/database/init.js
2025-07-16 23:56:37 +00:00

224 lines
No EOL
7.2 KiB
JavaScript

const sqlite3 = require('sqlite3').verbose();
const fs = require('fs');
const path = require('path');
class DatabaseManager {
constructor(dbPath = './database/gridbattle.db') {
this.dbPath = dbPath;
this.db = null;
}
async initialize() {
console.log('Initializing Grid Battle database...');
try {
// Ensure database directory exists
const dbDir = path.dirname(this.dbPath);
if (!fs.existsSync(dbDir)) {
fs.mkdirSync(dbDir, { recursive: true });
}
// Open database connection
this.db = new sqlite3.Database(this.dbPath, (err) => {
if (err) {
console.error('Error opening database:', err.message);
throw err;
}
console.log('Connected to SQLite database:', this.dbPath);
});
// Enable foreign keys
await this.runQuery('PRAGMA foreign_keys = ON');
// Load and execute schema
const schemaPath = path.join(__dirname, 'schema.sql');
const schema = fs.readFileSync(schemaPath, 'utf8');
// Split schema into individual statements
const statements = schema.split(';').filter(stmt => stmt.trim().length > 0);
for (const statement of statements) {
await this.runQuery(statement);
}
console.log('Database schema initialized successfully');
// Insert default data if needed
await this.insertDefaultData();
return this.db;
} catch (error) {
console.error('Database initialization failed:', error);
throw error;
}
}
async insertDefaultData() {
// Check if we need to insert any default data
const playerCount = await this.getScalar('SELECT COUNT(*) FROM players');
if (playerCount === 0) {
console.log('Inserting default test data...');
// Insert test players for development
await this.runQuery(`
INSERT INTO players (id, username, games_played, games_won, skill_rating)
VALUES
('test-player-1', 'TestPlayer1', 5, 3, 1150),
('test-player-2', 'TestPlayer2', 4, 1, 950),
('test-player-3', 'GridMaster', 10, 8, 1300)
`);
console.log('Default test data inserted');
}
}
// Promisified database operations
runQuery(sql, params = []) {
return new Promise((resolve, reject) => {
this.db.run(sql, params, function(err) {
if (err) {
console.error('Database query error:', err.message);
console.error('SQL:', sql);
reject(err);
} else {
resolve({ lastID: this.lastID, changes: this.changes });
}
});
});
}
getRow(sql, params = []) {
return new Promise((resolve, reject) => {
this.db.get(sql, params, (err, row) => {
if (err) {
console.error('Database query error:', err.message);
reject(err);
} else {
resolve(row);
}
});
});
}
getAllRows(sql, params = []) {
return new Promise((resolve, reject) => {
this.db.all(sql, params, (err, rows) => {
if (err) {
console.error('Database query error:', err.message);
reject(err);
} else {
resolve(rows);
}
});
});
}
getScalar(sql, params = []) {
return new Promise((resolve, reject) => {
this.db.get(sql, params, (err, row) => {
if (err) {
console.error('Database query error:', err.message);
reject(err);
} else {
// Return the first column value
const value = row ? Object.values(row)[0] : null;
resolve(value);
}
});
});
}
async close() {
return new Promise((resolve, reject) => {
if (this.db) {
this.db.close((err) => {
if (err) {
reject(err);
} else {
console.log('Database connection closed');
resolve();
}
});
} else {
resolve();
}
});
}
// Helper methods for common operations
async createPlayer(username, email = null) {
const { v4: uuidv4 } = require('uuid');
const playerId = uuidv4();
await this.runQuery(`
INSERT INTO players (id, username, email)
VALUES (?, ?, ?)
`, [playerId, username, email]);
return playerId;
}
async createGame(gameMode = 'standard', tournamentId = null) {
const { v4: uuidv4 } = require('uuid');
const gameId = uuidv4();
await this.runQuery(`
INSERT INTO games (id, game_mode, tournament_id)
VALUES (?, ?, ?)
`, [gameId, gameMode, tournamentId]);
return gameId;
}
async addPlayerToGame(gameId, playerId, playerNumber, spawnX, spawnY) {
await this.runQuery(`
INSERT INTO game_players (game_id, player_id, player_number, spawn_x, spawn_y, current_x, current_y)
VALUES (?, ?, ?, ?, ?, ?, ?)
`, [gameId, playerId, playerNumber, spawnX, spawnY, spawnX, spawnY]);
}
async logGameEvent(gameId, turnNumber, sequenceNumber, eventType, playerId, eventData = {}) {
await this.runQuery(`
INSERT INTO game_events (game_id, turn_number, sequence_number, event_type, player_id,
from_x, from_y, to_x, to_y, event_data)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`, [
gameId, turnNumber, sequenceNumber, eventType, playerId,
eventData.from_x || null, eventData.from_y || null,
eventData.to_x || null, eventData.to_y || null,
JSON.stringify(eventData)
]);
}
async getGameState(gameId) {
const game = await this.getRow('SELECT * FROM games WHERE id = ?', [gameId]);
if (!game) return null;
const players = await this.getAllRows(`
SELECT gp.*, p.username
FROM game_players gp
JOIN players p ON gp.player_id = p.id
WHERE gp.game_id = ?
ORDER BY gp.player_number
`, [gameId]);
return { game, players };
}
async getLeaderboard(limit = 10) {
return await this.getAllRows(`
SELECT * FROM leaderboard LIMIT ?
`, [limit]);
}
async getGameHistory(gameId) {
return await this.getAllRows(`
SELECT * FROM game_events
WHERE game_id = ?
ORDER BY turn_number, sequence_number
`, [gameId]);
}
}
module.exports = DatabaseManager;