Skip to content

Commit 36c04a7

Browse files
authored
Merge pull request #72 from php-openapi/63-just-column-name-rename
Resolve: Just column name rename #63
2 parents ca23577 + 369fdca commit 36c04a7

File tree

13 files changed

+208
-26
lines changed

13 files changed

+208
-26
lines changed

docker-compose.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ services:
4141
MYSQL_DATABASE: testdb
4242

4343
maria:
44-
image: mariadb:10.8
44+
image: mariadb:10.8.2
4545
ports:
4646
- '23306:3306'
4747
volumes:

src/lib/migrations/BaseMigrationBuilder.php

+65-3
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,10 @@ function (string $unknownColumn) {
199199

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

202+
$fromColNameToColName = $this->handleColumnsRename($columnsForCreate, $columnsForDrop, $this->newColumns);
203+
202204
if ($this->model->drop) {
203205
$this->newColumns = [];
204-
$wantNames = [];
205206
$columnsForCreate = [];
206207
$columnsForChange = [];
207208
$columnsForDrop = [];
@@ -218,7 +219,9 @@ function (string $unknownColumn) {
218219
}
219220

220221
if (!$relation) {
221-
$this->buildIndexChanges();
222+
$this->buildIndexChanges($fromColNameToColName);
223+
} else {
224+
$this->migrationForRenameColumn($fromColNameToColName);
222225
}
223226

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

304307
abstract public function handleCommentsMigration();
305308

306-
protected function buildIndexChanges():void
309+
protected function buildIndexChanges(array $fromColNameToColName): void
307310
{
308311
$haveIndexes = $this->findTableIndexes();
309312
$wantIndexes = $this->model->indexes;
@@ -338,6 +341,9 @@ function ($idx) use ($wantIndexes) {
338341
$this->migration->addUpCode($this->recordBuilder->dropIndex($tableName, $index->name))
339342
->addDownCode($downCode);
340343
}
344+
345+
$this->migrationForRenameColumn($fromColNameToColName);
346+
341347
foreach ($forCreate as $index) {
342348
$upCode = $index->isUnique
343349
? $this->recordBuilder->addUniqueIndex($tableName, $index->name, $index->columns)
@@ -614,4 +620,60 @@ protected function shouldCompareComment(ColumnSchema $desired): bool
614620
}
615621
return $comment;
616622
}
623+
624+
/**
625+
* @param array $columnsForCreate
626+
* @param array $columnsForDrop
627+
* @param $newColumns
628+
* @return array key is previous/old column name and value is new column name
629+
*/
630+
public function handleColumnsRename(array &$columnsForCreate, array &$columnsForDrop, $newColumns): array
631+
{
632+
$keys = [];
633+
$fromColNameToColName = [];
634+
$existingColumns = $this->tableSchema->columns;
635+
if (count($existingColumns) !== count($newColumns)) {
636+
return $fromColNameToColName;
637+
}
638+
$existingColumnNames = array_keys($existingColumns);
639+
$newColumnNames = array_flip(array_keys($newColumns));
640+
foreach ($columnsForCreate as $key => $column) {
641+
$index = $newColumnNames[$column->name];
642+
$previousColumnName = $existingColumnNames[$index] ?? null;
643+
if ($previousColumnName) {
644+
$current = $existingColumns[$previousColumnName];
645+
$desired = $newColumns[$column->name];
646+
$changedAttributes = $this->compareColumns(clone $current, clone $desired);
647+
if (empty($changedAttributes)) {
648+
$keys[] = $key;
649+
$dropKeyOut = null;
650+
array_walk($columnsForDrop, function ($value, $dropKey) use ($previousColumnName, &$dropKeyOut) {
651+
if ($value->name === $previousColumnName) {
652+
$dropKeyOut = $dropKey;
653+
}
654+
});
655+
// existing column name should be removed from $columnsForDrop
656+
unset($columnsForDrop[$dropKeyOut]);
657+
658+
// Create ALTER COLUMN NAME query
659+
// see `migrationForRenameColumn()`
660+
$fromColNameToColName[$previousColumnName] = $column->name;
661+
}
662+
}
663+
}
664+
665+
// new column name should be removed from $columnsForCreate
666+
foreach ($keys as $key) {
667+
unset($columnsForCreate[$key]);
668+
}
669+
return $fromColNameToColName;
670+
}
671+
672+
public function migrationForRenameColumn(array $fromColNameToColName): void
673+
{
674+
foreach ($fromColNameToColName as $previousColumnName => $columnName) {
675+
$this->migration->addUpCode($this->recordBuilder->renameColumn($this->model->tableAlias, $previousColumnName, $columnName))
676+
->addDownCode($this->recordBuilder->renameColumn($this->model->tableAlias, $columnName, $previousColumnName));
677+
}
678+
}
617679
}

src/lib/migrations/MigrationRecordBuilder.php

+6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ final class MigrationRecordBuilder
4949
public const ADD_COMMENT_ON_COLUMN = MigrationRecordBuilder::INDENT . "\$this->addCommentOnColumn('%s', '%s', %s);";
5050

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

5354
/**
5455
* @var \yii\db\Schema
@@ -387,4 +388,9 @@ public function dropCommentFromColumn($table, string $column): string
387388
{
388389
return sprintf(self::DROP_COMMENT_FROM_COLUMN, $table, $column);
389390
}
391+
392+
public function renameColumn(string $table, string $fromColumn, string $toColumn): string
393+
{
394+
return sprintf(self::RENAME_COLUMN, $table, $fromColumn, $toColumn);
395+
}
390396
}

tests/specs/change_column_name/maria/app/migrations_maria_db/m200000_000000_change_table_column_name_changes.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ class m200000_000000_change_table_column_name_changes extends \yii\db\Migration
77
{
88
public function up()
99
{
10-
$this->db->createCommand('ALTER TABLE {{%column_name_changes}} ADD COLUMN updated_at_2 datetime NOT NULL')->execute();
11-
$this->dropColumn('{{%column_name_changes}}', 'updated_at');
10+
$this->renameColumn('{{%column_name_changes}}', 'updated_at', 'updated_at_2');
1211
}
1312

1413
public function down()
1514
{
16-
$this->addColumn('{{%column_name_changes}}', 'updated_at', $this->datetime()->notNull());
17-
$this->dropColumn('{{%column_name_changes}}', 'updated_at_2');
15+
$this->renameColumn('{{%column_name_changes}}', 'updated_at_2', 'updated_at');
1816
}
1917
}

tests/specs/change_column_name/mysql/app/migrations_mysql_db/m200000_000000_change_table_column_name_changes.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ class m200000_000000_change_table_column_name_changes extends \yii\db\Migration
77
{
88
public function up()
99
{
10-
$this->db->createCommand('ALTER TABLE {{%column_name_changes}} ADD COLUMN updated_at_2 datetime NOT NULL')->execute();
11-
$this->dropColumn('{{%column_name_changes}}', 'updated_at');
10+
$this->renameColumn('{{%column_name_changes}}', 'updated_at', 'updated_at_2');
1211
}
1312

1413
public function down()
1514
{
16-
$this->addColumn('{{%column_name_changes}}', 'updated_at', $this->datetime()->notNull());
17-
$this->dropColumn('{{%column_name_changes}}', 'updated_at_2');
15+
$this->renameColumn('{{%column_name_changes}}', 'updated_at_2', 'updated_at');
1816
}
1917
}

tests/specs/change_column_name/pgsql/app/migrations_pgsql_db/m200000_000000_change_table_column_name_changes.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ class m200000_000000_change_table_column_name_changes extends \yii\db\Migration
77
{
88
public function safeUp()
99
{
10-
$this->db->createCommand('ALTER TABLE {{%column_name_changes}} ADD COLUMN "updated_at_2" timestamp NOT NULL')->execute();
11-
$this->dropColumn('{{%column_name_changes}}', 'updated_at');
10+
$this->renameColumn('{{%column_name_changes}}', 'updated_at', 'updated_at_2');
1211
}
1312

1413
public function safeDown()
1514
{
16-
$this->addColumn('{{%column_name_changes}}', 'updated_at', $this->timestamp()->notNull());
17-
$this->dropColumn('{{%column_name_changes}}', 'updated_at_2');
15+
$this->renameColumn('{{%column_name_changes}}', 'updated_at_2', 'updated_at');
1816
}
1917
}

tests/specs/issue_fix/3_bug_add_remove_property_and_at_the_same_time_change_it_at_x_indexes/mysql/migrations_mysql_db/m200000_000000_change_table_addresses.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@ class m200000_000000_change_table_addresses extends \yii\db\Migration
77
{
88
public function up()
99
{
10-
$this->addColumn('{{%addresses}}', 'postCode', $this->string(64)->null()->defaultValue(null));
1110
$this->dropIndex('addresses_shortName_postalCode_key', '{{%addresses}}');
11+
$this->renameColumn('{{%addresses}}', 'postalCode', 'postCode');
1212
$this->createIndex('addresses_shortName_postCode_key', '{{%addresses}}', ["shortName", "postCode"], true);
13-
$this->dropColumn('{{%addresses}}', 'postalCode');
1413
}
1514

1615
public function down()
1716
{
18-
$this->addColumn('{{%addresses}}', 'postalCode', $this->string(64)->null()->defaultValue(null));
1917
$this->dropIndex('addresses_shortName_postCode_key', '{{%addresses}}');
18+
$this->renameColumn('{{%addresses}}', 'postCode', 'postalCode');
2019
$this->createIndex('addresses_shortName_postalCode_key', '{{%addresses}}', ["shortName", "postalCode"], true);
21-
$this->dropColumn('{{%addresses}}', 'postCode');
2220
}
2321
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
return [
4+
'openApiPath' => '@specs/issue_fix/63_just_column_name_rename/index.yml',
5+
'generateUrls' => false,
6+
'generateModels' => false,
7+
'excludeModels' => [
8+
'Error',
9+
],
10+
'generateControllers' => false,
11+
'generateMigrations' => true,
12+
'generateModelFaker' => false, // `generateModels` must be `true` in order to use `generateModelFaker` as `true`
13+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
openapi: 3.0.3
2+
info:
3+
title: '63_just_column_name_rename'
4+
version: 1.0.0
5+
6+
components:
7+
schemas:
8+
Fruit:
9+
type: object
10+
properties:
11+
id:
12+
type: integer
13+
name_2:
14+
type: string
15+
description_2:
16+
type: string
17+
colour:
18+
type: string
19+
20+
paths:
21+
'/':
22+
get:
23+
responses:
24+
'200':
25+
description: OK
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/**
4+
* Table for Fruit
5+
*/
6+
class m200000_000000_change_table_fruits extends \yii\db\Migration
7+
{
8+
public function up()
9+
{
10+
$this->renameColumn('{{%fruits}}', 'name', 'name_2');
11+
$this->renameColumn('{{%fruits}}', 'description', 'description_2');
12+
}
13+
14+
public function down()
15+
{
16+
$this->renameColumn('{{%fruits}}', 'description_2', 'description');
17+
$this->renameColumn('{{%fruits}}', 'name_2', 'name');
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/**
4+
* Table for Fruit
5+
*/
6+
class m200000_000000_change_table_fruits extends \yii\db\Migration
7+
{
8+
public function safeUp()
9+
{
10+
$this->renameColumn('{{%fruits}}', 'name', 'name_2');
11+
$this->renameColumn('{{%fruits}}', 'description', 'description_2');
12+
}
13+
14+
public function safeDown()
15+
{
16+
$this->renameColumn('{{%fruits}}', 'description_2', 'description');
17+
$this->renameColumn('{{%fruits}}', 'name_2', 'name');
18+
}
19+
}

tests/unit/Issue58FixTest.php

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use tests\DbTestCase;
66
use Yii;
7-
use yii\base\InvalidArgumentException;
87
use yii\helpers\FileHelper;
98

109
// This class contains tests for various issues present at GitHub
@@ -900,7 +899,7 @@ public function test58Move1Add1Del1Col()
900899
description:
901900
type: boolean
902901
col_6:
903-
type: boolean
902+
type: integer
904903
paths:
905904
'/':
906905
get:
@@ -919,7 +918,7 @@ class m200000_000000_change_table_fruits extends \yii\db\Migration
919918
{
920919
public function up()
921920
{
922-
$this->addColumn('{{%fruits}}', 'col_6', $this->boolean()->null()->defaultValue(null));
921+
$this->addColumn('{{%fruits}}', 'col_6', $this->integer()->null()->defaultValue(null));
923922
$this->dropColumn('{{%fruits}}', 'size');
924923
$this->alterColumn('{{%fruits}}', 'colour', $this->tinyInteger(1)->null()->defaultValue(null)->after('id'));
925924
}
@@ -962,7 +961,8 @@ public function test58Add1Del1ColAtSamePosition()
962961
name:
963962
type: boolean
964963
description_new:
965-
type: boolean
964+
type: integer
965+
default: 7
966966
colour:
967967
type: boolean
968968
size:
@@ -985,7 +985,7 @@ class m200000_000000_change_table_fruits extends \yii\db\Migration
985985
{
986986
public function up()
987987
{
988-
$this->addColumn('{{%fruits}}', 'description_new', $this->boolean()->null()->defaultValue(null)->after('name'));
988+
$this->addColumn('{{%fruits}}', 'description_new', $this->integer()->null()->defaultValue(7)->after('name'));
989989
$this->dropColumn('{{%fruits}}', 'description');
990990
}
991991

tests/unit/IssueFixTest.php

+47-1
Original file line numberDiff line numberDiff line change
@@ -742,14 +742,14 @@ public function test3BugAddRemovePropertyAndAtTheSameTimeChangeItAtXIndexes()
742742
$this->createTestTableFor3BugAddRemovePropertyAndAtTheSameTimeChangeItAtXIndexes();
743743
$testFile = Yii::getAlias("@specs/issue_fix/3_bug_add_remove_property_and_at_the_same_time_change_it_at_x_indexes/index.php");
744744
$this->runGenerator($testFile);
745-
$this->runActualMigrations('mysql', 1);
746745
$actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [
747746
'recursive' => true,
748747
]);
749748
$expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/3_bug_add_remove_property_and_at_the_same_time_change_it_at_x_indexes/mysql"), [
750749
'recursive' => true,
751750
]);
752751
$this->checkFiles($actualFiles, $expectedFiles);
752+
$this->runActualMigrations('mysql', 1);
753753
$this->dropTestTableFor3BugAddRemovePropertyAndAtTheSameTimeChangeItAtXIndexes();
754754
}
755755

@@ -916,4 +916,50 @@ public function test35ResolveTodoReCheckOptionsRouteInRestAction()
916916
$this->checkFiles($actualFiles, $expectedFiles);
917917
}
918918

