Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Implement enum with table name
  • Loading branch information
SOHELAHMED7 committed Jan 3, 2023
commit d4527f55abeac5084cf4529fd3e20922c7144fcb
15 changes: 13 additions & 2 deletions src/lib/ColumnToCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ class ColumnToCode
*/
private $dbSchema;

/**
* @var string
* @example {{%table}}
*/
private $tableAlias;

/**
* @var bool
*/
Expand Down Expand Up @@ -107,13 +113,15 @@ class ColumnToCode
*/
public function __construct(
Schema $dbSchema,
string $tableAlias,
ColumnSchema $column,
bool $fromDb = false,
bool $alter = false,
bool $raw = false,
bool $alterByXDbType = false
) {
$this->dbSchema = $dbSchema;
$this->tableAlias = $tableAlias;
$this->column = $column;
$this->fromDb = $fromDb;
$this->alter = $alter;
Expand Down Expand Up @@ -160,7 +168,9 @@ public function getCode(bool $quoted = false):string
public function getAlterExpression(bool $addUsingExpression = false):string
{
if ($this->isEnum() && ApiGenerator::isPostgres()) {
return "'" . sprintf('enum_%1$s USING "%1$s"::"enum_%1$s"', $this->column->name) . "'";
$rawTableName = $this->dbSchema->getRawTableName($this->tableAlias);
$enumTypeName = 'enum_'.$rawTableName.'_'.$this->column->name;
return "'" . sprintf($enumTypeName.' USING "%1$s"::"'.$enumTypeName.'"', $this->column->name) . "'";
}
if ($this->column->dbType === 'tsvector') {
return "'" . $this->rawParts['type'] . "'";
Expand Down Expand Up @@ -368,7 +378,8 @@ private function getIsBuiltinType($type, $dbType)
private function resolveEnumType():void
{
if (ApiGenerator::isPostgres()) {
$this->rawParts['type'] = 'enum_' . $this->column->name;
$rawTableName = $this->dbSchema->getRawTableName($this->tableAlias);
$this->rawParts['type'] = 'enum_'.$rawTableName.'_' . $this->column->name;
return;
}
$this->rawParts['type'] = 'enum(' . self::mysqlEnumToString($this->column->enumValues) . ')';
Expand Down
28 changes: 15 additions & 13 deletions src/lib/migrations/BaseMigrationBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -409,25 +409,27 @@ protected function isNeedUsingExpression(string $fromDbType, string $toDbType):b
}

// 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
public function tmpSaveNewCol(\cebe\yii2openapi\db\ColumnSchema $columnSchema): \yii\db\ColumnSchema
public function tmpSaveNewCol(string $tableAlias, \cebe\yii2openapi\db\ColumnSchema $columnSchema): \yii\db\ColumnSchema
{
$tableName = 'tmp_table_';
$tmpTableName = 'tmp_table_';
$tmpEnumName = function (string $columnName): string {
return '"tmp_enum_'.$columnName.'_"';
};
$rawTableName = $this->db->schema->getRawTableName($tableAlias);
$innerEnumTypeName = "enum_{$tmpTableName}_$columnSchema->name";

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

if (is_string($columnSchema->xDbType) && !empty($columnSchema->xDbType)) {
$name = MigrationRecordBuilder::quote($columnSchema->name);
$column = [$name.' '.$this->newColStr($columnSchema)];
$column = [$name.' '.$this->newColStr($tmpTableName, $columnSchema)];
if (ApiGenerator::isPostgres() && static::isEnum($columnSchema)) {
$column = strtr($column, ['enum_'.$columnSchema->name => $tmpEnumName($columnSchema->name)]);
$column = strtr($column, [$innerEnumTypeName => $tmpEnumName($columnSchema->name)]);
}
} else {
$column = [$columnSchema->name => $this->newColStr($columnSchema)];
$column = [$columnSchema->name => $this->newColStr($tmpTableName, $columnSchema)];
if (ApiGenerator::isPostgres() && static::isEnum($columnSchema)) {
$column[$columnSchema->name] = strtr($column[$columnSchema->name], ['enum_'.$columnSchema->name => $tmpEnumName($columnSchema->name)]);
$column[$columnSchema->name] = strtr($column[$columnSchema->name], [$innerEnumTypeName => $tmpEnumName($columnSchema->name)]);
}
}

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

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

$table = Yii::$app->db->getTableSchema($tableName);
$table = Yii::$app->db->getTableSchema($tmpTableName);

Yii::$app->db->createCommand()->dropTable($tableName)->execute();
Yii::$app->db->createCommand()->dropTable($tmpTableName)->execute();

if (ApiGenerator::isPostgres() && static::isEnum($columnSchema)) {// drop enum
Yii::$app->db->createCommand('DROP TYPE '.$tmpEnumName($columnSchema->name))->execute();
Expand All @@ -455,15 +457,15 @@ public function tmpSaveNewCol(\cebe\yii2openapi\db\ColumnSchema $columnSchema):
}
// reset back column enum name to original as we are comparing with current
// 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
$table->columns[$columnSchema->name]->dbType = 'enum_'.$columnSchema->name;
$table->columns[$columnSchema->name]->dbType = 'enum_'.$rawTableName.'_'.$columnSchema->name;
}

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

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

Expand Down
44 changes: 24 additions & 20 deletions src/lib/migrations/MigrationRecordBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ final class MigrationRecordBuilder
public const ADD_UNIQUE = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', '%s', true);";
public const ADD_INDEX = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', '%s', %s);";
public const DROP_COLUMN = MigrationRecordBuilder::INDENT . "\$this->dropColumn('%s', '%s');";
public const ADD_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('CREATE TYPE \"enum_%s\" AS ENUM(%s)');";
public const DROP_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('DROP TYPE \"enum_%s\"');";
public const ADD_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('CREATE TYPE \"enum_%s_%s\" AS ENUM(%s)');";
public const DROP_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('DROP TYPE \"enum_%s_%s\"');";
public const DROP_TABLE = MigrationRecordBuilder::INDENT . "\$this->dropTable('%s');";
public const ADD_FK = MigrationRecordBuilder::INDENT . "\$this->addForeignKey('%s', '%s', '%s', '%s', '%s');";
public const ADD_PK = MigrationRecordBuilder::INDENT . "\$this->addPrimaryKey('%s', '%s', '%s');";
Expand Down Expand Up @@ -64,9 +64,9 @@ public function createTable(string $tableAlias, array $columns):string
foreach ($columns as $columnName => $cebeDbColumnSchema) {
if (is_string($cebeDbColumnSchema->xDbType) && !empty($cebeDbColumnSchema->xDbType)) {
$name = static::quote($columnName);
$codeColumns[] = $name.' '.$this->columnToCode($cebeDbColumnSchema, false)->getCode();
$codeColumns[] = $name.' '.$this->columnToCode($tableAlias, $cebeDbColumnSchema, false)->getCode();
} else {
$codeColumns[$columnName] = $this->columnToCode($cebeDbColumnSchema, false)->getCode();
$codeColumns[$columnName] = $this->columnToCode($tableAlias, $cebeDbColumnSchema, false)->getCode();
}
}

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

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

Expand All @@ -95,11 +95,11 @@ public function addColumn(string $tableAlias, ColumnSchema $column):string
public function addDbColumn(string $tableAlias, ColumnSchema $column):string
{
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
$converter = $this->columnToCode($column, true);
$converter = $this->columnToCode($tableAlias, $column, true);
$name = static::quote($column->name);
return sprintf(self::ADD_COLUMN_RAW, $tableAlias, $column->name, $converter->getCode());
}
$converter = $this->columnToCode($column, true);
$converter = $this->columnToCode($tableAlias, $column, true);
return sprintf(self::ADD_COLUMN, $tableAlias, $column->name, $converter->getCode(true));
}

Expand All @@ -109,15 +109,15 @@ public function addDbColumn(string $tableAlias, ColumnSchema $column):string
public function alterColumn(string $tableAlias, ColumnSchema $column):string
{
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
$converter = $this->columnToCode($column, true, false, true, true);
$converter = $this->columnToCode($tableAlias, $column, true, false, true, true);
return sprintf(
ApiGenerator::isPostgres() ? self::ALTER_COLUMN_RAW_PGSQL : self::ALTER_COLUMN_RAW,
$tableAlias,
$column->name,
$converter->getCode()
);
}
$converter = $this->columnToCode($column, true);
$converter = $this->columnToCode($tableAlias, $column, true);
return sprintf(self::ALTER_COLUMN, $tableAlias, $column->name, $converter->getCode(true));
}

Expand All @@ -127,15 +127,15 @@ public function alterColumn(string $tableAlias, ColumnSchema $column):string
public function alterColumnType(string $tableAlias, ColumnSchema $column, bool $addUsing = false):string
{
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
$converter = $this->columnToCode($column, false, false, true, true);
$converter = $this->columnToCode($tableAlias, $column, false, false, true, true);
return sprintf(
ApiGenerator::isPostgres() ? self::ALTER_COLUMN_RAW_PGSQL : self::ALTER_COLUMN_RAW,
$tableAlias,
$column->name,
rtrim(ltrim($converter->getAlterExpression($addUsing), "'"), "'")
);
}
$converter = $this->columnToCode($column, false);
$converter = $this->columnToCode($tableAlias, $column, false);
return sprintf(self::ALTER_COLUMN, $tableAlias, $column->name, $converter->getAlterExpression($addUsing));
}

