Skip to content

Commit 79bc270

Browse files
committed
Fix issue: case: drop 2 column: its position in add column in down code in migration
1 parent 3718dc6 commit 79bc270

File tree

6 files changed

+72
-21
lines changed

6 files changed

+72
-21
lines changed

src/db/ColumnSchema.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,11 @@ class ColumnSchema extends \yii\db\ColumnSchema
2525
* ```
2626
*/
2727
public $xDbType;
28+
29+
/**
30+
* TODO
31+
* Used only for MySQL/MariaDB
32+
* @var string|null
33+
*/
34+
public ?string $position = null;
2835
}

src/lib/migrations/BaseMigrationBuilder.php

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ function (string $unknownColumn) {
220220
} else {
221221
$this->buildRelations();
222222
}
223+
224+
// $this->handleColumnsPositionsChanges($haveNames, $wantNames);
225+
223226
return $this->migration;
224227
}
225228

@@ -249,12 +252,12 @@ protected function buildColumnsDrop(array $columns):void
249252
{
250253
foreach ($columns as $column) {
251254
$tableName = $this->model->getTableAlias();
255+
$position = $this->findPosition($column, true);
252256
if ($column->isPrimaryKey && !$column->autoIncrement) {
253257
$pkName = 'pk_' . $this->model->tableName . '_' . $column->name;
254258
$this->migration->addDownCode($this->recordBuilder->addPrimaryKey($tableName, [$column->name], $pkName))
255259
->addUpCode($this->recordBuilder->dropPrimaryKey($tableName, [$column->name], $pkName));
256260
}
257-
$position = $this->findPosition($column, true);
258261
$this->migration->addDownCode($this->recordBuilder->addDbColumn($tableName, $column, $position))
259262
->addUpCode($this->recordBuilder->dropColumn($tableName, $column->name));
260263
}
@@ -514,6 +517,8 @@ public function isDefaultValueChanged(
514517
}
515518

516519
/**
520+
* TODO move this method to MysqlMigrationBuilder
521+
* Only for MySQL and MariaDB
517522
* Given a column, compute its previous column name present in OpenAPI schema
518523
* @return ?string
519524
* `null` if column is added at last
@@ -528,24 +533,26 @@ public function findPosition(ColumnSchema $column, bool $forDrop = false): ?stri
528533
if ($key > 0) {
529534
$prevColName = $columnNames[$key-1];
530535

531-
if (!isset($columnNames[$key+1])) { // if new col is added at last then no need to add 'AFTER' SQL part. This is checked as if next column is present or not
536+
if (!$forDrop && !isset($columnNames[$key+1])) { // if new col is added at last then no need to add 'AFTER' SQL part. This is checked as if next column is present or not
532537
return null;
533538
}
534539

535-
// in case of `down()` code of migration, putting 'after <colName>' in add column statmenet is erroneous because <colName> may not exist.
540+
// in case of `down()` code of migration, putting 'after <colName>' in add column statement is erroneous because <colName> may not exist.
536541
// Example: From col a, b, c, d, if I drop c and d then their migration code will be generated like:
537542
// `up()` code
538543
// drop c
539544
// drop d
540545
// `down()` code
541-
// add d after c (c does not exist! Error!)
542-
// add c
546+
// add d after c (c does not exist! Error!) (TODO check if c is present in newColumn)
547+
// add c after b (can fix this issue) TODO
543548
if ($forDrop) {
544-
return null;
549+
// return null; // TODO this case can be fixed
545550
}
546551

547-
548-
return self::POS_AFTER . ' ' . $prevColName;
552+
if (array_key_exists($prevColName, $this->newColumns)) {
553+
return self::POS_AFTER . ' ' . $prevColName;
554+
}
555+
return null;
549556

550557
// if no `$columnSchema` is found, previous column does not exist. This happens when 'after column' is not yet added in migration or added after currently undertaken column
551558
} elseif ($key === 0) {
@@ -574,4 +581,20 @@ public function modifyDesiredInContextOfDesiredFromDb(ColumnSchema $desired, Col
574581
}
575582
$desired->dbType = $desiredFromDb->dbType;
576583
}
584+
585+
// TODO
586+
public function handleColumnsPositionsChanges(array $haveNames, array $wantNames)
587+
{
588+
$indices = [];
589+
if ($haveNames !== $wantNames) {
590+
foreach ($wantNames as $key => $name) {
591+
if ($name !== $haveNames[$key]) {
592+
$indices[] = $key;
593+
}
594+
}
595+
}
596+
for ($i = 0; $i < count($indices)/2; $i++) {
597+
$this->migration->addUpCode($this->recordBuilder->alterColumn());
598+
}
599+
}
577600
}

src/lib/migrations/MigrationRecordBuilder.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public function addDbColumn(string $tableAlias, ColumnSchema $column, ?string $p
112112
/**
113113
* @throws \yii\base\InvalidConfigException
114114
*/
115-
public function alterColumn(string $tableAlias, ColumnSchema $column):string
115+
public function alterColumn(string $tableAlias, ColumnSchema $column, ?string $position = null):string # TODO
116116
{
117117
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
118118
$converter = $this->columnToCode($tableAlias, $column, true, false, true, true);
@@ -130,7 +130,12 @@ public function alterColumn(string $tableAlias, ColumnSchema $column):string
130130
/**
131131
* @throws \yii\base\InvalidConfigException
132132
*/
133-
public function alterColumnType(string $tableAlias, ColumnSchema $column, bool $addUsing = false):string
133+
public function alterColumnType(
134+
string $tableAlias,
135+
ColumnSchema $column,
136+
bool $addUsing = false,
137+
?string $position = null
138+
):string # TODO
134139
{
135140
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
136141
$converter = $this->columnToCode($tableAlias, $column, false, false, true, true);
@@ -149,7 +154,12 @@ public function alterColumnType(string $tableAlias, ColumnSchema $column, bool $
149154
* This method is only used in Pgsql
150155
* @throws \yii\base\InvalidConfigException
151156
*/
152-
public function alterColumnTypeFromDb(string $tableAlias, ColumnSchema $column, bool $addUsing = false) :string
157+
public function alterColumnTypeFromDb(
158+
string $tableAlias,
159+
ColumnSchema $column,
160+
bool $addUsing = false,
161+
?string $position = null
162+
) :string # TODO
153163
{
154164
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
155165
$converter = $this->columnToCode($tableAlias, $column, true, false, true, true);

src/lib/migrations/MysqlMigrationBuilder.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,15 @@ final class MysqlMigrationBuilder extends BaseMigrationBuilder
2626
protected function buildColumnChanges(ColumnSchema $current, ColumnSchema $desired, array $changed):void
2727
{
2828
$newColumn = clone $current;
29+
$position = $this->findPosition($desired);
2930
foreach ($changed as $attr) {
3031
$newColumn->$attr = $desired->$attr;
3132
}
3233
if (static::isEnum($newColumn)) {
3334
$newColumn->dbType = 'enum'; // TODO this is concretely not correct
3435
}
35-
$this->migration->addUpCode($this->recordBuilder->alterColumn($this->model->getTableAlias(), $newColumn))
36-
->addDownCode($this->recordBuilder->alterColumn($this->model->getTableAlias(), $current));
36+
$this->migration->addUpCode($this->recordBuilder->alterColumn($this->model->getTableAlias(), $newColumn, $position))
37+
->addDownCode($this->recordBuilder->alterColumn($this->model->getTableAlias(), $current, $position));
3738
}
3839

3940
protected function compareColumns(ColumnSchema $current, ColumnSchema $desired):array
@@ -159,4 +160,14 @@ public function modifyDesiredInContextOfCurrent(ColumnSchema $current, ColumnSch
159160
$desired->size = $current->size;
160161
}
161162
}
163+
164+
/**
165+
* TODO
166+
* Check if order/position of column is changed
167+
* @return void
168+
*/
169+
public function checkOrder()
170+
{
171+
172+
}
162173
}

tests/specs/issue_fix/58_create_migration_for_column_position_change_if_a_field_position_is_changed_in_spec/index.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ components:
1111
properties:
1212
id:
1313
type: integer
14-
name:
15-
type: string
16-
description: desc
17-
# colour:
18-
# type: string
19-
description:
20-
type: string
14+
# name: # TODO
15+
# type: string
16+
# description: desc
17+
# colour:
18+
# type: string
19+
# description:
20+
# type: string
2121

2222
paths:
2323
'/':

tests/unit/IssueFixTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ private function createTableFor58CreateMigrationForColumnPositionChangeIfAFieldP
384384
Yii::$app->db->createCommand()->createTable('{{%fruits}}', [
385385
'id' => 'pk',
386386
'description' => 'text',
387-
'name' => 'varchar(255) COMMENT "some-comment"',
387+
'name' => 'text',
388388
])->execute();
389389
}
390390

0 commit comments

Comments
 (0)