Merge pull request #6 from kobolol/codex/update-database-connection-handling

Refactor database connections to use per-query instances
This commit is contained in:
Jonas
2025-11-21 23:15:42 +01:00
committed by GitHub
3 changed files with 143 additions and 92 deletions

View File

@@ -5,23 +5,28 @@ require("dotenv").config();
class DataBaseManager { class DataBaseManager {
constructor(host, database) { constructor(host, database) {
this.connection = mySql.createConnection({ this.connectionConfig = {
host: host, host: host,
port: process.env.DB_PORT || 3306, port: process.env.DB_PORT || 3306,
user: "root", user: "root",
password: process.env.DB_PASSWORD || undefined, password: process.env.DB_PASSWORD || undefined,
database: database database: database
}); };
this.connection.connect((err) => { const connectionFactory = () => this.createConnection();
if (err) {
throw err;
this.usermanager = new UserManager(connectionFactory);
this.scoremanager = new ScoreManager(connectionFactory);
} }
createConnection() {
const connection = mySql.createConnection(this.connectionConfig);
connection.on("error", (error) => {
console.error("Database connection error:", error);
}); });
this.usermanager = new UserManager(this.connection); return connection;
this.scoremanager = new ScoreManager(this.connection);
} }
} }

View File

@@ -2,42 +2,59 @@ const mySql = require("mysql2");
const Score = require("./Score"); const Score = require("./Score");
class ScoreManager{ class ScoreManager{
/**@param {mySql.Connection} connection*/ /**@param {() => mySql.Connection} connectionFactory*/
constructor(connection) { constructor(connectionFactory) {
this.connection = connection; this.connectionFactory = connectionFactory;
this.splitLimit = 25; this.splitLimit = 25;
} }
async withConnection(callback) {
const connection = this.connectionFactory();
try {
return await callback(connection);
}
finally {
connection.end();
}
}
async getAllScores(){ async getAllScores(){
const response = await this.connection.promise().query("SELECT * FROM scores ORDER BY score DESC"); return await this.withConnection(async (connection) => {
const response = await connection.promise().query("SELECT * FROM scores ORDER BY score DESC");
const sortedScores = response[0].map((scoreData, index) => new Score(scoreData, index + 1)); const sortedScores = response[0].map((scoreData, index) => new Score(scoreData, index + 1));
return sortedScores; return sortedScores;
});
} }
async createScore(newScoreJson){ async createScore(newScoreJson){
return await this.withConnection(async (connection) => {
const sql = "INSERT INTO scores (user1, user2, score) VALUES (?, ?, ?)"; const sql = "INSERT INTO scores (user1, user2, score) VALUES (?, ?, ?)";
const insertResult = await this.connection const insertResult = await connection
.promise() .promise()
.query(sql, [newScoreJson.user1, newScoreJson.user2, newScoreJson.score]); .query(sql, [newScoreJson.user1, newScoreJson.user2, newScoreJson.score]);
const insertId = insertResult[0].insertId; const insertId = insertResult[0].insertId;
const selectSql = "SELECT * FROM scores WHERE id = ?"; const selectSql = "SELECT * FROM scores WHERE id = ?";
const selectResult = await this.connection.promise().query(selectSql, [insertId]); const selectResult = await connection.promise().query(selectSql, [insertId]);
const rank = await this.getRankById(insertId); const rank = await this.getRankById(insertId);
return new Score(selectResult[0][0], rank); return new Score(selectResult[0][0], rank);
});
} }
async getScoreById(id){ async getScoreById(id){
const response = await this.connection.promise().query("SELECT * FROM scores WHERE id = ?", [id]); return await this.withConnection(async (connection) => {
const response = await connection.promise().query("SELECT * FROM scores WHERE id = ?", [id]);
const rank = await this.getRankById(id); const rank = await this.getRankById(id);
return new Score(response[0][0], rank); return new Score(response[0][0], rank);
});
} }
async getSplitedScoreCount(){ async getSplitedScoreCount(){
@@ -51,7 +68,8 @@ class ScoreManager{
async getSpiltedScore(count){ async getSpiltedScore(count){
const offset = (count - 1) * this.splitLimit; const offset = (count - 1) * this.splitLimit;
const response = await this.connection.promise().query( return await this.withConnection(async (connection) => {
const response = await connection.promise().query(
`SELECT * FROM scores ORDER BY score DESC LIMIT ${this.splitLimit} OFFSET ${offset}`, `SELECT * FROM scores ORDER BY score DESC LIMIT ${this.splitLimit} OFFSET ${offset}`,
); );
@@ -61,16 +79,19 @@ class ScoreManager{
}); });
return sortedScoreSplit; return sortedScoreSplit;
});
} }
async getRankById(id){ async getRankById(id){
return await this.withConnection(async (connection) => {
const rankSql = const rankSql =
"SELECT COUNT(*) + 1 AS rank_position FROM scores WHERE score > (SELECT score FROM scores WHERE id = ?)"; "SELECT COUNT(*) + 1 AS rank_position FROM scores WHERE score > (SELECT score FROM scores WHERE id = ?)";
const rankResult = await this.connection.promise().query(rankSql, [id]); const rankResult = await connection.promise().query(rankSql, [id]);
const rank = rankResult[0][0]?.rank_position ?? null; const rank = rankResult[0][0]?.rank_position ?? null;
return rank; return rank;
});
} }
} }

