Skip to content

Commit

Permalink
Merge pull request #72 from php-openapi/63-just-column-name-rename
Browse files Browse the repository at this point in the history
Resolve: Just column name rename #63
  • Loading branch information
cebe authored Dec 23, 2024
2 parents ca23577 + 369fdca commit 36c04a7
Show file tree
Hide file tree
Showing 13 changed files with 208 additions and 26 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ services:
MYSQL_DATABASE: testdb

maria:
image: mariadb:10.8
image: mariadb:10.8.2
ports:
- '23306:3306'
volumes:
Expand Down
68 changes: 65 additions & 3 deletions src/lib/migrations/BaseMigrationBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,10 @@ function (string $unknownColumn) {

$columnsForChange = array_intersect($wantNames, $haveNames);

$fromColNameToColName = $this->handleColumnsRename($columnsForCreate, $columnsForDrop, $this->newColumns);

if ($this->model->drop) {
$this->newColumns = [];
$wantNames = [];
$columnsForCreate = [];
$columnsForChange = [];
$columnsForDrop = [];
Expand All @@ -218,7 +219,9 @@ function (string $unknownColumn) {
}

if (!$relation) {
$this->buildIndexChanges();
$this->buildIndexChanges($fromColNameToColName);
} else {
$this->migrationForRenameColumn($fromColNameToColName);
}

$this->buildColumnsDrop($columnsForDrop);
Expand Down Expand Up @@ -303,7 +306,7 @@ abstract protected function findTableIndexes():array;

abstract public function handleCommentsMigration();

protected function buildIndexChanges():void
protected function buildIndexChanges(array $fromColNameToColName): void
{
$haveIndexes = $this->findTableIndexes();
$wantIndexes = $this->model->indexes;
Expand Down Expand Up @@ -338,6 +341,9 @@ function ($idx) use ($wantIndexes) {
$this->migration->addUpCode($this->recordBuilder->dropIndex($tableName, $index->name))
->addDownCode($downCode);
}

$this->migrationForRenameColumn($fromColNameToColName);

foreach ($forCreate as $index) {
$upCode = $index->isUnique
? $this->recordBuilder->addUniqueIndex($tableName, $index->name, $index->columns)
Expand Down Expand Up @@ -614,4 +620,60 @@ protected function shouldCompareComment(ColumnSchema $desired): bool
}
return $comment;
}

/**
* @param array $columnsForCreate
* @param array $columnsForDrop
* @param $newColumns
* @return array key is previous/old column name and value is new column name
*/
public function handleColumnsRename(array &$columnsForCreate, array &$columnsForDrop, $newColumns): array
{
$keys = [];
$fromColNameToColName = [];
$existingColumns = $this->tableSchema->columns;
if (count($existingColumns) !== count($newColumns)) {
return $fromColNameToColName;
}
$existingColumnNames = array_keys($existingColumns);
$newColumnNames = array_flip(array_keys($newColumns));
foreach ($columnsForCreate as $key => $column) {
$index = $newColumnNames[$column->name];
$previousColumnName = $existingColumnNames[$index] ?? null;
if ($previousColumnName) {
$current = $existingColumns[$previousColumnName];
$desired = $newColumns[$column->name];
$changedAttributes = $this->compareColumns(clone $current, clone $desired);
if (empty($changedAttributes)) {
$keys[] = $key;
$dropKeyOut = null;
array_walk($columnsForDrop, function ($value, $dropKey) use ($previousColumnName, &$dropKeyOut) {
if ($value->name === $previousColumnName) {
$dropKeyOut = $dropKey;
}
});
// existing column name should be removed from $columnsForDrop
unset($columnsForDrop[$dropKeyOut]);

// Create ALTER COLUMN NAME query
// see `migrationForRenameColumn()`
$fromColNameToColName[$previousColumnName] = $column->name;
}
}
}

// new column name should be removed from $columnsForCreate
foreach ($keys as $key) {
unset($columnsForCreate[$key]);
}
return $fromColNameToColName;
}

public function migrationForRenameColumn(array $fromColNameToColName): void
{
foreach ($fromColNameToColName as $previousColumnName => $columnName) {
$this->migration->addUpCode($this->recordBuilder->renameColumn($this->model->tableAlias, $previousColumnName, $columnName))
->addDownCode($this->recordBuilder->renameColumn($this->model->tableAlias, $columnName, $previousColumnName));
}
}
}
6 changes: 6 additions & 0 deletions src/lib/migrations/MigrationRecordBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ final class MigrationRecordBuilder
public const ADD_COMMENT_ON_COLUMN = MigrationRecordBuilder::INDENT . "\$this->addCommentOnColumn('%s', '%s', %s);";

public const DROP_COMMENT_FROM_COLUMN = MigrationRecordBuilder::INDENT . "\$this->dropCommentFromColumn('%s', '%s');";
public const RENAME_COLUMN = MigrationRecordBuilder::INDENT . "\$this->renameColumn('%s', '%s', '%s');";

/**
* @var \yii\db\Schema
Expand Down Expand Up @@ -387,4 +388,9 @@ public function dropCommentFromColumn($table, string $column): string
{
return sprintf(self::DROP_COMMENT_FROM_COLUMN, $table, $column);
}

public function renameColumn(string $table, string $fromColumn, string $toColumn): string
{
return sprintf(self::RENAME_COLUMN, $table, $fromColumn, $toColumn);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ class m200000_000000_change_table_column_name_changes extends \yii\db\Migration
{
public function up()
{
$this->db->createCommand('ALTER TABLE {{%column_name_changes}} ADD COLUMN updated_at_2 datetime NOT NULL')->execute();
$this->dropColumn('{{%column_name_changes}}', 'updated_at');
$this->renameColumn('{{%column_name_changes}}', 'updated_at', 'updated_at_2');
}

public function down()
{
$this->addColumn('{{%column_name_changes}}', 'updated_at', $this->datetime()->notNull());
$this->dropColumn('{{%column_name_changes}}', 'updated_at_2');
$this->renameColumn('{{%column_name_changes}}', 'updated_at_2', 'updated_at');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ class m200000_000000_change_table_column_name_changes extends \yii\db\Migration
{
public function up()
{
$this->db->createCommand('ALTER TABLE {{%column_name_changes}} ADD COLUMN updated_at_2 datetime NOT NULL')->execute();
$this->dropColumn('{{%column_name_changes}}', 'updated_at');
$this->renameColumn('{{%column_name_changes}}', 'updated_at', 'updated_at_2');
}

public function down()
{
$this->addColumn('{{%column_name_changes}}', 'updated_at', $this->datetime()->notNull());
$this->dropColumn('{{%column_name_changes}}', 'updated_at_2');
$this->renameColumn('{{%column_name_changes}}', 'updated_at_2', 'updated_at');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ class m200000_000000_change_table_column_name_changes extends \yii\db\Migration
{
public function safeUp()
{
$this->db->createCommand('ALTER TABLE {{%column_name_changes}} ADD COLUMN "updated_at_2" timestamp NOT NULL')->execute();
$this->dropColumn('{{%column_name_changes}}', 'updated_at');
$this->renameColumn('{{%column_name_changes}}', 'updated_at', 'updated_at_2');
}

public function safeDown()
{
$this->addColumn('{{%column_name_changes}}', 'updated_at', $this->timestamp()->notNull());
$this->dropColumn('{{%column_name_changes}}', 'updated_at_2');
$this->renameColumn('{{%column_name_changes}}', 'updated_at_2', 'updated_at');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ class m200000_000000_change_table_addresses extends \yii\db\Migration
{
public function up()
{
$this->addColumn('{{%addresses}}', 'postCode', $this->string(64)->null()->defaultValue(null));
$this->dropIndex('addresses_shortName_postalCode_key', '{{%addresses}}');
$this->renameColumn('{{%addresses}}', 'postalCode', 'postCode');
$this->createIndex('addresses_shortName_postCode_key', '{{%addresses}}', ["shortName", "postCode"], true);
$this->dropColumn('{{%addresses}}', 'postalCode');
}

public function down()
{
$this->addColumn('{{%addresses}}', 'postalCode', $this->string(64)->null()->defaultValue(null));
$this->dropIndex('addresses_shortName_postCode_key', '{{%addresses}}');
$this->renameColumn('{{%addresses}}', 'postCode', 'postalCode');
$this->createIndex('addresses_shortName_postalCode_key', '{{%addresses}}', ["shortName", "postalCode"], true);
$this->dropColumn('{{%addresses}}', 'postCode');
}
}
13 changes: 13 additions & 0 deletions tests/specs/issue_fix/63_just_column_name_rename/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

return [
'openApiPath' => '@specs/issue_fix/63_just_column_name_rename/index.yml',
'generateUrls' => false,
'generateModels' => false,
'excludeModels' => [
'Error',
],
'generateControllers' => false,
'generateMigrations' => true,
'generateModelFaker' => false, // `generateModels` must be `true` in order to use `generateModelFaker` as `true`
];
25 changes: 25 additions & 0 deletions tests/specs/issue_fix/63_just_column_name_rename/index.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
openapi: 3.0.3
info:
title: '63_just_column_name_rename'
version: 1.0.0

components:
schemas:
Fruit:
type: object
properties:
id:
type: integer
name_2:
type: string
description_2:
type: string
colour:
type: string

paths:
'/':
get:
responses:
'200':
description: OK
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* Table for Fruit
*/
class m200000_000000_change_table_fruits extends \yii\db\Migration
{
public function up()
{
$this->renameColumn('{{%fruits}}', 'name', 'name_2');
$this->renameColumn('{{%fruits}}', 'description', 'description_2');
}

public function down()
{
$this->renameColumn('{{%fruits}}', 'description_2', 'description');
$this->renameColumn('{{%fruits}}', 'name_2', 'name');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* Table for Fruit
*/
class m200000_000000_change_table_fruits extends \yii\db\Migration
{
public function safeUp()
{
$this->renameColumn('{{%fruits}}', 'name', 'name_2');
$this->renameColumn('{{%fruits}}', 'description', 'description_2');
}

public function safeDown()
{
$this->renameColumn('{{%fruits}}', 'description_2', 'description');
$this->renameColumn('{{%fruits}}', 'name_2', 'name');
}
}
10 changes: 5 additions & 5 deletions tests/unit/Issue58FixTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use tests\DbTestCase;
use Yii;
use yii\base\InvalidArgumentException;
use yii\helpers\FileHelper;

// This class contains tests for various issues present at GitHub
Expand Down Expand Up @@ -900,7 +899,7 @@ public function test58Move1Add1Del1Col()
description:
type: boolean
col_6:
type: boolean
type: integer
paths:
'/':
get:
Expand All @@ -919,7 +918,7 @@ class m200000_000000_change_table_fruits extends \yii\db\Migration
{
public function up()
{
$this->addColumn('{{%fruits}}', 'col_6', $this->boolean()->null()->defaultValue(null));
$this->addColumn('{{%fruits}}', 'col_6', $this->integer()->null()->defaultValue(null));
$this->dropColumn('{{%fruits}}', 'size');
$this->alterColumn('{{%fruits}}', 'colour', $this->tinyInteger(1)->null()->defaultValue(null)->after('id'));
}
Expand Down Expand Up @@ -962,7 +961,8 @@ public function test58Add1Del1ColAtSamePosition()
name:
type: boolean
description_new:
type: boolean
type: integer
default: 7
colour:
type: boolean
size:
Expand All @@ -985,7 +985,7 @@ class m200000_000000_change_table_fruits extends \yii\db\Migration
{
public function up()
{
$this->addColumn('{{%fruits}}', 'description_new', $this->boolean()->null()->defaultValue(null)->after('name'));
$this->addColumn('{{%fruits}}', 'description_new', $this->integer()->null()->defaultValue(7)->after('name'));
$this->dropColumn('{{%fruits}}', 'description');
}
Expand Down
48 changes: 47 additions & 1 deletion tests/unit/IssueFixTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -742,14 +742,14 @@ public function test3BugAddRemovePropertyAndAtTheSameTimeChangeItAtXIndexes()
$this->createTestTableFor3BugAddRemovePropertyAndAtTheSameTimeChangeItAtXIndexes();
$testFile = Yii::getAlias("@specs/issue_fix/3_bug_add_remove_property_and_at_the_same_time_change_it_at_x_indexes/index.php");
$this->runGenerator($testFile);
$this->runActualMigrations('mysql', 1);
$actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [
'recursive' => true,
]);
$expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/3_bug_add_remove_property_and_at_the_same_time_change_it_at_x_indexes/mysql"), [
'recursive' => true,
]);
$this->checkFiles($actualFiles, $expectedFiles);
$this->runActualMigrations('mysql', 1);
$this->dropTestTableFor3BugAddRemovePropertyAndAtTheSameTimeChangeItAtXIndexes();
}

Expand Down Expand Up @@ -916,4 +916,50 @@ public function test35ResolveTodoReCheckOptionsRouteInRestAction()
$this->checkFiles($actualFiles, $expectedFiles);
}

