Update server/src/db.js
This commit is contained in:
@@ -19,52 +19,58 @@ export async function query(q, params) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// init DB from schema + seed
|
// Initialize DB (schema + seed)
|
||||||
export async function init() {
|
export async function init() {
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
const schema = fs.readFileSync(path.join(__dirname, 'schema.sql'), 'utf8');
|
const schema = fs.readFileSync(path.join(__dirname, 'schema.sql'), 'utf8');
|
||||||
await query(schema);
|
await query(schema);
|
||||||
|
|
||||||
const seed = fs.readFileSync(path.join(__dirname, 'seed.sql'), 'utf8');
|
const seed = fs.readFileSync(path.join(__dirname, 'seed.sql'), 'utf8');
|
||||||
await query(seed);
|
await query(seed);
|
||||||
console.log('DB initialized.');
|
|
||||||
|
console.log('DB initialized (characters + items + inventory).');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Models (simple)
|
/**
|
||||||
|
* Characters model
|
||||||
export const Users = {
|
* - username + passhash live here
|
||||||
|
* - bcrypt provides salt + cost factor per hash
|
||||||
|
*/
|
||||||
|
export const Characters = {
|
||||||
|
// create a new character with username + password
|
||||||
async create(username, password) {
|
async create(username, password) {
|
||||||
const passhash = await bcrypt.hash(password, 10);
|
// bcrypt automatically generates a unique salt for each hash.
|
||||||
|
// You can bump the rounds (12, 14, etc.) if you want more work factor.
|
||||||
|
const saltRounds = 12;
|
||||||
|
const passhash = await bcrypt.hash(password, saltRounds);
|
||||||
|
|
||||||
const { rows } = await query(
|
const { rows } = await query(
|
||||||
'INSERT INTO users (username, passhash) VALUES ($1,$2) RETURNING id, username',
|
'INSERT INTO characters (username, passhash) VALUES ($1,$2) RETURNING id, username, x, y, level, xp',
|
||||||
[username, passhash]
|
[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];
|
return rows[0];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// verify username/password; return character row or null
|
||||||
async verify(username, password) {
|
async verify(username, password) {
|
||||||
const { rows } = await query(
|
const { rows } = await query(
|
||||||
'SELECT * FROM users WHERE username=$1',
|
'SELECT * FROM characters WHERE username=$1',
|
||||||
[username]
|
[username]
|
||||||
);
|
);
|
||||||
if (!rows[0]) return null;
|
const char = rows[0];
|
||||||
const ok = await bcrypt.compare(password, rows[0].passhash);
|
if (!char) return null;
|
||||||
return ok ? rows[0] : null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Characters = {
|
const ok = await bcrypt.compare(password, char.passhash);
|
||||||
async getByUserId(userId) {
|
return ok ? char : null;
|
||||||
const { rows } = await query(
|
},
|
||||||
'SELECT * FROM characters WHERE user_id=$1 LIMIT 1',
|
|
||||||
[userId]
|
async getById(id) {
|
||||||
);
|
const { rows } = await query('SELECT * FROM characters WHERE id=$1', [id]);
|
||||||
return rows[0] || null;
|
return rows[0] || null;
|
||||||
},
|
},
|
||||||
|
|
||||||
async addXP(id, amount) {
|
async addXP(id, amount) {
|
||||||
await query('UPDATE characters SET xp = xp + $1 WHERE id=$2', [amount, id]);
|
await query('UPDATE characters SET xp = xp + $1 WHERE id=$2', [amount, id]);
|
||||||
}
|
}
|
||||||
@@ -78,19 +84,19 @@ export const Inventory = {
|
|||||||
);
|
);
|
||||||
return rows;
|
return rows;
|
||||||
},
|
},
|
||||||
|
|
||||||
async add(characterId, itemKey, qty) {
|
async add(characterId, itemKey, qty) {
|
||||||
// upsert
|
const sql = `
|
||||||
const text = `
|
|
||||||
INSERT INTO inventory (character_id, item_key, qty)
|
INSERT INTO inventory (character_id, item_key, qty)
|
||||||
VALUES ($1,$2,$3)
|
VALUES ($1,$2,$3)
|
||||||
ON CONFLICT (character_id, item_key)
|
ON CONFLICT (character_id, item_key)
|
||||||
DO UPDATE SET qty = inventory.qty + EXCLUDED.qty
|
DO UPDATE SET qty = inventory.qty + EXCLUDED.qty
|
||||||
`;
|
`;
|
||||||
await query(text, [characterId, itemKey, qty]);
|
await query(sql, [characterId, itemKey, qty]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// allow manual init: node src/db.js init
|
// allow: node src/db.js init
|
||||||
if (process.argv[2] === 'init') {
|
if (process.argv[2] === 'init') {
|
||||||
init()
|
init()
|
||||||
.then(() => process.exit(0))
|
.then(() => process.exit(0))
|
||||||
|
|||||||
Reference in New Issue
Block a user