diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 53dd1d7..bb3ad38 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,5 +1,26 @@ + + + + + + + + + + + + + + + + + + + ]]> + + @@ -25,26 +46,4 @@ database]]> - - - - - - - - - - - - - - - - - - getName()]]> - getName()]]> - getName()]]> - - diff --git a/psalm.xml b/psalm.xml index 755ad51..286a1ec 100644 --- a/psalm.xml +++ b/psalm.xml @@ -5,6 +5,7 @@ xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" errorBaseline="psalm-baseline.xml" errorLevel="1" + findUnusedBaselineEntry="true" > diff --git a/src/Changes/ChangeType.php b/src/Changes/ChangeType.php new file mode 100644 index 0000000..296404a --- /dev/null +++ b/src/Changes/ChangeType.php @@ -0,0 +1,25 @@ + + */ + public function collect(Atomizer $atomizer): array + { + $result = []; + + foreach ($atomizer->getTables() as $table) { + if ($table->getStatus() === AbstractTable::STATUS_NEW) { + $result[] = [ChangeType::CreateTable, $table->getName()]; + continue; + } + + if ($table->getStatus() === AbstractTable::STATUS_DECLARED_DROPPED) { + $result[] = [ChangeType::DropTable, $table->getName()]; + continue; + } + + if ($table->getComparator()->isRenamed()) { + $result[] = [ChangeType::RenameTable, $table->getInitialName()]; + continue; + } + + $result[] = [ChangeType::ChangeTable, $table->getName()]; + + $comparator = $table->getComparator(); + + foreach ($comparator->addedColumns() as $column) { + $result[] = [ChangeType::AddColumn, $column->getName()]; + } + + foreach ($comparator->droppedColumns() as $column) { + $result[] = [ChangeType::DropColumn, $column->getName()]; + } + + foreach ($comparator->alteredColumns() as $column) { + $result[] = [ChangeType::AlterColumn, $column[0]->getName()]; + } + + foreach ($comparator->addedIndexes() as $index) { + $result[] = [ChangeType::AddIndex, $index->getName()]; + } + + foreach ($comparator->droppedIndexes() as $index) { + $result[] = [ChangeType::DropIndex, $index->getName()]; + } + + foreach ($comparator->alteredIndexes() as $index) { + $result[] = [ChangeType::AlterIndex, $index[0]->getName()]; + } + + foreach ($comparator->addedForeignKeys() as $fk) { + $result[] = [ChangeType::AddFk, $fk->getName()]; + } + + foreach ($comparator->droppedForeignKeys() as $fk) { + $result[] = [ChangeType::DropFk, $fk->getName()]; + } + + foreach ($comparator->alteredForeignKeys() as $fk) { + $result[] = [ChangeType::AlterFk, $fk[0]->getName()]; + } + } + + return $result; + } +} diff --git a/src/ChangesCountNameGenerator.php b/src/ChangesCountNameGenerator.php new file mode 100644 index 0000000..86c4162 --- /dev/null +++ b/src/ChangesCountNameGenerator.php @@ -0,0 +1,62 @@ +collect($atomizer) as $pair) { + $key = $this->changeToString($pair[0]); + $map[$key] ??= 0; + $map[$key]++; + } + + $result = []; + foreach ($map as $key => $cnt) { + $result[] = "{$key}{$cnt}"; + } + + return \implode('_', $result); + } + + private function changeToString(ChangeType $change): string + { + return match ($change) { + ChangeType::CreateTable => 'ct', + ChangeType::DropTable => 'dt', + ChangeType::RenameTable, + ChangeType::ChangeTable => 't', + ChangeType::AddColumn, + ChangeType::DropColumn, + ChangeType::AlterColumn => 'c', + ChangeType::AddIndex, + ChangeType::DropIndex, + ChangeType::AlterIndex => 'i', + ChangeType::AddFk, + ChangeType::DropFk, + ChangeType::AlterFk => 'fk', + }; + } +} diff --git a/src/NameBasedOnChangesGenerator.php b/src/NameBasedOnChangesGenerator.php index b851ce4..4c0f120 100644 --- a/src/NameBasedOnChangesGenerator.php +++ b/src/NameBasedOnChangesGenerator.php @@ -4,72 +4,44 @@ namespace Cycle\Schema\Generator\Migrations; -use Cycle\Database\Schema\AbstractTable; use Cycle\Migrations\Atomizer\Atomizer; +use Cycle\Schema\Generator\Migrations\Changes\ChangeType; +use Cycle\Schema\Generator\Migrations\Changes\Collector; final class NameBasedOnChangesGenerator implements NameGeneratorInterface { public function generate(Atomizer $atomizer): string { - $name = []; - - foreach ($atomizer->getTables() as $table) { - if ($table->getStatus() === AbstractTable::STATUS_NEW) { - $name[] = 'create_' . $table->getName(); - continue; - } - - if ($table->getStatus() === AbstractTable::STATUS_DECLARED_DROPPED) { - $name[] = 'drop_' . $table->getName(); - continue; - } - - if ($table->getComparator()->isRenamed()) { - $name[] = 'rename_' . $table->getInitialName(); - continue; - } - - $name[] = 'change_' . $table->getName(); - - $comparator = $table->getComparator(); - - foreach ($comparator->addedColumns() as $column) { - $name[] = 'add_' . $column->getName(); - } - - foreach ($comparator->droppedColumns() as $column) { - $name[] = 'rm_' . $column->getName(); - } - - foreach ($comparator->alteredColumns() as $column) { - $name[] = 'alter_' . $column[0]->getName(); - } - - foreach ($comparator->addedIndexes() as $index) { - $name[] = 'add_index_' . $index->getName(); - } - - foreach ($comparator->droppedIndexes() as $index) { - $name[] = 'rm_index_' . $index->getName(); - } - - foreach ($comparator->alteredIndexes() as $index) { - $name[] = 'alter_index_' . $index[0]->getName(); - } - - foreach ($comparator->addedForeignKeys() as $fk) { - $name[] = 'add_fk_' . $fk->getName(); - } - - foreach ($comparator->droppedForeignKeys() as $fk) { - $name[] = 'rm_fk_' . $fk->getName(); - } - - foreach ($comparator->alteredForeignKeys() as $fk) { - $name[] = 'alter_fk_' . $fk[0]->getName(); - } - } + $collector = new Collector(); + return \implode( + '_', + \array_map( + fn(array $pair): string => $this->changeToString($pair[0], $pair[1]), + $collector->collect($atomizer), + ), + ); + } - return \implode('_', $name); + private function changeToString(ChangeType $change, string $name): string + { + return sprintf( + '%s_%s', + match ($change) { + ChangeType::CreateTable => 'create', + ChangeType::DropTable => 'drop', + ChangeType::RenameTable => 'rename', + ChangeType::ChangeTable => 'change', + ChangeType::AddColumn => 'add', + ChangeType::DropColumn => 'rm', + ChangeType::AlterColumn => 'alter', + ChangeType::AddIndex => 'add_index', + ChangeType::DropIndex => 'rm_index', + ChangeType::AlterIndex => 'alter_index', + ChangeType::AddFk => 'add_fk', + ChangeType::DropFk => 'rm_fk', + ChangeType::AlterFk => 'alter_fk', + }, + $name, + ); } } diff --git a/tests/Migrations/Unit/ChangesCountTest.php b/tests/Migrations/Unit/ChangesCountTest.php new file mode 100644 index 0000000..5500c67 --- /dev/null +++ b/tests/Migrations/Unit/ChangesCountTest.php @@ -0,0 +1,107 @@ +createMock(RendererInterface::class), + ); + + $create = $this->createMock(AbstractTable::class); + $create->method('getName')->willReturn('creates'); + $create->method('getStatus')->willReturn(AbstractTable::STATUS_NEW); + + $drops = $this->createMock(AbstractTable::class); + $drops->method('getName')->willReturn('drops'); + $drops->method('getStatus')->willReturn(AbstractTable::STATUS_DECLARED_DROPPED); + + $renamesCmp = $this->createMock(ComparatorInterface::class); + $renamesCmp->method('isRenamed')->willReturn(true); + $renames = $this->createMock(AbstractTable::class); + $renames->method('getName')->willReturn('renames'); + $renames->method('getStatus')->willReturn(AbstractTable::STATUS_EXISTS); + $renames->method('getComparator')->willReturn($renamesCmp); + $renames->method('getInitialName')->willReturn('old_name'); + + // Comparator + $changeCmp = $this->createMock(ComparatorInterface::class); + $changeCmp->method('isRenamed')->willReturn(false); + //// Column + $columnAdd = $this->createMock(AbstractColumn::class); + $columnAdd->method('getName')->willReturn('c1'); + $columnDrop = $this->createMock(AbstractColumn::class); + $columnDrop->method('getName')->willReturn('c2'); + $columnAlter = $this->createMock(AbstractColumn::class); + $columnAlter->method('getName')->willReturn('c3'); + $changeCmp->method('addedColumns')->willReturn([$columnAdd]); + $changeCmp->method('droppedColumns')->willReturn([$columnDrop]); + $changeCmp->method('alteredColumns') + ->willReturn([ + [$columnAlter, $this->createMock(AbstractColumn::class)], + ]); + //// Index + $indexAdd = $this->createMock(AbstractIndex::class); + $indexAdd->method('getName')->willReturn('i1'); + $indexDrop = $this->createMock(AbstractIndex::class); + $indexDrop->method('getName')->willReturn('i2'); + $indexAlter = $this->createMock(AbstractIndex::class); + $indexAlter->method('getName')->willReturn('i3'); + $changeCmp->method('addedIndexes')->willReturn([$indexAdd]); + $changeCmp->method('droppedIndexes')->willReturn([$indexDrop]); + $changeCmp->method('alteredIndexes') + ->willReturn([ + [$indexAlter, $this->createMock(AbstractIndex::class)], + ]); + //// FK + $fkAdd = $this->createMock(AbstractForeignKey::class); + $fkAdd->method('getName')->willReturn('fk1'); + $fkDrop = $this->createMock(AbstractForeignKey::class); + $fkDrop->method('getName')->willReturn('fk2'); + $fkAlter = $this->createMock(AbstractForeignKey::class); + $fkAlter->method('getName')->willReturn('fk3'); + $changeCmp->method('addedForeignKeys')->willReturn([$fkAdd]); + $changeCmp->method('droppedForeignKeys')->willReturn([$fkDrop]); + $changeCmp->method('alteredForeignKeys') + ->willReturn([ + [$fkAlter, $this->createMock(AbstractForeignKey::class)], + ]); + + // Table + $change = $this->createMock(AbstractTable::class); + $change->method('getStatus')->willReturn(AbstractTable::STATUS_EXISTS); + $renames->method('getName')->willReturn('changes'); + $change->method('getComparator')->willReturn($changeCmp); + + $atomizer + ->addTable($create) + ->addTable($drops) + ->addTable($renames) + ->addTable($change); + $generator = new ChangesCountNameGenerator(); + self::assertSame( + 'ct1_dt1_t2_c3_i3_fk3', + $generator->generate($atomizer), + ); + } +} diff --git a/tests/Migrations/Unit/NameBasedOnChangesGeneratorTest.php b/tests/Migrations/Unit/NameBasedOnChangesGeneratorTest.php new file mode 100644 index 0000000..67ecd57 --- /dev/null +++ b/tests/Migrations/Unit/NameBasedOnChangesGeneratorTest.php @@ -0,0 +1,54 @@ +createMock(RendererInterface::class), + ); + + $create = $this->createMock(AbstractTable::class); + $create->method('getName')->willReturn('creates'); + $create->method('getStatus')->willReturn(AbstractTable::STATUS_NEW); + + $drops = $this->createMock(AbstractTable::class); + $drops->method('getName')->willReturn('drops'); + $drops->method('getStatus')->willReturn(AbstractTable::STATUS_DECLARED_DROPPED); + + $renamesCmp = $this->createMock(ComparatorInterface::class); + $renamesCmp->method('isRenamed')->willReturn(true); + $renames = $this->createMock(AbstractTable::class); + $renames->method('getName')->willReturn('renames'); + $renames->method('getStatus')->willReturn(AbstractTable::STATUS_EXISTS); + $renames->method('getComparator')->willReturn($renamesCmp); + $renames->method('getInitialName')->willReturn('old_name'); + + $atomizer + ->addTable($create) + ->addTable($drops) + ->addTable($renames); + $generator = new NameBasedOnChangesGenerator(); + self::assertSame( + 'create_creates_drop_drops_rename_old_name', + $generator->generate($atomizer), + ); + } +}