<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260712120000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Build performance indexes concurrently without rewriting application data.';
}
public function isTransactional(): bool
{
// PostgreSQL does not allow CREATE/DROP INDEX CONCURRENTLY inside a
// transaction. Running each statement separately avoids blocking
// normal writes for the duration of an index build.
return false;
}
public function up(Schema $schema): void
{
$this->abortIf('postgresql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on postgresql.');
// Drop first so a retry also repairs an invalid index left behind by
// an interrupted CREATE INDEX CONCURRENTLY operation.
$this->rebuildIndex('IDX_M_DEVICE_FINISHED', 'measurements (device_id, finished_at DESC, id DESC)');
$this->rebuildIndex('IDX_MS_MEASUREMENT_DELETED', 'measurement_settings (measurement_id, is_deleted)');
$this->rebuildIndex('IDX_DS_DEVICE_LATEST', 'data_samples (device_id, id DESC)');
$this->rebuildIndex('IDX_DC_DEVICE_COMMAND', 'device_command (device_id, command)');
$this->rebuildIndex('IDX_PROBE_CHANNEL_TIME', 'probes (channel_id, time DESC)');
}
public function down(Schema $schema): void
{
$this->abortIf('postgresql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on postgresql.');
$this->addSql('DROP INDEX CONCURRENTLY IF EXISTS IDX_PROBE_CHANNEL_TIME');
$this->addSql('DROP INDEX CONCURRENTLY IF EXISTS IDX_DC_DEVICE_COMMAND');
$this->addSql('DROP INDEX CONCURRENTLY IF EXISTS IDX_DS_DEVICE_LATEST');
$this->addSql('DROP INDEX CONCURRENTLY IF EXISTS IDX_MS_MEASUREMENT_DELETED');
$this->addSql('DROP INDEX CONCURRENTLY IF EXISTS IDX_M_DEVICE_FINISHED');
}
private function rebuildIndex(string $name, string $definition): void
{
$this->addSql(sprintf('DROP INDEX CONCURRENTLY IF EXISTS %s', $name));
$this->addSql(sprintf('CREATE INDEX CONCURRENTLY %s ON %s', $name, $definition));
}
}