Skip to content
This repository was archived by the owner on Jun 4, 2024. It is now read-only.

Commit e2fc2e9

Browse files
authored
Merge pull request #10 from SOHELAHMED7/128-change-enum-name-generation-in-pgsql-and-quote-it
Draft - Fix #128 - Change Enum name generation in PgSQL and quote it
2 parents 1cdb53b + d4f6f2d commit e2fc2e9

32 files changed

+544
-102
lines changed

src/lib/ColumnToCode.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ class ColumnToCode
5353
*/
5454
private $dbSchema;
5555

56+
/**
57+
* @var string
58+
* @example {{%table}}
59+
*/
60+
private $tableAlias;
61+
5662
/**
5763
* @var bool
5864
*/
@@ -107,13 +113,15 @@ class ColumnToCode
107113
*/
108114
public function __construct(
109115
Schema $dbSchema,
116+
string $tableAlias,
110117
ColumnSchema $column,
111118
bool $fromDb = false,
112119
bool $alter = false,
113120
bool $raw = false,
114121
bool $alterByXDbType = false
115122
) {
116123
$this->dbSchema = $dbSchema;
124+
$this->tableAlias = $tableAlias;
117125
$this->column = $column;
118126
$this->fromDb = $fromDb;
119127
$this->alter = $alter;
@@ -160,7 +168,9 @@ public function getCode(bool $quoted = false):string
160168
public function getAlterExpression(bool $addUsingExpression = false):string
161169
{
162170
if ($this->isEnum() && ApiGenerator::isPostgres()) {
163-
return "'" . sprintf('enum_%1$s USING "%1$s"::enum_%1$s', $this->column->name) . "'";
171+
$rawTableName = $this->dbSchema->getRawTableName($this->tableAlias);
172+
$enumTypeName = 'enum_'.$rawTableName.'_'.$this->column->name;
173+
return "'" . sprintf($enumTypeName.' USING "%1$s"::"'.$enumTypeName.'"', $this->column->name) . "'";
164174
}
165175
if ($this->column->dbType === 'tsvector') {
166176
return "'" . $this->rawParts['type'] . "'";
@@ -368,7 +378,8 @@ private function getIsBuiltinType($type, $dbType)
368378
private function resolveEnumType():void
369379
{
370380
if (ApiGenerator::isPostgres()) {
371-
$this->rawParts['type'] = 'enum_' . $this->column->name;
381+
$rawTableName = $this->dbSchema->getRawTableName($this->tableAlias);
382+
$this->rawParts['type'] = 'enum_'.$rawTableName.'_' . $this->column->name;
372383
return;
373384
}
374385
$this->rawParts['type'] = 'enum(' . self::mysqlEnumToString($this->column->enumValues) . ')';

src/lib/migrations/BaseMigrationBuilder.php

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -409,25 +409,27 @@ protected function isNeedUsingExpression(string $fromDbType, string $toDbType):b
409409
}
410410

411411
// temporary save new/changed/desired column to temporary table. If saved we can fetch it from DB and then it can be used to compare with current column
412-
public function tmpSaveNewCol(\cebe\yii2openapi\db\ColumnSchema $columnSchema): \yii\db\ColumnSchema
412+
public function tmpSaveNewCol(string $tableAlias, \cebe\yii2openapi\db\ColumnSchema $columnSchema): \yii\db\ColumnSchema
413413
{
414-
$tableName = 'tmp_table_';
414+
$tmpTableName = 'tmp_table_';
415415
$tmpEnumName = function (string $columnName): string {
416416
return '"tmp_enum_'.$columnName.'_"';
417417
};
418+
$rawTableName = $this->db->schema->getRawTableName($tableAlias);
419+
$innerEnumTypeName = "enum_{$tmpTableName}_$columnSchema->name";
418420

419-
Yii::$app->db->createCommand('DROP TABLE IF EXISTS '.$tableName)->execute();
421+
Yii::$app->db->createCommand('DROP TABLE IF EXISTS '.$tmpTableName)->execute();
420422

421423
if (is_string($columnSchema->xDbType) && !empty($columnSchema->xDbType)) {
422424
$name = MigrationRecordBuilder::quote($columnSchema->name);
423-
$column = [$name.' '.$this->newColStr($columnSchema)];
425+
$column = [$name.' '.$this->newColStr($tmpTableName, $columnSchema)];
424426
if (ApiGenerator::isPostgres() && static::isEnum($columnSchema)) {
425-
$column = strtr($column, ['enum_'.$columnSchema->name => $tmpEnumName($columnSchema->name)]);
427+
$column = strtr($column, [$innerEnumTypeName => $tmpEnumName($columnSchema->name)]);
426428
}
427429
} else {
428-
$column = [$columnSchema->name => $this->newColStr($columnSchema)];
430+
$column = [$columnSchema->name => $this->newColStr($tmpTableName, $columnSchema)];
429431
if (ApiGenerator::isPostgres() && static::isEnum($columnSchema)) {
430-
$column[$columnSchema->name] = strtr($column[$columnSchema->name], ['enum_'.$columnSchema->name => $tmpEnumName($columnSchema->name)]);
432+
$column[$columnSchema->name] = strtr($column[$columnSchema->name], [$innerEnumTypeName => $tmpEnumName($columnSchema->name)]);
431433
}
432434
}
433435

@@ -442,11 +444,11 @@ public function tmpSaveNewCol(\cebe\yii2openapi\db\ColumnSchema $columnSchema):
442444
)->execute();
443445
}
444446

445-
Yii::$app->db->createCommand()->createTable($tableName, $column)->execute();
447+
Yii::$app->db->createCommand()->createTable($tmpTableName, $column)->execute();
446448

447-
$table = Yii::$app->db->getTableSchema($tableName);
449+
$table = Yii::$app->db->getTableSchema($tmpTableName);
448450

449-
Yii::$app->db->createCommand()->dropTable($tableName)->execute();
451+
Yii::$app->db->createCommand()->dropTable($tmpTableName)->execute();
450452

451453
if (ApiGenerator::isPostgres() && static::isEnum($columnSchema)) {// drop enum
452454
Yii::$app->db->createCommand('DROP TYPE '.$tmpEnumName($columnSchema->name))->execute();
@@ -455,15 +457,15 @@ public function tmpSaveNewCol(\cebe\yii2openapi\db\ColumnSchema $columnSchema):
455457
}
456458
// reset back column enum name to original as we are comparing with current
457459
// e.g. we get different enum type name such as `enum_status` and `tmp_enum_status_` even there is no change, so below statement fix this issue
458-
$table->columns[$columnSchema->name]->dbType = 'enum_'.$columnSchema->name;
460+
$table->columns[$columnSchema->name]->dbType = 'enum_'.$rawTableName.'_'.$columnSchema->name;
459461
}
460462

461463
return $table->columns[$columnSchema->name];
462464
}
463465

