Add server/src/db.js

This commit is contained in:
2025-11-13 15:30:16 +00:00
parent ac55ae3ff2
commit bd1326f466

101
server/src/db.js Normal file
View File

@@ -0,0 +1,101 @@
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import pg from 'pg';
import bcrypt from 'bcryptjs';
const { Pool } = pg;
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
export async function query(q, params) {
const client = await pool.connect();
try {
return await client.query(q, params);
} finally {
client.release();
}
}
// init DB from schema + seed
export async function init() {
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const schema = fs.readFileSync(path.join(__dirname, 'schema.sql'), 'utf8');
await query(schema);
const seed = fs.readFileSync(path.join(__dirname, 'seed.sql'), 'utf8');
await query(seed);
console.log('DB initialized.');
}
// Models (simple)
export const Users = {
async create(username, password) {
const passhash = await bcrypt.hash(password, 10);
const { rows } = await query(
'INSERT INTO users (username, passhash) VALUES ($1,$2) RETURNING id, username',
[username, passhash]
);
// create character with same name
await query(
'INSERT INTO characters (user_id, name) VALUES ($1,$2)',
[rows[0].id, username]
);
return rows[0];
},
async verify(username, password) {
const { rows } = await query(
'SELECT * FROM users WHERE username=$1',
[username]
);
if (!rows[0]) return null;
const ok = await bcrypt.compare(password, rows[0].passhash);
return ok ? rows[0] : null;
}
};
export const Characters = {
async getByUserId(userId) {
const { rows } = await query(
'SELECT * FROM characters WHERE user_id=$1 LIMIT 1',
[userId]
);
return rows[0] || null;
},
async addXP(id, amount) {
await query('UPDATE characters SET xp = xp + $1 WHERE id=$2', [amount, id]);
}
};
export const Inventory = {
async all(characterId) {
const { rows } = await query(
'SELECT item_key, qty FROM inventory WHERE character_id=$1',
[characterId]
);
return rows;
},
async add(characterId, itemKey, qty) {
// upsert
const text = `
INSERT INTO inventory (character_id, item_key, qty)
VALUES ($1,$2,$3)
ON CONFLICT (character_id, item_key)
DO UPDATE SET qty = inventory.qty + EXCLUDED.qty
`;
await query(text, [characterId, itemKey, qty]);
}
};
// allow manual init: node src/db.js init
if (process.argv[2] === 'init') {
init()
.then(() => process.exit(0))
.catch(e => {
console.error(e);
process.exit(1);
});
}