up
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
/**
|
||||
* Migration: Add conversation fields and indexes
|
||||
* - Creates a backup SQL file for `conversations` (CREATE TABLE + INSERTs)
|
||||
* - Adds columns if missing
|
||||
* - Adds indexes if missing
|
||||
*
|
||||
* Usage (CLI): php scripts/migrate_add_conversation_fields.php --yes
|
||||
* If --yes is not passed the script will prompt for confirmation.
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
|
||||
$options = getopt('', ['yes']);
|
||||
$force = isset($options['yes']);
|
||||
|
||||
$dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=" . (defined('DB_CHARSET') ? DB_CHARSET : 'utf8mb4');
|
||||
try {
|
||||
$pdo = new PDO($dsn, DB_USER, DB_PASS, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
||||
} catch (Throwable $t) {
|
||||
echo "Error connecting to DB: " . $t->getMessage() . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo "This script will backup table `conversations` and apply schema changes.\n";
|
||||
if (!$force) {
|
||||
fwrite(STDOUT, "Proceed? (yes/no): ");
|
||||
$answer = trim(fgets(STDIN));
|
||||
if (strtolower($answer) !== 'yes') {
|
||||
echo "Aborted by user.\n";
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// 1) Backup: get CREATE TABLE and all rows
|
||||
$timestamp = date('Ymd_His');
|
||||
$backupDir = __DIR__ . '/../backups';
|
||||
if (!is_dir($backupDir)) mkdir($backupDir, 0755, true);
|
||||
$backupFile = $backupDir . "/conversations_backup_{$timestamp}.sql";
|
||||
|
||||
try {
|
||||
// Show create
|
||||
$row = $pdo->query("SHOW CREATE TABLE `conversations`")->fetch(PDO::FETCH_ASSOC);
|
||||
$createSql = $row['Create Table'] ?? null;
|
||||
if (!$createSql) throw new Exception('Could not obtain CREATE TABLE for conversations');
|
||||
|
||||
$fh = fopen($backupFile, 'w');
|
||||
fwrite($fh, "-- Backup of table `conversations` generated at {$timestamp}\n\n");
|
||||
fwrite($fh, "DROP TABLE IF EXISTS `conversations`;\n");
|
||||
fwrite($fh, $createSql . ";\n\n");
|
||||
|
||||
// Dump rows as INSERTs in batches
|
||||
$stmt = $pdo->query("SELECT * FROM `conversations`");
|
||||
$cols = [];
|
||||
$insertCount = 0;
|
||||
$batchSize = 200;
|
||||
$rows = [];
|
||||
while ($r = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
if (empty($cols)) $cols = array_keys($r);
|
||||
$values = array_map(function($v) use ($pdo) { return $pdo->quote($v); }, array_values($r));
|
||||
$rows[] = '(' . implode(',', $values) . ')';
|
||||
if (count($rows) >= $batchSize) {
|
||||
$line = "INSERT INTO `conversations` (`" . implode('`,`', $cols) . "`) VALUES\n" . implode(",\n", $rows) . ";\n";
|
||||
fwrite($fh, $line);
|
||||
$insertCount += count($rows);
|
||||
$rows = [];
|
||||
}
|
||||
}
|
||||
if (count($rows)) {
|
||||
$line = "INSERT INTO `conversations` (`" . implode('`,`', $cols) . "`) VALUES\n" . implode(",\n", $rows) . ";\n";
|
||||
fwrite($fh, $line);
|
||||
$insertCount += count($rows);
|
||||
}
|
||||
fclose($fh);
|
||||
echo "Backup written to: {$backupFile} (rows: {$insertCount})\n";
|
||||
} catch (Throwable $t) {
|
||||
echo "Backup failed: " . $t->getMessage() . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// 2) Prepare ALTER statements (only add if missing)
|
||||
$columnsToAdd = [
|
||||
'message_id' => "VARCHAR(255) DEFAULT NULL",
|
||||
'message_type' => "VARCHAR(32) DEFAULT 'text'",
|
||||
'media_url' => "TEXT DEFAULT NULL",
|
||||
'local_file' => "VARCHAR(255) DEFAULT NULL",
|
||||
'local_thumb' => "VARCHAR(255) DEFAULT NULL",
|
||||
'filename' => "VARCHAR(255) DEFAULT NULL",
|
||||
'mime_type' => "VARCHAR(100) DEFAULT NULL",
|
||||
'reply_to_message_id' => "VARCHAR(255) DEFAULT NULL",
|
||||
'reaction_emoji' => "VARCHAR(64) DEFAULT NULL",
|
||||
'reaction_to_message_id' => "VARCHAR(255) DEFAULT NULL",
|
||||
'status' => "VARCHAR(32) DEFAULT 'received'"
|
||||
];
|
||||
|
||||
$existingColsStmt = $pdo->query("SHOW COLUMNS FROM `conversations`");
|
||||
$existingCols = [];
|
||||
foreach ($existingColsStmt->fetchAll(PDO::FETCH_ASSOC) as $c) $existingCols[] = $c['Field'];
|
||||
|
||||
$alters = [];
|
||||
foreach ($columnsToAdd as $col => $type) {
|
||||
if (!in_array($col, $existingCols)) {
|
||||
$alters[] = "ADD COLUMN `{$col}` {$type}";
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (count($alters)) {
|
||||
$sql = "ALTER TABLE `conversations` " . implode(', ', $alters) . ";";
|
||||
$pdo->exec($sql);
|
||||
echo "Applied ALTER TABLE to add columns: " . implode(', ', array_keys($columnsToAdd)) . "\n";
|
||||
} else {
|
||||
echo "No new columns to add.\n";
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
echo "ALTER TABLE failed: " . $t->getMessage() . PHP_EOL;
|
||||
echo "You can manually inspect {$backupFile} and run the appropriate ALTERs.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// 3) Add indexes if missing
|
||||
$indexes = [
|
||||
'idx_message_id' => ['cols' => ['message_id'], 'unique' => false],
|
||||
'idx_reply' => ['cols' => ['reply_to_message_id'], 'unique' => false],
|
||||
];
|
||||
|
||||
$existingIndexes = [];
|
||||
$rs = $pdo->query("SHOW INDEX FROM `conversations`");
|
||||
foreach ($rs->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
||||
$existingIndexes[$row['Key_name']][] = $row['Column_name'];
|
||||
}
|
||||
|
||||
foreach ($indexes as $name => $info) {
|
||||
if (!isset($existingIndexes[$name])) {
|
||||
$colsSql = implode('`,`', $info['cols']);
|
||||
$sql = "CREATE INDEX `{$name}` ON `conversations` (`{$colsSql}`);";
|
||||
try {
|
||||
$pdo->exec($sql);
|
||||
echo "Added index {$name} (" . implode(',', $info['cols']) . ")\n";
|
||||
} catch (Throwable $t) {
|
||||
echo "Failed to add index {$name}: " . $t->getMessage() . PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
echo "Index {$name} already exists.\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "Migration complete. Backup file: {$backupFile}\n";
|
||||
|
||||
return 0;
|
||||
Reference in New Issue
Block a user