diff --git a/src/db/ColumnSchema.php b/src/db/ColumnSchema.php index 71127a24..64ff042f 100644 --- a/src/db/ColumnSchema.php +++ b/src/db/ColumnSchema.php @@ -25,4 +25,11 @@ class ColumnSchema extends \yii\db\ColumnSchema * ``` */ public $xDbType; + + /** + * @var string|null + * Custom Enum type + * @see \cebe\yii2openapi\lib\items\Attribute::$xDbType and `x-db-type` docs in README.md // TODO SK + */ + public $xEnumType; } diff --git a/src/lib/AttributeResolver.php b/src/lib/AttributeResolver.php index 906226d4..77ffb59c 100644 --- a/src/lib/AttributeResolver.php +++ b/src/lib/AttributeResolver.php @@ -235,7 +235,7 @@ protected function resolveProperty( if ($property->isVirtual()) { throw new InvalidDefinitionException('References not supported for virtual attributes'); } - + if ($property->isNonDbReference()) { $attribute->asNonDbReference($property->getRefClassName()); $relation = Yii::createObject( @@ -288,6 +288,9 @@ protected function resolveProperty( if ($property->hasEnum()) { $attribute->setEnumValues($property->getAttr('enum')); } + if ($property->hasAttr('x-enum-type')) { + $attribute->setXEnumType($property->getAttr('x-enum-type')); + } } if ($property->hasRefItems()) { diff --git a/src/lib/ColumnToCode.php b/src/lib/ColumnToCode.php index e9a570bc..7862b37d 100644 --- a/src/lib/ColumnToCode.php +++ b/src/lib/ColumnToCode.php @@ -188,7 +188,7 @@ public function getAlterExpression(bool $addUsingExpression = false):string { if ($this->isEnum() && ApiGenerator::isPostgres()) { $rawTableName = $this->dbSchema->getRawTableName($this->tableAlias); - $enumTypeName = 'enum_'.$rawTableName.'_'.$this->column->name; + $enumTypeName = $this->column->xEnumType ?? 'enum_'.$rawTableName.'_'.$this->column->name; return "'" . sprintf('"'.$enumTypeName.'" USING "%1$s"::"'.$enumTypeName.'"', $this->column->name) . "'"; } if ($this->column->dbType === 'tsvector') { @@ -399,7 +399,7 @@ private function resolveEnumType():void { if (ApiGenerator::isPostgres()) { $rawTableName = $this->dbSchema->getRawTableName($this->tableAlias); - $this->rawParts['type'] = '"enum_'.$rawTableName.'_' . $this->column->name.'"'; + $this->rawParts['type'] = $this->column->xEnumType ?? '"enum_'.$rawTableName.'_' . $this->column->name.'"'; return; } $this->rawParts['type'] = 'enum(' . self::mysqlEnumToString($this->column->enumValues) . ')'; diff --git a/src/lib/items/Attribute.php b/src/lib/items/Attribute.php index 5b62e49d..77e63158 100644 --- a/src/lib/items/Attribute.php +++ b/src/lib/items/Attribute.php @@ -115,6 +115,12 @@ class Attribute extends BaseObject */ public $defaultValue; + /** + * Custom enum type naming + * string | null + */ + public $xEnumType; + /** * @var array|null */ @@ -200,6 +206,12 @@ public function setDefault($value):Attribute return $this; } + public function setXEnumType(string $xEnumType):Attribute + { + $this->xEnumType = $xEnumType; + return $this; + } + public function setEnumValues(array $values):Attribute { $this->enumValues = $values; @@ -330,6 +342,9 @@ public function toColumnSchema():ColumnSchema //@TODO: Need to discuss $column->defaultValue = null; } + if (!empty($this->xEnumType)) { + $column->xEnumType = $this->xEnumType; + } if (is_array($this->enumValues)) { $column->enumValues = $this->enumValues; } diff --git a/src/lib/migrations/BaseMigrationBuilder.php b/src/lib/migrations/BaseMigrationBuilder.php index d4c49c21..e5038d7b 100644 --- a/src/lib/migrations/BaseMigrationBuilder.php +++ b/src/lib/migrations/BaseMigrationBuilder.php @@ -420,8 +420,13 @@ protected function isNeedUsingExpression(string $fromDbType, string $toDbType):b public function tmpSaveNewCol(string $tableAlias, \cebe\yii2openapi\db\ColumnSchema $columnSchema): \yii\db\ColumnSchema { $tmpTableName = 'tmp_table_'; - $tmpEnumName = function (string $columnName): string { - return '"tmp_enum_'.$columnName.'_"'; + + $tmpEnumName = function (\cebe\yii2openapi\db\ColumnSchema $columnSchema): string { + if ($columnSchema->xEnumType) { +// return 'tmp_'.$columnSchema->xEnumType; + return $columnSchema->xEnumType; + } + return '"tmp_enum_'.$columnSchema->name.'_"'; }; $rawTableName = $this->db->schema->getRawTableName($tableAlias); $innerEnumTypeName = "\"enum_{$tmpTableName}_{$columnSchema->name}\""; @@ -432,12 +437,12 @@ public function tmpSaveNewCol(string $tableAlias, \cebe\yii2openapi\db\ColumnSch $name = MigrationRecordBuilder::quote($columnSchema->name); $column = [$name.' '.$this->newColStr($tmpTableName, $columnSchema)]; if (ApiGenerator::isPostgres() && static::isEnum($columnSchema)) { - $column = strtr($column, [$innerEnumTypeName => $tmpEnumName($columnSchema->name)]); + $column = strtr($column, [$innerEnumTypeName => $tmpEnumName($columnSchema)]); } } else { $column = [$columnSchema->name => $this->newColStr($tmpTableName, $columnSchema)]; if (ApiGenerator::isPostgres() && static::isEnum($columnSchema)) { - $column[$columnSchema->name] = strtr($column[$columnSchema->name], [$innerEnumTypeName => $tmpEnumName($columnSchema->name)]); + $column[$columnSchema->name] = strtr($column[$columnSchema->name], [$innerEnumTypeName => $tmpEnumName($columnSchema)]); } } @@ -448,7 +453,7 @@ public function tmpSaveNewCol(string $tableAlias, \cebe\yii2openapi\db\ColumnSch return "'$aValue'"; }, $allEnumValues); Yii::$app->db->createCommand( - 'CREATE TYPE '.$tmpEnumName($columnSchema->name).' AS ENUM('.implode(', ', $allEnumValues).')' + 'CREATE TYPE '.$tmpEnumName($columnSchema).' AS ENUM('.implode(', ', $allEnumValues).')' )->execute(); } @@ -459,13 +464,25 @@ public function tmpSaveNewCol(string $tableAlias, \cebe\yii2openapi\db\ColumnSch 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(); - if ('"'.$table->columns[$columnSchema->name]->dbType.'"' !== $tmpEnumName($columnSchema->name)) { - throw new \Exception('Unknown error related to PgSQL enum '.$table->columns[$columnSchema->name]->dbType); - } + Yii::$app->db->createCommand('DROP TYPE '.$tmpEnumName($columnSchema))->execute(); + +// $table->columns[$columnSchema->name]->dbType = $tmpEnumName($columnSchema); + $table->columns[$columnSchema->name]->dbType = $columnSchema->xEnumType ?? "enum_{$rawTableName}_{$columnSchema->name}"; + + +// if ('"'.$table->columns[$columnSchema->name]->dbType.'"' !== $tmpEnumName($columnSchema)) { +// throw new \Exception('Unknown error related to PgSQL enum '.$table->columns[$columnSchema->name]->dbType); +// } // 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_'.$rawTableName.'_'.$columnSchema->name; +// $table->columns[$columnSchema->name]->dbType = $columnSchema->xEnumType ?? 'enum_'.$rawTableName.'_'.$columnSchema->name; +// $table->columns[$columnSchema->name]->dbType = 'enum_'.$rawTableName.'_'.$columnSchema->name; + + +// if (is_array($desired->enumValues)) { +// $desired->dbType = $columnSchema->xEnumType ?? 'enum_'.$rawTableName.'_'.$desired->name +// } + } return $table->columns[$columnSchema->name]; diff --git a/src/lib/migrations/MigrationRecordBuilder.php b/src/lib/migrations/MigrationRecordBuilder.php index 98ee03b8..af8799db 100644 --- a/src/lib/migrations/MigrationRecordBuilder.php +++ b/src/lib/migrations/MigrationRecordBuilder.php @@ -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_%s\" AS ENUM(%s)');"; - public const DROP_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('DROP TYPE \"enum_%s_%s\"');"; + public const ADD_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('CREATE TYPE \"%s\" AS ENUM(%s)');"; + public const DROP_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('DROP TYPE \"%s\"');"; public const DROP_TABLE = MigrationRecordBuilder::INDENT . "\$this->dropTable('%s');"; public const ADD_FK = MigrationRecordBuilder::INDENT . "\$this->addForeignKey('%s', '%s', '%s', '%s', '%s');"; @@ -203,10 +203,20 @@ public function dropColumnNotNull(string $tableAlias, ColumnSchema $column):stri return sprintf(self::ALTER_COLUMN, $tableAlias, $column->name, '"DROP NOT NULL"'); } - public function createEnum(string $tableAlias, string $columnName, array $values):string + public function createEnum(string $tableAlias, string $columnName, array $values, ?string $enumType = null): string { $rawTableName = $this->dbSchema->getRawTableName($tableAlias); - return sprintf(self::ADD_ENUM, $rawTableName, $columnName, ColumnToCode::enumToString($values)); + + if (is_string($enumType)) { + $enumType = trim($enumType); + } + + // -- Decide the final enum type name + // If a custom name is provided, use it verbatim (trim extra quotes). + // Otherwise derive the legacy name "enum_