464-
public function newColStr(\cebe\yii2openapi\db\ColumnSchema $columnSchema): string
466+
public function newColStr(string $tableAlias, \cebe\yii2openapi\db\ColumnSchema $columnSchema): string
465467
{
466-
$ctc = new ColumnToCode(\Yii::$app->db->schema, $columnSchema, false, false, true);
468+
$ctc = new ColumnToCode(\Yii::$app->db->schema, $tableAlias, $columnSchema, false, false, true);
467469
return ColumnToCode::undoEscapeQuotes($ctc->getCode());
468470
}
469471

src/lib/migrations/MigrationRecordBuilder.php

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ final class MigrationRecordBuilder
2727
public const ADD_UNIQUE = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', '%s', true);";
2828
public const ADD_INDEX = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', '%s', %s);";
2929
public const DROP_COLUMN = MigrationRecordBuilder::INDENT . "\$this->dropColumn('%s', '%s');";
30-
public const ADD_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('CREATE TYPE enum_%s AS ENUM(%s)');";
31-
public const DROP_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('DROP TYPE enum_%s');";
30+
public const ADD_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('CREATE TYPE \"enum_%s_%s\" AS ENUM(%s)');";
31+
public const DROP_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('DROP TYPE \"enum_%s_%s\"');";
3232
public const DROP_TABLE = MigrationRecordBuilder::INDENT . "\$this->dropTable('%s');";
3333
public const ADD_FK = MigrationRecordBuilder::INDENT . "\$this->addForeignKey('%s', '%s', '%s', '%s', '%s');";
3434
public const ADD_PK = MigrationRecordBuilder::INDENT . "\$this->addPrimaryKey('%s', '%s', '%s');";
@@ -64,9 +64,9 @@ public function createTable(string $tableAlias, array $columns):string
6464
foreach ($columns as $columnName => $cebeDbColumnSchema) {
6565
if (is_string($cebeDbColumnSchema->xDbType) && !empty($cebeDbColumnSchema->xDbType)) {
6666
$name = static::quote($columnName);
67-
$codeColumns[] = $name.' '.$this->columnToCode($cebeDbColumnSchema, false)->getCode();
67+
$codeColumns[] = $name.' '.$this->columnToCode($tableAlias, $cebeDbColumnSchema, false)->getCode();
6868
} else {
69-
$codeColumns[$columnName] = $this->columnToCode($cebeDbColumnSchema, false)->getCode();
69+
$codeColumns[$columnName] = $this->columnToCode($tableAlias, $cebeDbColumnSchema, false)->getCode();
7070
}
7171
}
7272

