Add server/src/db.js
This commit is contained in:
101
server/src/db.js
Normal file
101
server/src/db.js
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user