Expand All @@ -145,15 +145,15 @@ public function alterColumnType(string $tableAlias, ColumnSchema $column, bool $
public function alterColumnTypeFromDb(string $tableAlias, ColumnSchema $column, bool $addUsing = false) :string
{
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
$converter = $this->columnToCode($column, true, false, true, true);
$converter = $this->columnToCode($tableAlias, $column, true, false, true, true);
return sprintf(
ApiGenerator::isPostgres() ? self::ALTER_COLUMN_RAW_PGSQL : self::ALTER_COLUMN_RAW,
$tableAlias,
$column->name,
rtrim(ltrim($converter->getAlterExpression($addUsing), "'"), "'")
);
}
$converter = $this->columnToCode($column, true);
$converter = $this->columnToCode($tableAlias, $column, true);
return sprintf(self::ALTER_COLUMN, $tableAlias, $column->name, $converter->getAlterExpression($addUsing));
}

Expand All @@ -162,7 +162,7 @@ public function alterColumnTypeFromDb(string $tableAlias, ColumnSchema $column,
*/
public function setColumnDefault(string $tableAlias, ColumnSchema $column):string
{
$default = $this->columnToCode($column, false, true)->getDefaultValue();
$default = $this->columnToCode($tableAlias, $column, false, true)->getDefaultValue();
if ($default === null) {
return '';
}
Expand All @@ -174,7 +174,7 @@ public function setColumnDefault(string $tableAlias, ColumnSchema $column):strin
*/
public function setColumnDefaultFromDb(string $tableAlias, ColumnSchema $column):string
{
$default = $this->columnToCode($column, true, true)->getDefaultValue();
$default = $this->columnToCode($tableAlias, $column, true, true)->getDefaultValue();
if ($default === null) {
return '';
}
Expand All @@ -196,9 +196,10 @@ public function dropColumnNotNull(string $tableAlias, ColumnSchema $column):stri
return sprintf(self::ALTER_COLUMN, $tableAlias, $column->name, '"DROP NOT NULL"');
}

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

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

public function dropEnum(string $columnName):string
public function dropEnum(string $tableAlias, string $columnName):string
{
return sprintf(self::DROP_ENUM, $columnName);
$rawTableName = $this->dbSchema->getRawTableName($tableAlias);
return sprintf(self::DROP_ENUM, $rawTableName, $columnName);
}

public function dropFk(string $fkName, string $tableAlias):string
Expand All @@ -258,6 +260,7 @@ public function dropIndex(string $tableAlias, string $indexName):string
* @throws \yii\base\InvalidConfigException
*/
private function columnToCode(
string $tableAlias,
ColumnSchema $column,
bool $fromDb = false,
bool $alter = false,
Expand All @@ -266,6 +269,7 @@ private function columnToCode(
): ColumnToCode {
return Yii::createObject(ColumnToCode::class, [
$this->dbSchema,
$tableAlias,
$column,
$fromDb,
$alter,
Expand Down
3 changes: 2 additions & 1 deletion src/lib/migrations/MysqlMigrationBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ protected function buildColumnChanges(ColumnSchema $current, ColumnSchema $desir
protected function compareColumns(ColumnSchema $current, ColumnSchema $desired):array
{
$changedAttributes = [];
$tableAlias = $this->model->getTableAlias();

$this->modifyCurrent($current);
$this->modifyDesired($desired);
$this->modifyDesiredInContextOfCurrent($current, $desired);

// 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
$desiredFromDb = $this->tmpSaveNewCol($desired);
$desiredFromDb = $this->tmpSaveNewCol($tableAlias, $desired);
$this->modifyDesired($desiredFromDb);
$this->modifyDesiredInContextOfCurrent($current, $desiredFromDb);

Expand Down
Loading