100 lines
3.4 KiB
TypeScript
100 lines
3.4 KiB
TypeScript
import type { GameState } from './state.js';
|
|
|
|
/**
|
|
* Thin game DB initializer / accessor.
|
|
* This currently returns the underlying db module (for runtime compatibility)
|
|
* and is the single place to add typed helper methods for game persistence.
|
|
*/
|
|
export async function initGameDB(): Promise<any> {
|
|
// dynamic import to preserve original runtime ordering
|
|
// path is relative to this file (routes/games)
|
|
// Prefer synchronous require at runtime when available to avoid TS module resolution
|
|
// issues during type-checking. Declare require to keep TypeScript happy.
|
|
let mod: any;
|
|
try {
|
|
mod = (globalThis as any).require('../db/games');
|
|
} catch (e) {
|
|
// If require isn't available (very unusual in our Node container),
|
|
// return a safe no-op DB object rather than attempting a dynamic import.
|
|
// This keeps runtime behavior unchanged in the normal case and avoids
|
|
// needing // @ts-ignore for module resolution during type-checking.
|
|
return {
|
|
sequelize: undefined,
|
|
Sequelize: undefined,
|
|
getGameById: async (_id: string | number) => null,
|
|
saveGameState: async (_id: string | number, _state: GameState) => { /* no-op */ },
|
|
deleteGame: async (_id: string | number) => { /* no-op */ }
|
|
} as any;
|
|
}
|
|
// If the module uses default export, prefer it
|
|
const db = (mod && (mod.default || mod));
|
|
|
|
// attach typed helper placeholders (will be implemented incrementally)
|
|
if (!db.getGameById) {
|
|
db.getGameById = async (id: string | number): Promise<GameState | null> => {
|
|
// fallback: try to query by id using raw SQL if sequelize is available
|
|
if (db && db.sequelize) {
|
|
try {
|
|
const rows = await db.sequelize.query('SELECT state FROM games WHERE id=:id', {
|
|
replacements: { id },
|
|
type: db.Sequelize.QueryTypes.SELECT
|
|
});
|
|
if (rows && rows.length) {
|
|
const r = rows[0] as any;
|
|
// state may be stored as text or JSON
|
|
if (typeof r.state === 'string') {
|
|
try {
|
|
return JSON.parse(r.state) as GameState;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
return r.state as GameState;
|
|
}
|
|
} catch (e) {
|
|
// ignore and fallthrough
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
}
|
|
|
|
if (!db.saveGameState) {
|
|
db.saveGameState = async (id: string | number, state: GameState): Promise<void> => {
|
|
if (db && db.sequelize) {
|
|
const payload = JSON.stringify(state);
|
|
try {
|
|
await db.sequelize.query('UPDATE games SET state=:state WHERE id=:id', {
|
|
replacements: { id, state: payload }
|
|
});
|
|
} catch (e) {
|
|
// if update failed, attempt insert
|
|
try {
|
|
await db.sequelize.query('INSERT INTO games (id, state) VALUES(:id, :state)', {
|
|
replacements: { id, state: payload }
|
|
});
|
|
} catch (err) {
|
|
// swallow; callers should handle missing persistence
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
if (!db.deleteGame) {
|
|
db.deleteGame = async (id: string | number): Promise<void> => {
|
|
if (db && db.sequelize) {
|
|
try {
|
|
await db.sequelize.query('DELETE FROM games WHERE id=:id', {
|
|
replacements: { id }
|
|
});
|
|
} catch (e) {
|
|
// swallow errors; callers will rely on fallback behavior
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
return db;
|
|
}
|