919+
// https://github.com/php-openapi/yii2-openapi/issues/63
920+
public function test63JustColumnNameRename()
921+
{
922+
$testFile = Yii::getAlias("@specs/issue_fix/63_just_column_name_rename/index.php");
923+
924+
// MySQL
925+
Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute();
926+
Yii::$app->db->createCommand()->createTable('{{%fruits}}', [
927+
'id' => 'pk',
928+
'name' => 'text',
929+
'description' => 'text',
930+
'colour' => 'text',
931+
])->execute();
932+
933+
$this->runGenerator($testFile);
934+
$this->runActualMigrations('mysql', 1);
935+
$actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [
936+
'recursive' => true,
937+
]);
938+
$expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/63_just_column_name_rename/mysql"), [
939+
'recursive' => true,
940+
]);
941+
$this->checkFiles($actualFiles, $expectedFiles);
942+
Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute();
943+
944+
// PgSQL
945+
$this->changeDbToPgsql();
946+
Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute();
947+
Yii::$app->db->createCommand()->createTable('{{%fruits}}', [
948+
'id' => 'pk',
949+
'name' => 'text',
950+
'description' => 'text',
951+
'colour' => 'text',
952+
])->execute();
953+
$this->runGenerator($testFile, 'pgsql');
954+
$this->runActualMigrations('pgsql', 1);
955+
$actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [
956+
'recursive' => true,
957+
'except' => ['migrations_mysql_db']
958+
]);
959+
$expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/63_just_column_name_rename/pgsql"), [
960+
'recursive' => true,
961+
]);
962+
$this->checkFiles($actualFiles, $expectedFiles);
963+
Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute();
964+
}
919965
}

0 commit comments

Comments
 (0)