View File

@@ -3,9 +3,20 @@ const bcrypt = require("bcrypt")
const User = require("./User") const User = require("./User")
class UserManager { class UserManager {
/**@param {mySql.Connection} connection*/ /**@param {() => mySql.Connection} connectionFactory*/
constructor(connection) { constructor(connectionFactory) {
this.connection = connection; this.connectionFactory = connectionFactory;
}
async withConnection(callback) {
const connection = this.connectionFactory();
try {
return await callback(connection);
}
finally {
connection.end();
}
} }
// Gebe zumindest {username: "x", password: "x"} mit! // Gebe zumindest {username: "x", password: "x"} mit!
@@ -16,14 +27,20 @@ class UserManager {
const user = await this.getUser({username: userJson.username}); const user = await this.getUser({username: userJson.username});
if(user) return 0; if(user) return 0;
return await this.withConnection(async (connection) => {
try { try {
const passHash = await bcrypt.hash(userJson.password, 10); const passHash = await bcrypt.hash(userJson.password, 10);
this.connection.query(`INSERT INTO users (username, email, password, fullName) VALUES ("${userJson.username}",` + await connection
` ${userJson.email ? `"${userJson.email}"` : "NULL"}, "${passHash}", ${userJson.fullName ? `"${userJson.fullName}"` : "NULL"})`); .promise()
.query(
`INSERT INTO users (username, email, password, fullName) VALUES ("${userJson.username}",` +
` ${userJson.email ? `"${userJson.email}"` : "NULL"}, "${passHash}", ${userJson.fullName ? `"${userJson.fullName}"` : "NULL"})`
);
return 1; return 1;
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
});
} }
// Gebe nichts mit um alle user zu bekommen oder {id: 1} oder {username: "x"} um darauf einen bestimmten zu bekommen; // Gebe nichts mit um alle user zu bekommen oder {id: 1} oder {username: "x"} um darauf einen bestimmten zu bekommen;
@@ -37,8 +54,9 @@ class UserManager {
selectionString = `SELECT * FROM users WHERE username="${userData.username}"`; selectionString = `SELECT * FROM users WHERE username="${userData.username}"`;
} }
return await this.withConnection(async (connection) => {
try { try {
const response = await this.connection.promise().query(selectionString); const response = await connection.promise().query(selectionString);
if(response[0].length === 0){ if(response[0].length === 0){
return null; return null;
@@ -61,6 +79,7 @@ class UserManager {
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
});
} }
// 0: User Existiert nicht | 1: Funktioniert // 0: User Existiert nicht | 1: Funktioniert
@@ -70,19 +89,23 @@ class UserManager {
if(!user) return 0; if(!user) return 0;
if(!newUserData.password) return 0; if(!newUserData.password) return 0;
return await this.withConnection(async (connection) => {
try { try {
this.connection.query( await connection
.promise()
.query(
`UPDATE users SET `UPDATE users SET
username="${newUserData.username}", username="${newUserData.username}",
email=${newUserData.email ? `"${newUserData.email}"` : "NULL"}, email=${newUserData.email ? `"${newUserData.email}"` : "NULL"},
fullName=${newUserData.fullName ? `"${newUserData.fullName}"` : "NULL"}, fullName=${newUserData.fullName ? `"${newUserData.fullName}"` : "NULL"},
password="${newUserData.password}" password="${newUserData.password}"
WHERE id = ${id}` WHERE id = ${id}`
) );
return 1; return 1;
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
});
} }
// 0: Es gibt den User nicht | 1: Funktioniert // 0: Es gibt den User nicht | 1: Funktioniert
@@ -90,12 +113,14 @@ class UserManager {
const user = await this.getUser({id}); const user = await this.getUser({id});
if(!user) return 0; if(!user) return 0;
return await this.withConnection(async (connection) => {
try { try {
this.connection.query(`DELETE FROM users where id=${id}`); await connection.promise().query(`DELETE FROM users where id=${id}`);
return 1; return 1;
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
});
} }
} }