// https://github.com/php-openapi/yii2-openapi/issues/63
public function test63JustColumnNameRename()
{
$testFile = Yii::getAlias("@specs/issue_fix/63_just_column_name_rename/index.php");

// MySQL
Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute();
Yii::$app->db->createCommand()->createTable('{{%fruits}}', [
'id' => 'pk',
'name' => 'text',
'description' => 'text',
'colour' => 'text',
])->execute();

$this->runGenerator($testFile);
$this->runActualMigrations('mysql', 1);
$actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [
'recursive' => true,
]);
$expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/63_just_column_name_rename/mysql"), [
'recursive' => true,
]);
$this->checkFiles($actualFiles, $expectedFiles);
Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute();

// PgSQL
$this->changeDbToPgsql();
Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute();
Yii::$app->db->createCommand()->createTable('{{%fruits}}', [
'id' => 'pk',
'name' => 'text',
'description' => 'text',
'colour' => 'text',
])->execute();
$this->runGenerator($testFile, 'pgsql');
$this->runActualMigrations('pgsql', 1);
$actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [
'recursive' => true,
'except' => ['migrations_mysql_db']
]);
$expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/63_just_column_name_rename/pgsql"), [
'recursive' => true,
]);
$this->checkFiles($actualFiles, $expectedFiles);
Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute();
}
}

0 comments on commit 36c04a7

Please sign in to comment.