Checkpoint: mysqldump n'est pas disponible dans le container Node.js. Remplacement par un dump SQL généré directement via mysql2 : SHOW CREATE TABLE + SELECT * pour chaque table, avec échappement correct des valeurs.
This commit is contained in:
@@ -256,13 +256,48 @@ async function startServer() {
|
||||
const fileName = `backup-${database}-${timestamp}.sql`;
|
||||
const filePath = path.join(backupDir, fileName);
|
||||
|
||||
// Construire la commande mysqldump
|
||||
const sslFlag = dbUrl.searchParams.get("ssl-mode") === "DISABLED" ? "" : "--ssl-mode=REQUIRED";
|
||||
const cmd = `mysqldump ${sslFlag} -h "${host}" -P ${port} -u "${username}" --password="${password}" "${database}" > "${filePath}"`;
|
||||
// Dump SQL via mysql2 (pas besoin de mysqldump)
|
||||
console.log(`[Backup] Generating SQL dump for database ${database}...`);
|
||||
const mysql = await import("mysql2/promise");
|
||||
const sslRequired = !dbUrl.searchParams.get("ssl-mode")?.includes("DISABLED");
|
||||
const conn = await mysql.createConnection({
|
||||
host, port: parseInt(port), user: username, password: decodeURIComponent(password),
|
||||
database, ssl: sslRequired ? { rejectUnauthorized: false } : undefined,
|
||||
});
|
||||
|
||||
console.log(`[Backup] Generating dump for database ${database}...`);
|
||||
await execAsync(cmd);
|
||||
console.log(`[Backup] Dump saved to ${filePath}`);
|
||||
let sql = `-- Backup généré le ${new Date().toISOString()}\n-- Base : ${database}\nSET FOREIGN_KEY_CHECKS=0;\n\n`;
|
||||
|
||||
// Lister les tables
|
||||
const [tables] = await conn.query<any[]>(`SHOW TABLES`);
|
||||
const tableNames: string[] = tables.map((r: any) => Object.values(r)[0] as string);
|
||||
|
||||
for (const table of tableNames) {
|
||||
// CREATE TABLE
|
||||
const [createRows] = await conn.query<any[]>(`SHOW CREATE TABLE \`${table}\``);
|
||||
const createSql: string = createRows[0]['Create Table'] || createRows[0][`Create Table`];
|
||||
sql += `\n-- Table: ${table}\nDROP TABLE IF EXISTS \`${table}\`;\n${createSql};\n\n`;
|
||||
|
||||
// INSERT DATA
|
||||
const [rows] = await conn.query<any[]>(`SELECT * FROM \`${table}\``);
|
||||
if (rows.length > 0) {
|
||||
const cols = Object.keys(rows[0]).map(c => `\`${c}\``).join(", ");
|
||||
const values = rows.map(row =>
|
||||
"(" + Object.values(row).map(v =>
|
||||
v === null ? "NULL" :
|
||||
v instanceof Date ? `'${v.toISOString().replace('T', ' ').replace('Z', '')}'` :
|
||||
typeof v === "number" ? v :
|
||||
`'${String(v).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`
|
||||
).join(", ") + ")"
|
||||
).join(",\n");
|
||||
sql += `INSERT INTO \`${table}\` (${cols}) VALUES\n${values};\n\n`;
|
||||
}
|
||||
}
|
||||
|
||||
sql += `\nSET FOREIGN_KEY_CHECKS=1;\n-- Fin du dump\n`;
|
||||
await conn.end();
|
||||
|
||||
fs.writeFileSync(filePath, sql, "utf8");
|
||||
console.log(`[Backup] Dump saved to ${filePath} (${(sql.length / 1024).toFixed(1)} Ko)`);
|
||||
|
||||
// Retourner le fichier en téléchargement
|
||||
const encodedName = encodeURIComponent(fileName);
|
||||
|
||||
Reference in New Issue
Block a user