Skip to content
This repository was archived by the owner on Apr 8, 2026. It is now read-only.

Commit 3188630

Browse files
author
BuildTools
committed
feat(DatabaseService): switch from sqlite3 to mysql2 for database connection
1 parent 31580a9 commit 3188630

10 files changed

Lines changed: 226 additions & 134 deletions

File tree

databaseTemplate.db

-132 KB
Binary file not shown.

dist/index.js

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
66
const app_1 = require("./app");
77
const fs_1 = __importDefault(require("fs"));
88
const path_1 = __importDefault(require("path"));
9+
const child_process_1 = require("child_process");
10+
const dotenv_1 = __importDefault(require("dotenv"));
11+
dotenv_1.default.config();
912
const port = process.env.PORT || 3000;
1013
app_1.app.listen(port, () => {
1114
console.log(`Server started on port ${port}`);
@@ -16,19 +19,28 @@ function getTimestamp() {
1619
return `${pad(now.getDate())}-${pad(now.getMonth() + 1)}-${now.getFullYear()}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
1720
}
1821
function backupDatabase() {
19-
const cwd = process.cwd();
20-
const dbPath = path_1.default.join(cwd, "database.db");
21-
const backupDir = path_1.default.join(cwd, "database_backups");
22+
const timestamp = getTimestamp();
23+
const backupDir = path_1.default.join(process.cwd(), "database_backups");
24+
const backupPath = path_1.default.join(backupDir, `mysql_backup_${timestamp}.sql`);
2225
if (!fs_1.default.existsSync(backupDir)) {
2326
fs_1.default.mkdirSync(backupDir, { recursive: true });
2427
}
25-
const backupPath = path_1.default.join(backupDir, `database_${getTimestamp()}.db`);
26-
fs_1.default.copyFile(dbPath, backupPath, (err) => {
27-
if (err) {
28-
console.error("Database backup failed:", err);
28+
const dbUser = process.env.DB_USER;
29+
const dbPassword = process.env.DB_PASSWORD;
30+
const dbName = process.env.DB_NAME;
31+
const dbHost = process.env.DB_HOST;
32+
if (!dbUser || !dbPassword || !dbName || !dbHost) {
33+
console.error("Missing database credentials in environment variables.");
34+
return;
35+
}
36+
const command = `mysqldump -h ${dbHost} -u ${dbUser} -p'${dbPassword}' ${dbName} > ${backupPath}`;
37+
(0, child_process_1.exec)(command, (error, stdout, stderr) => {
38+
if (error) {
39+
console.error("MySQL database backup failed:", error);
40+
console.error("stderr:", stderr);
2941
}
3042
else {
31-
console.log("Database backup created:", backupPath);
43+
console.log("MySQL database backup created:", backupPath);
3244
}
3345
});
3446
}

dist/services/DatabaseService.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Knex } from "knex";
2+
import "reflect-metadata";
23
export interface IDatabaseService {
34
request(query: string, params?: unknown[]): Promise<void>;
45
read<T>(query: string, params?: unknown[]): Promise<T[]>;

dist/services/DatabaseService.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
1212
exports.DatabaseService = void 0;
1313
const knex_1 = require("knex");
1414
const inversify_1 = require("inversify");
15+
require("reflect-metadata");
1516
let DatabaseService = class DatabaseService {
1617
constructor() {
18+
console.log(process.env.DB_HOST, process.env.DB_USER, process.env.DB_NAME);
1719
this.db = (0, knex_1.knex)({
18-
client: "sqlite3",
20+
client: "mysql",
1921
connection: {
20-
filename: __dirname + "/../../database.db",
22+
host: process.env.DB_HOST,
23+
user: process.env.DB_USER,
24+
port: 3306,
25+
password: process.env.DB_PASS,
26+
database: process.env.DB_NAME,
2127
},
2228
useNullAsDefault: true,
2329
});
30+
this.db
31+
.raw("SELECT 1")
32+
.then(() => {
33+
console.log("Database connection established");
34+
})
35+
.catch((err) => {
36+
console.error("Database connection error:", err);
37+
});
2438
}
2539
getKnex() {
2640
return this.db;
@@ -37,7 +51,8 @@ let DatabaseService = class DatabaseService {
3751
async read(query, params = []) {
3852
try {
3953
const result = await this.db.raw(query, params);
40-
const rows = result || [];
54+
// Pour MySQL, result = [rows, fields]
55+
const rows = Array.isArray(result) && Array.isArray(result[0]) ? result[0] : result;
4156
return rows.map((row) => {
4257
for (const key in row) {
4358
if (typeof row[key] === "string") {

dist/services/LogService.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ let LogService = class LogService {
1919
this.databaseService = databaseService;
2020
}
2121
async createLog(logData) {
22+
return;
2223
const query = `
2324
INSERT INTO logs (
2425
timestamp, ip_address, table_name, controller,

dist/services/UserService.js

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
1717
var UserService_1;
1818
Object.defineProperty(exports, "__esModule", { value: true });
1919
exports.UserService = void 0;
20+
/* eslint-disable @typescript-eslint/no-explicit-any */
2021
const inversify_1 = require("inversify");
2122
const dotenv_1 = require("dotenv");
2223
const path_1 = __importDefault(require("path"));
@@ -47,6 +48,9 @@ let UserService = UserService_1 = class UserService {
4748
return base + " AND (disabled = 0 OR disabled IS NULL)";
4849
}
4950
async fetchUserByAnyId(user_id, includeDisabled = false) {
51+
// console.log("Fetching user by any ID:", user_id);
52+
if (!user_id)
53+
return null;
5054
const users = await this.databaseService.read(`SELECT * FROM users WHERE ${UserService_1.getIdWhereClause(includeDisabled)}`, [user_id, user_id, user_id, user_id]);
5155
return users.length > 0 ? users[0] : null;
5256
}
@@ -229,24 +233,24 @@ let UserService = UserService_1 = class UserService {
229233
const query = `
230234
SELECT
231235
u.*,
232-
json_group_array(
236+
CONCAT('[', GROUP_CONCAT(
233237
CASE WHEN inv.item_id IS NOT NULL AND i.itemId IS NOT NULL THEN
234-
json_object(
238+
JSON_OBJECT(
235239
'user_id', inv.user_id,
236240
'item_id', inv.item_id,
237241
'itemId', i.itemId,
238242
'name', i.name,
239243
'description', i.description,
240244
'amount', inv.amount,
241245
'iconHash', i.iconHash,
242-
'sellable', CASE WHEN inv.sellable = 1 THEN 1 ELSE 0 END,
246+
'sellable', IF(inv.sellable = 1, 1, 0),
243247
'purchasePrice', inv.purchasePrice,
244-
'metadata', CASE WHEN inv.metadata IS NOT NULL THEN json(inv.metadata) ELSE NULL END
248+
'metadata', inv.metadata
245249
)
246250
END
247-
) as inventory,
248-
(SELECT json_group_array(
249-
json_object(
251+
), ']') as inventory,
252+
(SELECT CONCAT('[', GROUP_CONCAT(
253+
JSON_OBJECT(
250254
'itemId', oi.itemId,
251255
'name', oi.name,
252256
'description', oi.description,
@@ -255,9 +259,9 @@ let UserService = UserService_1 = class UserService {
255259
'iconHash', oi.iconHash,
256260
'showInStore', oi.showInStore
257261
)
258-
) FROM items oi WHERE oi.owner = u.user_id AND (oi.deleted IS NULL OR oi.deleted = 0) AND oi.showInStore = 1 ORDER BY oi.name) as ownedItems,
259-
(SELECT json_group_array(
260-
json_object(
262+
), ']') FROM items oi WHERE oi.owner = u.user_id AND (oi.deleted IS NULL OR oi.deleted = 0) AND oi.showInStore = 1 ORDER BY oi.name) as ownedItems,
263+
(SELECT CONCAT('[', GROUP_CONCAT(
264+
JSON_OBJECT(
261265
'gameId', g.gameId,
262266
'name', g.name,
263267
'description', g.description,
@@ -278,7 +282,7 @@ let UserService = UserService_1 = class UserService {
278282
'multiplayer', g.multiplayer,
279283
'download_link', g.download_link
280284
)
281-
) FROM games g WHERE g.owner_id = u.user_id AND g.showInStore = 1 ORDER BY g.name) as createdGames
285+
), ']') FROM games g WHERE g.owner_id = u.user_id AND g.showInStore = 1 ORDER BY g.name) as createdGames
282286
FROM users u
283287
LEFT JOIN inventories inv ON u.user_id = inv.user_id AND inv.amount > 0
284288
LEFT JOIN items i ON inv.item_id = i.itemId AND (i.deleted IS NULL OR i.deleted = 0)
@@ -298,8 +302,20 @@ let UserService = UserService_1 = class UserService {
298302
return null;
299303
const user = results[0];
300304
if (user.inventory) {
301-
user.inventory = user.inventory.filter((item) => item !== null);
302-
user.inventory.sort((a, b) => {
305+
user.inventory = user.inventory
306+
.filter((item) => item !== null)
307+
.map((item) => ({
308+
...item,
309+
metadata: typeof item.metadata === "string" && item.metadata
310+
? (() => { try {
311+
return JSON.parse(item.metadata);
312+
}
313+
catch {
314+
return item.metadata;
315+
} })()
316+
: item.metadata
317+
}))
318+
.sort((a, b) => {
303319
const nameCompare = a.name?.localeCompare(b.name || '') || 0;
304320
if (nameCompare !== 0)
305321
return nameCompare;
@@ -316,24 +332,24 @@ let UserService = UserService_1 = class UserService {
316332
const query = `
317333
SELECT
318334
u.user_id, u.username, u.verified, u.isStudio, u.admin,
319-
json_group_array(
335+
CONCAT('[', GROUP_CONCAT(
320336
CASE WHEN inv.item_id IS NOT NULL AND i.itemId IS NOT NULL THEN
321-
json_object(
337+
JSON_OBJECT(
322338
'user_id', inv.user_id,
323339
'item_id', inv.item_id,
324340
'itemId', i.itemId,
325341
'name', i.name,
326342
'description', i.description,
327343
'amount', inv.amount,
328344
'iconHash', i.iconHash,
329-
'sellable', CASE WHEN inv.sellable = 1 THEN 1 ELSE 0 END,
345+
'sellable', IF(inv.sellable = 1, 1, 0),
330346
'purchasePrice', inv.purchasePrice,
331-
'metadata', CASE WHEN inv.metadata IS NOT NULL THEN json(inv.metadata) ELSE NULL END
347+
'metadata', inv.metadata
332348
)
333349
END
334-
) as inventory,
335-
(SELECT json_group_array(
336-
json_object(
350+
), ']') as inventory,
351+
(SELECT CONCAT('[', GROUP_CONCAT(
352+
JSON_OBJECT(
337353
'itemId', oi.itemId,
338354
'name', oi.name,
339355
'description', oi.description,
@@ -342,9 +358,9 @@ let UserService = UserService_1 = class UserService {
342358
'iconHash', oi.iconHash,
343359
'showInStore', oi.showInStore
344360
)
345-
) FROM items oi WHERE oi.owner = u.user_id AND (oi.deleted IS NULL OR oi.deleted = 0) AND oi.showInStore = 1 ORDER BY oi.name) as ownedItems,
346-
(SELECT json_group_array(
347-
json_object(
361+
), ']') FROM items oi WHERE oi.owner = u.user_id AND (oi.deleted IS NULL OR oi.deleted = 0) AND oi.showInStore = 1 ORDER BY oi.name) as ownedItems,
362+
(SELECT CONCAT('[', GROUP_CONCAT(
363+
JSON_OBJECT(
348364
'gameId', g.gameId,
349365
'name', g.name,
350366
'description', g.description,
@@ -364,7 +380,7 @@ let UserService = UserService_1 = class UserService {
364380
'trailer_link', g.trailer_link,
365381
'multiplayer', g.multiplayer
366382
)
367-
) FROM games g WHERE g.owner_id = u.user_id AND g.showInStore = 1 ORDER BY g.name) as createdGames
383+
), ']') FROM games g WHERE g.owner_id = u.user_id AND g.showInStore = 1 ORDER BY g.name) as createdGames
368384
FROM users u
369385
LEFT JOIN inventories inv ON u.user_id = inv.user_id AND inv.amount > 0
370386
LEFT JOIN items i ON inv.item_id = i.itemId AND (i.deleted IS NULL OR i.deleted = 0)
@@ -376,8 +392,20 @@ let UserService = UserService_1 = class UserService {
376392
return null;
377393
const user = results[0];
378394
if (user.inventory) {
379-
user.inventory = user.inventory.filter((item) => item !== null);
380-
user.inventory.sort((a, b) => {
395+
user.inventory = user.inventory
396+
.filter((item) => item !== null)
397+
.map((item) => ({
398+
...item,
399+
metadata: typeof item.metadata === "string" && item.metadata
400+
? (() => { try {
401+
return JSON.parse(item.metadata);
402+
}
403+
catch {
404+
return item.metadata;
405+
} })()
406+
: item.metadata
407+
}))
408+
.sort((a, b) => {
381409
const nameCompare = a.name?.localeCompare(b.name || '') || 0;
382410
if (nameCompare !== 0)
383411
return nameCompare;
@@ -403,24 +431,25 @@ let UserService = UserService_1 = class UserService {
403431
const query = `
404432
SELECT
405433
u.*,
406-
json_group_array(
434+
IFNULL(CONCAT('[', GROUP_CONCAT(
407435
CASE WHEN inv.item_id IS NOT NULL AND i.itemId IS NOT NULL THEN
408-
json_object(
436+
JSON_OBJECT(
409437
'user_id', inv.user_id,
410438
'item_id', inv.item_id,
411439
'itemId', i.itemId,
412440
'name', i.name,
413441
'description', i.description,
414442
'amount', inv.amount,
415443
'iconHash', i.iconHash,
416-
'sellable', CASE WHEN inv.sellable = 1 THEN 1 ELSE 0 END,
444+
'sellable', IF(inv.sellable = 1, 1, 0),
417445
'purchasePrice', inv.purchasePrice,
418-
'metadata', CASE WHEN inv.metadata IS NOT NULL THEN json(inv.metadata) ELSE NULL END
446+
'metadata', inv.metadata
419447
)
420448
END
421-
) as inventory,
422-
(SELECT json_group_array(
423-
json_object(
449+
ORDER BY i.name SEPARATOR ','
450+
), ']'), '[]') as inventory,
451+
(SELECT IFNULL(CONCAT('[', GROUP_CONCAT(
452+
JSON_OBJECT(
424453
'itemId', oi.itemId,
425454
'name', oi.name,
426455
'description', oi.description,
@@ -429,9 +458,10 @@ let UserService = UserService_1 = class UserService {
429458
'iconHash', oi.iconHash,
430459
'showInStore', oi.showInStore
431460
)
432-
) FROM items oi WHERE oi.owner = u.user_id AND (oi.deleted IS NULL OR oi.deleted = 0) AND oi.showInStore = 1 ORDER BY oi.name) as ownedItems,
433-
(SELECT json_group_array(
434-
json_object(
461+
ORDER BY oi.name SEPARATOR ','
462+
), ']'), '[]') FROM items oi WHERE oi.owner = u.user_id AND (oi.deleted IS NULL OR oi.deleted = 0) AND oi.showInStore = 1) as ownedItems,
463+
(SELECT IFNULL(CONCAT('[', GROUP_CONCAT(
464+
JSON_OBJECT(
435465
'gameId', g.gameId,
436466
'name', g.name,
437467
'description', g.description,
@@ -451,7 +481,8 @@ let UserService = UserService_1 = class UserService {
451481
'trailer_link', g.trailer_link,
452482
'multiplayer', g.multiplayer
453483
)
454-
) FROM games g WHERE g.owner_id = u.user_id AND g.showInStore = 1 ORDER BY g.name) as createdGames
484+
ORDER BY g.name SEPARATOR ','
485+
), ']'), '[]') FROM games g WHERE g.owner_id = u.user_id AND g.showInStore = 1) as createdGames
455486
FROM users u
456487
LEFT JOIN inventories inv ON u.user_id = inv.user_id AND inv.amount > 0
457488
LEFT JOIN items i ON inv.item_id = i.itemId AND (i.deleted IS NULL OR i.deleted = 0)
@@ -462,19 +493,6 @@ let UserService = UserService_1 = class UserService {
462493
if (results.length === 0)
463494
return null;
464495
const user = results[0];
465-
if (user.inventory) {
466-
user.inventory = user.inventory.filter((item) => item !== null);
467-
user.inventory.sort((a, b) => {
468-
const nameCompare = a.name?.localeCompare(b.name || '') || 0;
469-
if (nameCompare !== 0)
470-
return nameCompare;
471-
if (!a.metadata && b.metadata)
472-
return -1;
473-
if (a.metadata && !b.metadata)
474-
return 1;
475-
return 0;
476-
});
477-
}
478496
return user;
479497
}
480498
async findByResetToken(reset_token) {

0 commit comments

Comments
 (0)