@@ -80,12 +80,12 @@ public function createTable(string $tableAlias, array $columns):string
8080
public function addColumn(string $tableAlias, ColumnSchema $column):string
8181
{
8282
if (is_string($column->xDbType) && !empty($column->xDbType)) {
83-
$converter = $this->columnToCode($column, false);
83+
$converter = $this->columnToCode($tableAlias, $column, false);
8484
$name = static::quote($column->name);
8585
return sprintf(self::ADD_COLUMN_RAW, $tableAlias, $name, $converter->getCode());
8686
}
8787

88-
$converter = $this->columnToCode($column, false);
88+
$converter = $this->columnToCode($tableAlias, $column, false);
8989
return sprintf(self::ADD_COLUMN, $tableAlias, $column->name, $converter->getCode(true));
9090
}
9191

@@ -95,11 +95,11 @@ public function addColumn(string $tableAlias, ColumnSchema $column):string
9595
public function addDbColumn(string $tableAlias, ColumnSchema $column):string
9696
{
9797
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
98-
$converter = $this->columnToCode($column, true);
98+
$converter = $this->columnToCode($tableAlias, $column, true);
9999
$name = static::quote($column->name);
100100
return sprintf(self::ADD_COLUMN_RAW, $tableAlias, $column->name, $converter->getCode());
101101
}
102-
$converter = $this->columnToCode($column, true);
102+
$converter = $this->columnToCode($tableAlias, $column, true);
103103
return sprintf(self::ADD_COLUMN, $tableAlias, $column->name, $converter->getCode(true));
104104
}
105105

@@ -109,15 +109,15 @@ public function addDbColumn(string $tableAlias, ColumnSchema $column):string
109109
public function alterColumn(string $tableAlias, ColumnSchema $column):string
110110
{
111111
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
112-
$converter = $this->columnToCode($column, true, false, true, true);
112+
$converter = $this->columnToCode($tableAlias, $column, true, false, true, true);
113113
return sprintf(
114114
ApiGenerator::isPostgres() ? self::ALTER_COLUMN_RAW_PGSQL : self::ALTER_COLUMN_RAW,
115115
$tableAlias,
116116
$column->name,
117117
$converter->getCode()
118118
);
119119
}
120-
$converter = $this->columnToCode($column, true);
120+
$converter = $this->columnToCode($tableAlias, $column, true);
121121
return sprintf(self::ALTER_COLUMN, $tableAlias, $column->name, $converter->getCode(true));
122122
}
123123

@@ -127,15 +127,15 @@ public function alterColumn(string $tableAlias, ColumnSchema $column):string
127127
public function alterColumnType(string $tableAlias, ColumnSchema $column, bool $addUsing = false):string
128128
{
129129
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
130-
$converter = $this->columnToCode($column, false, false, true, true);
130+
$converter = $this->columnToCode($tableAlias, $column, false, false, true, true);
131131
return sprintf(
132132
ApiGenerator::isPostgres() ? self::ALTER_COLUMN_RAW_PGSQL : self::ALTER_COLUMN_RAW,
133133
$tableAlias,
134134
$column->name,
135135
rtrim(ltrim($converter->getAlterExpression($addUsing), "'"), "'")
136136
);
137137
}
138-
$converter = $this->columnToCode($column, false);
138+
$converter = $this->columnToCode($tableAlias, $column, false);
139139
return sprintf(self::ALTER_COLUMN, $tableAlias, $column->name, $converter->getAlterExpression($addUsing));
140140
}
141141

@@ -145,15 +145,15 @@ public function alterColumnType(string $tableAlias, ColumnSchema $column, bool $
145145
public function alterColumnTypeFromDb(string $tableAlias, ColumnSchema $column, bool $addUsing = false) :string
146146
{
147147
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
148-
$converter = $this->columnToCode($column, true, false, true, true);
148+
$converter = $this->columnToCode($tableAlias, $column, true, false, true, true);
149149
return sprintf(
150150
ApiGenerator::isPostgres() ? self::ALTER_COLUMN_RAW_PGSQL : self::ALTER_COLUMN_RAW,
151151
$tableAlias,
152152
$column->name,
153153
rtrim(ltrim($converter->getAlterExpression($addUsing), "'"), "'")
154154
);
155155
}
156-
$converter = $this->columnToCode($column, true);
156+
$converter = $this->columnToCode($tableAlias, $column, true);
157157
return sprintf(self::ALTER_COLUMN, $tableAlias, $column->name, $converter->getAlterExpression($addUsing));
158158
}
159159

