Skip to content

Resolve: Just column name rename #63 #72

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
}
}
Loading