Files
dwroller/database/sqlite-db.js
2025-08-15 10:35:27 +02:00

191 lines
5.3 KiB
JavaScript

const Database = require('better-sqlite3');
const path = require('path');
const fs = require('fs');
// Create database directory if it doesn't exist
const dbDir = path.join(__dirname, 'sqlite');
if (!fs.existsSync(dbDir)) {
fs.mkdirSync(dbDir, { recursive: true });
}
const dbPath = path.join(dbDir, 'deathwatch.db');
const db = new Database(dbPath);
// Enable WAL mode for better concurrency
db.pragma('journal_mode = WAL');
// Create tables
const createTables = () => {
// Players table
db.exec(`
CREATE TABLE IF NOT EXISTS players (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
roller_info TEXT DEFAULT '{}',
shop_info TEXT DEFAULT '{}',
tab_info TEXT DEFAULT '{}',
pw TEXT DEFAULT '',
pw_hash TEXT DEFAULT '',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
// Sessions table (if you need it)
db.exec(`
CREATE TABLE IF NOT EXISTS sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT UNIQUE NOT NULL,
data TEXT DEFAULT '{}',
expires_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
// Create indexes for better performance
db.exec(`
CREATE INDEX IF NOT EXISTS idx_players_name ON players(name);
CREATE INDEX IF NOT EXISTS idx_sessions_session_id ON sessions(session_id);
CREATE INDEX IF NOT EXISTS idx_sessions_expires_at ON sessions(expires_at);
`);
console.log('SQLite tables created successfully');
};
// Initialize database
createTables();
// Prepared statements for common operations
const statements = {
// Player operations
getAllPlayers: db.prepare('SELECT * FROM players ORDER BY name'),
getPlayerByName: db.prepare('SELECT * FROM players WHERE name = ?'),
insertPlayer: db.prepare(`
INSERT INTO players (name, roller_info, shop_info, tab_info, pw, pw_hash)
VALUES (?, ?, ?, ?, ?, ?)
`),
updatePlayer: db.prepare(`
UPDATE players
SET roller_info = ?, shop_info = ?, tab_info = ?, pw = ?, pw_hash = ?, updated_at = CURRENT_TIMESTAMP
WHERE name = ?
`),
deletePlayer: db.prepare('DELETE FROM players WHERE name = ?'),
// Session operations
getSession: db.prepare('SELECT * FROM sessions WHERE session_id = ? AND expires_at > datetime(\'now\')'),
insertSession: db.prepare(`
INSERT INTO sessions (session_id, data, expires_at)
VALUES (?, ?, ?)
`),
updateSession: db.prepare(`
UPDATE sessions
SET data = ?, expires_at = ?, updated_at = CURRENT_TIMESTAMP
WHERE session_id = ?
`),
deleteSession: db.prepare('DELETE FROM sessions WHERE session_id = ?'),
cleanExpiredSessions: db.prepare('DELETE FROM sessions WHERE expires_at <= datetime(\'now\')')
};
// Helper functions
const playerHelpers = {
getAll: () => {
const rows = statements.getAllPlayers.all();
return rows.map(row => ({
name: row.name,
rollerInfo: JSON.parse(row.roller_info || '{}'),
shopInfo: JSON.parse(row.shop_info || '{}'),
tabInfo: JSON.parse(row.tab_info || '{}'),
pw: row.pw,
pwHash: row.pw_hash,
_id: row.id,
createdAt: row.created_at,
updatedAt: row.updated_at
}));
},
getByName: (name) => {
const row = statements.getPlayerByName.get(name);
if (!row) return null;
return {
name: row.name,
rollerInfo: JSON.parse(row.roller_info || '{}'),
shopInfo: JSON.parse(row.shop_info || '{}'),
tabInfo: JSON.parse(row.tab_info || '{}'),
pw: row.pw,
pwHash: row.pw_hash,
_id: row.id,
createdAt: row.created_at,
updatedAt: row.updated_at
};
},
create: (playerData) => {
const result = statements.insertPlayer.run(
playerData.name,
JSON.stringify(playerData.rollerInfo || {}),
JSON.stringify(playerData.shopInfo || {}),
JSON.stringify(playerData.tabInfo || {}),
playerData.pw || '',
playerData.pwHash || ''
);
return { ...playerData, _id: result.lastInsertRowid };
},
update: (name, playerData) => {
const result = statements.updatePlayer.run(
JSON.stringify(playerData.rollerInfo || {}),
JSON.stringify(playerData.shopInfo || {}),
JSON.stringify(playerData.tabInfo || {}),
playerData.pw || '',
playerData.pwHash || '',
name
);
return result.changes > 0;
},
delete: (name) => {
const result = statements.deletePlayer.run(name);
return result.changes > 0;
}
};
const sessionHelpers = {
get: (sessionId) => {
const row = statements.getSession.get(sessionId);
if (!row) return null;
return {
sessionId: row.session_id,
data: JSON.parse(row.data || '{}'),
expiresAt: row.expires_at
};
},
create: (sessionId, data, expiresAt) => {
statements.insertSession.run(sessionId, JSON.stringify(data), expiresAt);
},
update: (sessionId, data, expiresAt) => {
const result = statements.updateSession.run(JSON.stringify(data), expiresAt, sessionId);
return result.changes > 0;
},
delete: (sessionId) => {
const result = statements.deleteSession.run(sessionId);
return result.changes > 0;
},
cleanExpired: () => {
const result = statements.cleanExpiredSessions.run();
return result.changes;
}
};
module.exports = {
db,
statements,
playerHelpers,
sessionHelpers,
close: () => db.close()
};