@@ -162,7 +162,7 @@ public function alterColumnTypeFromDb(string $tableAlias, ColumnSchema $column,
162162
*/
163163
public function setColumnDefault(string $tableAlias, ColumnSchema $column):string
164164
{
165-
$default = $this->columnToCode($column, false, true)->getDefaultValue();
165+
$default = $this->columnToCode($tableAlias, $column, false, true)->getDefaultValue();
166166
if ($default === null) {
167167
return '';
168168
}
@@ -174,7 +174,7 @@ public function setColumnDefault(string $tableAlias, ColumnSchema $column):strin
174174
*/
175175
public function setColumnDefaultFromDb(string $tableAlias, ColumnSchema $column):string
176176
{
177-
$default = $this->columnToCode($column, true, true)->getDefaultValue();
177+
$default = $this->columnToCode($tableAlias, $column, true, true)->getDefaultValue();
178178
if ($default === null) {
179179
return '';
180180
}
@@ -196,9 +196,10 @@ public function dropColumnNotNull(string $tableAlias, ColumnSchema $column):stri
196196
return sprintf(self::ALTER_COLUMN, $tableAlias, $column->name, '"DROP NOT NULL"');
197197
}
198198

199-
public function createEnum(string $columnName, array $values):string
199+
public function createEnum(string $tableAlias, string $columnName, array $values):string
200200
{
201-
return sprintf(self::ADD_ENUM, $columnName, ColumnToCode::enumToString($values));
201+
$rawTableName = $this->dbSchema->getRawTableName($tableAlias);
202+
return sprintf(self::ADD_ENUM, $rawTableName, $columnName, ColumnToCode::enumToString($values));
202203
}
203204

204205
public function addFk(string $fkName, string $tableAlias, string $fkCol, string $refTable, string $refCol):string
@@ -234,9 +235,10 @@ public function dropTable(string $tableAlias):string
234235
return sprintf(self::DROP_TABLE, $tableAlias);
235236
}
236237

237-
public function dropEnum(string $columnName):string
238+
public function dropEnum(string $tableAlias, string $columnName):string
238239
{
239-
return sprintf(self::DROP_ENUM, $columnName);
240+
$rawTableName = $this->dbSchema->getRawTableName($tableAlias);
241+
return sprintf(self::DROP_ENUM, $rawTableName, $columnName);
240242
}
241243

242244
public function dropFk(string $fkName, string $tableAlias):string
@@ -258,6 +260,7 @@ public function dropIndex(string $tableAlias, string $indexName):string
258260
* @throws \yii\base\InvalidConfigException
259261
*/
260262
private function columnToCode(
263+
string $tableAlias,
261264
ColumnSchema $column,
262265
bool $fromDb = false,
263266
bool $alter = false,
@@ -266,6 +269,7 @@ private function columnToCode(
266269
): ColumnToCode {
267270
return Yii::createObject(ColumnToCode::class, [
268271
$this->dbSchema,
272+
$tableAlias,
269273
$column,
270274
$fromDb,
271275
$alter,

src/lib/migrations/MysqlMigrationBuilder.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,14 @@ protected function buildColumnChanges(ColumnSchema $current, ColumnSchema $desir
3939
protected function compareColumns(ColumnSchema $current, ColumnSchema $desired):array
4040
{
4141
$changedAttributes = [];
42+
$tableAlias = $this->model->getTableAlias();
4243

4344
$this->modifyCurrent($current);
4445
$this->modifyDesired($desired);
4546
$this->modifyDesiredInContextOfCurrent($current, $desired);
4647

4748
// Why this is needed? Often manually created ColumnSchem instance have dbType 'varchar' with size 255 and ColumnSchema fetched from db have 'varchar(255)'. So varchar !== varchar(255). such normal mistake was leading to errors. So desired column is saved in temporary table and it is fetched from that temp. table and then compared with current ColumnSchema
48-
$desiredFromDb = $this->tmpSaveNewCol($desired);
49+
$desiredFromDb = $this->tmpSaveNewCol($tableAlias, $desired);
4950
$this->modifyDesired($desiredFromDb);
5051
$this->modifyDesiredInContextOfCurrent($current, $desiredFromDb);
5152

0 commit comments

Comments
 (0)