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 fileName = `backup-${database}-${timestamp}.sql`;
|
||||||
const filePath = path.join(backupDir, fileName);
|
const filePath = path.join(backupDir, fileName);
|
||||||
|
|
||||||
// Construire la commande mysqldump
|
// Dump SQL via mysql2 (pas besoin de mysqldump)
|
||||||
const sslFlag = dbUrl.searchParams.get("ssl-mode") === "DISABLED" ? "" : "--ssl-mode=REQUIRED";
|
console.log(`[Backup] Generating SQL dump for database ${database}...`);
|
||||||
const cmd = `mysqldump ${sslFlag} -h "${host}" -P ${port} -u "${username}" --password="${password}" "${database}" > "${filePath}"`;
|
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}...`);
|
let sql = `-- Backup généré le ${new Date().toISOString()}\n-- Base : ${database}\nSET FOREIGN_KEY_CHECKS=0;\n\n`;
|
||||||
await execAsync(cmd);
|
|
||||||
console.log(`[Backup] Dump saved to ${filePath}`);
|
// 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
|
// Retourner le fichier en téléchargement
|
||||||
const encodedName = encodeURIComponent(fileName);
|
const encodedName = encodeURIComponent(fileName);
|
||||||
|
|||||||
Reference in New Issue
Block a user