diff --git a/README.md b/README.md index 94b53f46..9d20b16a 100644 --- a/README.md +++ b/README.md @@ -316,8 +316,8 @@ e.g. attribute = 'my_property'. nullable: false ``` -### Handling of `enum` (#enum, #MariaDb) -It work on MariaDb. +### Handling of `enum` (#enum) +It works on all 3 DB: MySQL, MariaDb and PgSQL. ```yaml test_table: @@ -329,6 +329,8 @@ It work on MariaDb. - three ``` +Note: Change in enum values are not very simple. For Mysql and Mariadb, migrations will be generated but in many cases custom modification in it are required. For Pgsql migrations for change in enum values will not be generated. It should be handled manually. + ### Handling of `numeric` (#numeric, #MariaDb) precision-default = 10 scale-default = 2 @@ -372,9 +374,10 @@ Generated files: # Development -There commands are available to develop and check the tests. It can be used inside the Docker container. To enter into bash of container run `make cli` . +There commands are available to develop and check the tests. It is available inside the Docker container. To enter into bash shell of container, run `make cli` . ```bash +cd tests ./yii migrate-mysql/up ./yii migrate-mysql/down 4 diff --git a/src/lib/ColumnToCode.php b/src/lib/ColumnToCode.php index 7a0188e2..aef7f53f 100644 --- a/src/lib/ColumnToCode.php +++ b/src/lib/ColumnToCode.php @@ -53,6 +53,12 @@ class ColumnToCode */ private $dbSchema; + /** + * @var string + * @example {{%table}} + */ + private $tableAlias; + /** * @var bool */ @@ -77,9 +83,9 @@ class ColumnToCode */ private $isPk = false; - private $rawParts = ['type' => null, 'nullable' => null, 'default' => null]; + private $rawParts = ['type' => null, 'nullable' => null, 'default' => null, 'after' => null]; - private $fluentParts = ['type' => null, 'nullable' => null, 'default' => null]; + private $fluentParts = ['type' => null, 'nullable' => null, 'default' => null, 'after' => null]; /** * @var bool @@ -96,6 +102,13 @@ class ColumnToCode */ private $alterByXDbType; + /** + * @var null|string + * Column name of previous column/field. + * Used for `AFTER` in SQL to preserve order as in OpenAPI schema defination + */ + private $previousColumnName; + /** * ColumnToCode constructor. * @param \yii\db\Schema $dbSchema @@ -107,18 +120,22 @@ class ColumnToCode */ public function __construct( Schema $dbSchema, + string $tableAlias, ColumnSchema $column, bool $fromDb = false, bool $alter = false, bool $raw = false, - bool $alterByXDbType = false + bool $alterByXDbType = false, + ?string $previousColumnName = null ) { $this->dbSchema = $dbSchema; + $this->tableAlias = $tableAlias; $this->column = $column; $this->fromDb = $fromDb; $this->alter = $alter; $this->raw = $raw; $this->alterByXDbType = $alterByXDbType; + $this->previousColumnName = $previousColumnName; // We use `property_exists()` because sometimes we can have instance of \yii\db\mysql\ColumnSchema (or of Maria/Pgsql) or \cebe\yii2openapi\db\ColumnSchema if (property_exists($this->column, 'xDbType') && is_string($this->column->xDbType) && !empty($this->column->xDbType)) { @@ -134,7 +151,7 @@ public function getCode(bool $quoted = false):string return '$this->' . $this->fluentParts['type']; } if ($this->isBuiltinType) { - $parts = [$this->fluentParts['type'], $this->fluentParts['nullable'], $this->fluentParts['default']]; + $parts = [$this->fluentParts['type'], $this->fluentParts['nullable'], $this->fluentParts['default'], $this->fluentParts['after']]; array_unshift($parts, '$this'); return implode('->', array_filter(array_map('trim', $parts), 'trim')); } @@ -148,8 +165,11 @@ public function getCode(bool $quoted = false):string } $code = $this->rawParts['type'] . ' ' . $this->rawParts['nullable'] . $default; - if (ApiGenerator::isMysql() && $this->isEnum()) { - return $quoted ? '"' . str_replace("\'", "'", $code) . '"' : $code; + if ((ApiGenerator::isMysql() || ApiGenerator::isMariaDb()) && $this->rawParts['after']) { + $code .= ' ' . $this->rawParts['after']; + } + if ((ApiGenerator::isMysql() || ApiGenerator::isMariaDb()) && $this->isEnum()) { + return $quoted ? "'" . $code . "'" : $code; } if (ApiGenerator::isPostgres() && $this->alterByXDbType) { return $quoted ? "'" . $this->rawParts['type'] . "'" : $this->rawParts['type']; @@ -160,13 +180,18 @@ 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'] . "'"; } if ($addUsingExpression && ApiGenerator::isPostgres()) { - return "'" . $this->rawParts['type'] . " ".$this->rawParts['nullable'] + return "'" . $this->rawParts['type'] . + ($this->alterByXDbType ? + '' : + " ".$this->rawParts['nullable']) .' USING "'.$this->column->name.'"::'.$this->typeWithoutSize($this->rawParts['type'])."'"; } @@ -270,7 +295,9 @@ public static function enumToString(array $enum):string public static function mysqlEnumToString(array $enum):string { - return implode(', ', array_map('self::wrapQuotes', $enum)); + return implode(', ', array_map(function ($aEnumValue) { + return self::wrapQuotes($aEnumValue, '"'); + }, $enum)); } private function defaultValueJson(array $value):string @@ -329,7 +356,13 @@ private function resolve():void $this->rawParts['type'] = $this->column->dbType . (strpos($this->column->dbType, '(') !== false ? '' : $rawSize); } - + + if (ApiGenerator::isMysql() || ApiGenerator::isMariaDb()) { // for MySQL `AFTER` is supported for `ALTER table` queries and not supported for `CREATE table` queries + if ($this->previousColumnName) { + $this->fluentParts['after'] = 'after(\''.$this->previousColumnName.'\')'; + $this->rawParts['after'] = 'AFTER '.$this->previousColumnName; + } + } $this->isBuiltinType = $this->raw ? false : $this->getIsBuiltinType($type, $dbType); $this->resolveDefaultValue(); @@ -346,7 +379,7 @@ private function getIsBuiltinType($type, $dbType) return false; } - if ($this->isEnum() && ApiGenerator::isMariaDb()) { + if ($this->isEnum()) { return false; } if ($this->fromDb === true) { @@ -363,7 +396,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) . ')'; @@ -421,16 +455,18 @@ private function resolveDefaultValue():void break; default: $isExpression = StringHelper::startsWith($value, 'CURRENT') + || StringHelper::startsWith($value, 'current') || StringHelper::startsWith($value, 'LOCAL') || substr($value, -1, 1) === ')'; if ($isExpression) { $this->fluentParts['default'] = 'defaultExpression("' . self::escapeQuotes((string)$value) . '")'; + $this->rawParts['default'] = $value; } else { $this->fluentParts['default'] = $expectInteger ? 'defaultValue(' . $value . ')' : 'defaultValue("' . self::escapeQuotes((string)$value) . '")'; + $this->rawParts['default'] = $expectInteger ? $value : self::wrapQuotes($value); } - $this->rawParts['default'] = $expectInteger ? $value : self::wrapQuotes($value); - if (ApiGenerator::isMysql() && $this->isEnum()) { + if ((ApiGenerator::isMysql() || ApiGenerator::isMariaDb()) && $this->isEnum()) { $this->rawParts['default'] = self::escapeQuotes($this->rawParts['default']); } } diff --git a/src/lib/ValidationRulesBuilder.php b/src/lib/ValidationRulesBuilder.php index 746976b0..e696fc21 100644 --- a/src/lib/ValidationRulesBuilder.php +++ b/src/lib/ValidationRulesBuilder.php @@ -63,6 +63,10 @@ public function build():array } } foreach ($this->model->attributes as $attribute) { + // column/field/property with name `id` is considered as Primary Key by this library and it is automatically handled by DB/Yii; so remove it from validation `rules()` + if ($attribute->columnName === 'id' || $attribute->propertyName === 'id') { + continue; + } $this->resolveAttributeRules($attribute); } @@ -181,6 +185,10 @@ private function prepareTypeScope():void if ($attribute->isReadOnly()) { continue; } + // column/field/property with name `id` is considered as Primary Key by this library and it is automatically handled by DB/Yii; so remove it from validation `rules()` + if ($attribute->columnName === 'id' || $attribute->propertyName === 'id') { + continue; + } if ($attribute->defaultValue === null && $attribute->isRequired()) { $this->typeScope['required'][$attribute->columnName] = $attribute->columnName; } diff --git a/src/lib/migrations/BaseMigrationBuilder.php b/src/lib/migrations/BaseMigrationBuilder.php index 82becfb9..49d69bfb 100644 --- a/src/lib/migrations/BaseMigrationBuilder.php +++ b/src/lib/migrations/BaseMigrationBuilder.php @@ -7,6 +7,7 @@ namespace cebe\yii2openapi\lib\migrations; +use cebe\yii2openapi\generator\ApiGenerator; use cebe\yii2openapi\lib\ColumnToCode; use cebe\yii2openapi\lib\items\DbModel; use cebe\yii2openapi\lib\items\ManyToManyRelation; @@ -15,6 +16,7 @@ use yii\db\ColumnSchema; use yii\helpers\VarDumper; use yii\db\Connection; +use yii\db\Expression; abstract class BaseMigrationBuilder { @@ -203,14 +205,6 @@ function (string $unknownColumn) { // do not adjust existing primary keys continue; } - if (!empty($current->enumValues)) { - $current->type = 'enum'; - $current->dbType = 'enum'; - } - if (!empty($desired->enumValues)) { - $desired->type = 'enum'; - $desired->dbType = 'enum'; - } $changedAttributes = $this->compareColumns($current, $desired); if (empty($changedAttributes)) { continue; @@ -234,9 +228,14 @@ function (string $unknownColumn) { */ protected function buildColumnsCreation(array $columns):void { + $tableName = $this->model->getTableAlias(); + foreach ($columns as $column) { - $tableName = $this->model->getTableAlias(); - $this->migration->addUpCode($this->recordBuilder->addColumn($tableName, $column)) + /** @var $column ColumnSchema */ + + $previousColumnName = $this->previousColumnName($column); + + $this->migration->addUpCode($this->recordBuilder->addColumn($tableName, $column, $previousColumnName)) ->addDownCode($this->recordBuilder->dropColumn($tableName, $column->name)); } } @@ -406,44 +405,137 @@ protected function unPrefixTableName(string $tableName):string return str_replace($this->db->tablePrefix, '', $tableName); } - protected function isNeedUsingExpression(string $fromType, string $toType):bool + protected function isNeedUsingExpression(string $fromDbType, string $toDbType):bool { - $strings = ['string', 'text', 'char']; - if (in_array($fromType, $strings) && in_array($toType, $strings)) { + if ($fromDbType === $toDbType) { return false; } - $ints = ['smallint', 'integer', 'bigint', 'float', 'decimal']; - if (in_array($fromType, $ints) && in_array($toType, $ints)) { - return false; - } - $dates = ['date', 'timestamp']; - return !(in_array($fromType, $dates) && in_array($toType, $dates)); + return true; } - public function tmpSaveNewCol(\cebe\yii2openapi\db\ColumnSchema $columnSchema): \yii\db\ColumnSchema + // 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(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)) { - $column = [$columnSchema->name.' '.$this->newColStr($columnSchema)]; + $name = MigrationRecordBuilder::quote($columnSchema->name); + $column = [$name.' '.$this->newColStr($tmpTableName, $columnSchema)]; + if (ApiGenerator::isPostgres() && static::isEnum($columnSchema)) { + $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], [$innerEnumTypeName => $tmpEnumName($columnSchema->name)]); + } + } + + // create enum if relevant + if (ApiGenerator::isPostgres() && static::isEnum($columnSchema)) { + $allEnumValues = $columnSchema->enumValues; + $allEnumValues = array_map(function ($aValue) { + return "'$aValue'"; + }, $allEnumValues); + Yii::$app->db->createCommand( + 'CREATE TYPE '.$tmpEnumName($columnSchema->name).' AS ENUM('.implode(', ', $allEnumValues).')' + )->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(); + if ('"'.$table->columns[$columnSchema->name]->dbType.'"' !== $tmpEnumName($columnSchema->name)) { + 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; + } 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()); } + + public static function isEnum(\yii\db\ColumnSchema $columnSchema): bool + { + if (!empty($columnSchema->enumValues) && is_array($columnSchema->enumValues)) { + return true; + } + return false; + } + + public static function isEnumValuesChanged( + \yii\db\ColumnSchema $current, + \yii\db\ColumnSchema $desired + ): bool { + if (static::isEnum($current) && static::isEnum($desired) && + $current->enumValues !== $desired->enumValues) { + return true; + } + return false; + } + + public function isDefaultValueChanged( + ColumnSchema $current, + ColumnSchema $desired + ): bool { + // if the default value is object of \yii\db\Expression then default value is expression instead of constant. See https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html + // in such case instead of comparing two objects, we should compare expression + + if ($current->defaultValue instanceof Expression && + $desired->defaultValue instanceof Expression + && $current->defaultValue->expression === $desired->defaultValue->expression + ) { + return false; + } + + if ($current->defaultValue !== $desired->defaultValue) { + return true; + } + return false; + } + + /** + * Given a column, compute its previous column name present in OpenAPI schema + * For the first column, `null` is returned + * Also due to a issue https://github.com/cebe/yii2-openapi/issues/100 (TODO), existance (if it exists in DB table schema) of previous column is checked. + * This should be avoided once above issue is solved. + */ + public function previousColumnName(ColumnSchema $column): ?string + { + $columnNames = array_keys($this->newColumns); + + $key = array_search($column->name, $columnNames); + if ($key > 0) { + $prevColName = $columnNames[$key-1]; + + if ($this->tableSchema) { + $columnSchema = $this->tableSchema->getColumn($prevColName); + if ($columnSchema) { + return $prevColName; + } + } + // 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 + } + + return null; + } } diff --git a/src/lib/migrations/MigrationRecordBuilder.php b/src/lib/migrations/MigrationRecordBuilder.php index d15ee070..ba01afba 100644 --- a/src/lib/migrations/MigrationRecordBuilder.php +++ b/src/lib/migrations/MigrationRecordBuilder.php @@ -27,19 +27,20 @@ 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');"; public const ADD_COLUMN = MigrationRecordBuilder::INDENT . "\$this->addColumn('%s', '%s', %s);"; + public const ALTER_COLUMN = MigrationRecordBuilder::INDENT . "\$this->alterColumn('%s', '%s', %s);"; - public const ADD_COLUMN_RAW = MigrationRecordBuilder::INDENT . "\$this->db->createCommand('ALTER TABLE %s ADD COLUMN %s %s')->execute();"; - public const ALTER_COLUMN = MigrationRecordBuilder::INDENT . "\$this->alterColumn('%s', '%s', %s);"; + public const ADD_COLUMN_RAW = MigrationRecordBuilder::INDENT . "\$this->db->createCommand('ALTER TABLE %s ADD COLUMN %s %s')->execute();"; public const ALTER_COLUMN_RAW = MigrationRecordBuilder::INDENT . "\$this->db->createCommand('ALTER TABLE %s MODIFY %s %s')->execute();"; - public const ALTER_COLUMN_RAW_PGSQL = MigrationRecordBuilder::INDENT . "\$this->db->createCommand('ALTER TABLE %s ALTER COLUMN %s SET DATA TYPE %s')->execute();"; + + public const ALTER_COLUMN_RAW_PGSQL = MigrationRecordBuilder::INDENT . "\$this->db->createCommand('ALTER TABLE %s ALTER COLUMN \"%s\" SET DATA TYPE %s')->execute();"; /** * @var \yii\db\Schema @@ -62,9 +63,10 @@ public function createTable(string $tableAlias, array $columns):string $codeColumns = []; foreach ($columns as $columnName => $cebeDbColumnSchema) { if (is_string($cebeDbColumnSchema->xDbType) && !empty($cebeDbColumnSchema->xDbType)) { - $codeColumns[] = $columnName.' '.$this->columnToCode($cebeDbColumnSchema, false)->getCode(); + $name = static::quote($columnName); + $codeColumns[] = $name.' '.$this->columnToCode($tableAlias, $cebeDbColumnSchema, false)->getCode(); } else { - $codeColumns[$columnName] = $this->columnToCode($cebeDbColumnSchema, false)->getCode(); + $codeColumns[$columnName] = $this->columnToCode($tableAlias, $cebeDbColumnSchema, false)->getCode(); } } @@ -75,14 +77,17 @@ public function createTable(string $tableAlias, array $columns):string /** * @throws \yii\base\InvalidConfigException */ - public function addColumn(string $tableAlias, ColumnSchema $column):string + public function addColumn(string $tableAlias, ColumnSchema $column, ?string $previousColumnName = null):string { + // TODO implement previous column name + // $converter = $this->columnToCode($column, false, false, $previousColumnName); if (is_string($column->xDbType) && !empty($column->xDbType)) { - $converter = $this->columnToCode($column, false); - return sprintf(self::ADD_COLUMN_RAW, $tableAlias, $column->name, $converter->getCode()); + $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)); } @@ -92,10 +97,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)); } @@ -105,7 +111,7 @@ 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, @@ -113,7 +119,7 @@ public function alterColumn(string $tableAlias, ColumnSchema $column):string $converter->getCode() ); } - $converter = $this->columnToCode($column, true); + $converter = $this->columnToCode($tableAlias, $column, true); return sprintf(self::ALTER_COLUMN, $tableAlias, $column->name, $converter->getCode(true)); } @@ -123,7 +129,7 @@ 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, @@ -131,7 +137,7 @@ public function alterColumnType(string $tableAlias, ColumnSchema $column, bool $ 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)); } @@ -141,7 +147,7 @@ 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, @@ -149,7 +155,7 @@ public function alterColumnTypeFromDb(string $tableAlias, ColumnSchema $column, 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)); } @@ -158,7 +164,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 ''; } @@ -170,7 +176,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 ''; } @@ -192,9 +198,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 @@ -230,9 +237,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 @@ -254,19 +262,32 @@ 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, bool $raw = false, - bool $alterByXDbType = false + bool $alterByXDbType = false, + ?string $previousColumnName = null ): ColumnToCode { return Yii::createObject(ColumnToCode::class, [ $this->dbSchema, + $tableAlias, $column, $fromDb, $alter, $raw, - $alterByXDbType + $alterByXDbType, + $previousColumnName ]); } + + // https://github.com/cebe/yii2-openapi/issues/127 + public static function quote(string $columnName): string + { + if (ApiGenerator::isPostgres()) { + return '"'.$columnName.'"'; + } + return $columnName; + } } diff --git a/src/lib/migrations/MysqlMigrationBuilder.php b/src/lib/migrations/MysqlMigrationBuilder.php index 9cb17c79..09f3af2b 100644 --- a/src/lib/migrations/MysqlMigrationBuilder.php +++ b/src/lib/migrations/MysqlMigrationBuilder.php @@ -29,8 +29,8 @@ protected function buildColumnChanges(ColumnSchema $current, ColumnSchema $desir foreach ($changed as $attr) { $newColumn->$attr = $desired->$attr; } - if (!empty($newColumn->enumValues)) { - $newColumn->dbType = 'enum'; + if (static::isEnum($newColumn)) { + $newColumn->dbType = 'enum'; // TODO this is concretely not correct } $this->migration->addUpCode($this->recordBuilder->alterColumn($this->model->getTableAlias(), $newColumn)) ->addDownCode($this->recordBuilder->alterColumn($this->model->getTableAlias(), $current)); @@ -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); @@ -53,8 +54,14 @@ protected function compareColumns(ColumnSchema $current, ColumnSchema $desired): , 'dbType', 'phpType' , 'precision', 'scale', 'unsigned' ] as $attr) { - if ($current->$attr !== $desiredFromDb->$attr) { - $changedAttributes[] = $attr; + if ($attr === 'defaultValue') { + if ($this->isDefaultValueChanged($current, $desiredFromDb)) { + $changedAttributes[] = $attr; + } + } else { + if ($current->$attr !== $desiredFromDb->$attr) { + $changedAttributes[] = $attr; + } } } return $changedAttributes; diff --git a/src/lib/migrations/PostgresMigrationBuilder.php b/src/lib/migrations/PostgresMigrationBuilder.php index edd9ec4d..f87cb32c 100644 --- a/src/lib/migrations/PostgresMigrationBuilder.php +++ b/src/lib/migrations/PostgresMigrationBuilder.php @@ -22,9 +22,9 @@ protected function buildColumnsCreation(array $columns):void { foreach ($columns as $column) { $tableName = $this->model->getTableAlias(); - if ($column->dbType === 'enum') { - $this->migration->addUpCode($this->recordBuilder->createEnum($column->name, $column->enumValues)) - ->addDownCode($this->recordBuilder->dropEnum($column->name)); + if (static::isEnum($column)) { + $this->migration->addUpCode($this->recordBuilder->createEnum($tableName, $column->name, $column->enumValues)) + ->addDownCode($this->recordBuilder->dropEnum($tableName, $column->name), true); } $this->migration->addUpCode($this->recordBuilder->addColumn($tableName, $column)) ->addDownCode($this->recordBuilder->dropColumn($tableName, $column->name)); @@ -41,9 +41,9 @@ protected function buildColumnsDrop(array $columns):void $tableName = $this->model->getTableAlias(); $this->migration->addDownCode($this->recordBuilder->addDbColumn($tableName, $column)) ->addUpCode($this->recordBuilder->dropColumn($tableName, $column->name)); - if ($column->dbType === 'enum') { - $this->migration->addDownCode($this->recordBuilder->createEnum($column->name, $column->enumValues)) - ->addUpCode($this->recordBuilder->dropEnum($column->name), true); + if (static::isEnum($column)) { + $this->migration->addDownCode($this->recordBuilder->createEnum($tableName, $column->name, $column->enumValues)) + ->addUpCode($this->recordBuilder->dropEnum($tableName, $column->name)); } } } @@ -54,23 +54,21 @@ protected function buildColumnsDrop(array $columns):void protected function buildColumnChanges(ColumnSchema $current, ColumnSchema $desired, array $changed):void { $tableName = $this->model->getTableAlias(); - $isChangeToEnum = $current->type !== $desired->type && !empty($desired->enumValues); - $isChangeFromEnum = $current->type !== $desired->type && !empty($current->enumValues); - $isChangedEnum = $current->type === $desired->type && !empty($current->enumValues); + $isChangeToEnum = !static::isEnum($current) && static::isEnum($desired); + $isChangeFromEnum = static::isEnum($current) && !static::isEnum($desired); + $isChangedEnum = static::isEnumValuesChanged($current, $desired); if ($isChangedEnum) { // Generation for change enum values not supported. Do it manually // This action require several steps and can't be applied during single transaction return; } - if ($isChangeToEnum) { - $this->migration->addUpCode($this->recordBuilder->createEnum($desired->name, $desired->enumValues), true); - } - if ($isChangeFromEnum) { - $this->migration->addUpCode($this->recordBuilder->dropEnum($current->name)); - } - if (!empty(array_intersect(['type', 'size'], $changed))) { - $addUsing = $this->isNeedUsingExpression($desired->type, $current->type); - $this->migration->addUpCode($this->recordBuilder->alterColumnType($tableName, $desired)); + + if (!empty(array_intersect(['type', 'size' + , 'dbType', 'phpType' + , 'precision', 'scale', 'unsigned' + ], $changed))) { + $addUsing = $this->isNeedUsingExpression($current->dbType, $desired->dbType); + $this->migration->addUpCode($this->recordBuilder->alterColumnType($tableName, $desired, $addUsing)); $this->migration->addDownCode($this->recordBuilder->alterColumnTypeFromDb($tableName, $current, $addUsing)); } if (in_array('allowNull', $changed, true)) { @@ -93,25 +91,33 @@ protected function buildColumnChanges(ColumnSchema $current, ColumnSchema $desir $this->migration->addUpCode($upCode)->addDownCode($downCode, true); } } + if ($isChangeToEnum) { + $this->migration->addUpCode($this->recordBuilder->createEnum($tableName, $desired->name, $desired->enumValues), true); + } + if ($isChangeFromEnum) { + $this->migration->addUpCode($this->recordBuilder->dropEnum($tableName, $current->name)); + } + if ($isChangeFromEnum) { $this->migration - ->addDownCode($this->recordBuilder->createEnum($current->name, $current->enumValues), true); + ->addDownCode($this->recordBuilder->createEnum($tableName, $current->name, $current->enumValues)); } if ($isChangeToEnum) { - $this->migration->addDownCode($this->recordBuilder->dropEnum($current->name), true); + $this->migration->addDownCode($this->recordBuilder->dropEnum($tableName, $current->name), true); } } protected function compareColumns(ColumnSchema $current, ColumnSchema $desired):array { $changedAttributes = []; + $tableAlias = $this->model->getTableAlias(); $this->modifyCurrent($current); $this->modifyDesired($desired); $this->modifyDesiredInContextOfCurrent($current, $desired); // for docs, please see MysqlMigrationBuilder file - $desiredFromDb = $this->tmpSaveNewCol($desired); + $desiredFromDb = $this->tmpSaveNewCol($tableAlias, $desired); $this->modifyDesired($desiredFromDb); $this->modifyDesiredInContextOfCurrent($current, $desiredFromDb); @@ -119,8 +125,14 @@ protected function compareColumns(ColumnSchema $current, ColumnSchema $desired): , 'dbType', 'phpType' , 'precision', 'scale', 'unsigned' ] as $attr) { - if ($current->$attr !== $desiredFromDb->$attr) { - $changedAttributes[] = $attr; + if ($attr === 'defaultValue') { + if ($this->isDefaultValueChanged($current, $desiredFromDb)) { + $changedAttributes[] = $attr; + } + } else { + if ($current->$attr !== $desiredFromDb->$attr) { + $changedAttributes[] = $attr; + } } } return $changedAttributes; @@ -128,11 +140,12 @@ protected function compareColumns(ColumnSchema $current, ColumnSchema $desired): protected function createEnumMigrations():void { + $tableAlias = $this->model->getTableAlias(); $enums = $this->model->getEnumAttributes(); foreach ($enums as $attr) { $this->migration - ->addUpCode($this->recordBuilder->createEnum($attr->columnName, $attr->enumValues), true) - ->addDownCode($this->recordBuilder->dropEnum($attr->columnName)); + ->addUpCode($this->recordBuilder->createEnum($tableAlias, $attr->columnName, $attr->enumValues), true) + ->addDownCode($this->recordBuilder->dropEnum($tableAlias, $attr->columnName), true); } } diff --git a/src/lib/openapi/PropertySchema.php b/src/lib/openapi/PropertySchema.php index 4137f99a..9e6b638f 100644 --- a/src/lib/openapi/PropertySchema.php +++ b/src/lib/openapi/PropertySchema.php @@ -530,7 +530,7 @@ public static function findMoreDetailOf(string $xDbType): array } /** - * This method is copied from protected method `getColumnPhpType()` of \yii\db\Schema class + * This method is copied + enhanced from protected method `getColumnPhpType()` of \yii\db\Schema class * Extracts the PHP type from abstract DB type. * @param \yii\db\ColumnSchema $column the column schema information * @return string PHP type name @@ -546,6 +546,7 @@ public static function getColumnPhpType(ColumnSchema $column): string YiiDbSchema::TYPE_BOOLEAN => 'boolean', YiiDbSchema::TYPE_FLOAT => 'double', YiiDbSchema::TYPE_DOUBLE => 'double', + YiiDbSchema::TYPE_DECIMAL => 'double', # (enhanced) YiiDbSchema::TYPE_BINARY => 'resource', YiiDbSchema::TYPE_JSON => 'array', ]; diff --git a/tests/DbTestCase.php b/tests/DbTestCase.php index 8e59422a..bbbdd281 100644 --- a/tests/DbTestCase.php +++ b/tests/DbTestCase.php @@ -8,7 +8,7 @@ use yii\db\mysql\Schema as MySqlSchema; use yii\db\pgsql\Schema as PgSqlSchema; use \SamIT\Yii2\MariaDb\Schema as MariaDbSchema; -use yii\helpers\ArrayHelper; +use yii\helpers\{ArrayHelper, VarDumper}; use yii\helpers\FileHelper; class DbTestCase extends \PHPUnit\Framework\TestCase @@ -53,7 +53,7 @@ protected function tearDown() } } - protected function runGenerator($configFile, string $dbName) + protected function runGenerator($configFile, string $dbName = 'mysql') { $config = require $configFile; $config['migrationPath'] = "@app/migrations_{$dbName}_db/"; @@ -89,4 +89,41 @@ protected function changeDbToPgsql() self::assertNotInstanceOf(MySqlSchema::class, Yii::$app->db->schema); self::assertInstanceOf(PgSqlSchema::class, Yii::$app->db->schema); } + + protected function checkFiles(array $actual, array $expected) + { + self::assertEquals( + count($actual), + count($expected) + ); + foreach ($actual as $index => $file) { + $expectedFilePath = $expected[$index]; + self::assertFileExists($file); + self::assertFileExists($expectedFilePath); + + $this->assertFileEquals($expectedFilePath, $file, "Failed asserting that file contents of\n$file\nare equal to file contents of\n$expectedFilePath"); + } + } + + protected function runActualMigrations(string $db = 'mysql', int $number = 2): void + { + // up + exec('cd tests; ./yii migrate-'.$db.' --interactive=0', $upOutput, $upExitCode); + $last = count($upOutput) - 1; + $lastThird = count($upOutput) - 3; + $this->assertSame($upExitCode, 0); + $this->assertSame($upOutput[$last], 'Migrated up successfully.'); + $this->assertSame($upOutput[$lastThird], $number.' '.(($number === 1) ? 'migration was' : 'migrations were').' applied.'); + // 1 migration was applied. + // 2 migrations were applied. + + // down + exec('cd tests; ./yii migrate-'.$db.'/down --interactive=0 '.$number, $downOutput, $downExitCode); + $last = count($downOutput) - 1; + $lastThird = count($downOutput) - 3; + $this->assertSame($downExitCode, 0); + $this->assertSame($downOutput[$last], 'Migrated down successfully.'); + $this->assertSame($downOutput[$lastThird], $number.' '.(($number === 1) ? 'migration was' : 'migrations were').' reverted.'); + + } } diff --git a/tests/fixtures/blog.php b/tests/fixtures/blog.php index c9737bb9..deffbd6d 100644 --- a/tests/fixtures/blog.php +++ b/tests/fixtures/blog.php @@ -19,6 +19,10 @@ ->setSize(200)->setRequired()->setFakerStub('substr($faker->safeEmail, 0, 200)'), 'password' => (new Attribute('password', ['phpType' => 'string', 'dbType' => 'string'])) ->setRequired()->setFakerStub('$faker->password'), + 'role' => (new Attribute('role', ['phpType' => 'string', 'dbType' => 'string'])) + ->setSize(20) + ->setDefault('reader') + ->setFakerStub('$faker->randomElement([\'admin\', \'editor\', \'reader\'])'), 'flags' => (new Attribute('flags', ['phpType'=>'int', 'dbType'=>'integer']))->setDefault(0)->setFakerStub ('$faker->numberBetween(0, 1000000)'), 'created_at' => (new Attribute('created_at', ['phpType' => 'string', 'dbType' => 'datetime'])) @@ -28,7 +32,7 @@ 'indexes' => [ 'users_email_key' => DbIndex::make('users', ['email'], null, true), 'users_username_key' => DbIndex::make('users', ['username'], null, true), - 'users_flags_index' => DbIndex::make('users', ['flags']) + 'users_role_flags_index' => DbIndex::make('users', ['role', 'flags']) ] ]), 'category' => new DbModel([ diff --git a/tests/migrations/m100000_000000_maria.php b/tests/migrations/m100000_000000_maria.php index 53dc91df..936f7c83 100644 --- a/tests/migrations/m100000_000000_maria.php +++ b/tests/migrations/m100000_000000_maria.php @@ -34,6 +34,7 @@ public function up() 'username' => $this->string(200)->notNull()->unique(), 'email' => $this->string(200)->notNull()->unique(), 'password' => $this->string()->notNull(), + 'role' => $this->string(20)->null()->defaultValue('reader'), 'flags' => $this->integer()->null()->defaultValue(0), 'created_at' => $this->timestamp()->null()->defaultExpression("CURRENT_TIMESTAMP"), ]); diff --git a/tests/migrations/m100000_000000_mysql.php b/tests/migrations/m100000_000000_mysql.php index d1d0c19a..5b249c06 100644 --- a/tests/migrations/m100000_000000_mysql.php +++ b/tests/migrations/m100000_000000_mysql.php @@ -33,6 +33,7 @@ public function up() 'username' => $this->string(200)->notNull()->unique(), 'email' => $this->string(200)->notNull()->unique(), 'password' => $this->string()->notNull(), + 'role' => $this->string(20)->null()->defaultValue('reader'), 'flags' => $this->integer()->null()->defaultValue(0), 'created_at' => $this->timestamp()->null()->defaultExpression("CURRENT_TIMESTAMP"), ]); diff --git a/tests/migrations/m100000_000000_pgsql.php b/tests/migrations/m100000_000000_pgsql.php index 0780107d..a200fbef 100644 --- a/tests/migrations/m100000_000000_pgsql.php +++ b/tests/migrations/m100000_000000_pgsql.php @@ -29,6 +29,7 @@ public function safeUp() 'username' => $this->string(200)->notNull()->unique(), 'email' => $this->string(200)->notNull()->unique(), 'password' => $this->string()->notNull(), + 'role' => $this->string(20)->null()->defaultValue('reader'), 'flags' => $this->integer()->null()->defaultValue(0), 'created_at' => $this->timestamp()->null()->defaultExpression("CURRENT_TIMESTAMP"), ]); @@ -90,6 +91,9 @@ public function safeUp() 'str_country' => $this->text()->null()->defaultValue(null), ]); + $rawTableName = $this->db->schema->getRawTableName('{{%v3_pgcustom}}'); + $enumTypeName = 'enum_'.$rawTableName.'_status'; + $this->execute('CREATE TYPE "'.$enumTypeName.'" AS ENUM(\'active\', \'draft\')'); $this->createTable('{{%v3_pgcustom}}', [ 'id' => $this->bigPrimaryKey(), @@ -98,6 +102,7 @@ public function safeUp() 'json2' => $this->json()->null()->defaultValue(null), 'json3' => $this->json()->defaultValue(Json::encode(['foo' => 'bar', 'bar' => 'baz'])), 'json4' => "json DEFAULT '" . new Expression(Json::encode(['ffo' => 'bar'])) . "'", + 'status' => '"'.$enumTypeName.'"', 'search' => 'tsvector' ]); $columns = [ @@ -135,6 +140,8 @@ public function safeDown() $this->dropTable('{{%v2_users}}'); $this->dropTable('{{%v2_categories}}'); $this->dropTable('{{%v3_pgcustom}}'); + $rawTableName = $this->db->schema->getRawTableName('{{%v3_pgcustom}}'); + $this->execute('DROP TYPE "enum_'.$rawTableName.'_status"'); $this->dropTable('{{%default_sizes}}'); } } diff --git a/tests/specs/blog.yaml b/tests/specs/blog.yaml index cd03139d..1021b843 100644 --- a/tests/specs/blog.yaml +++ b/tests/specs/blog.yaml @@ -51,7 +51,7 @@ components: x-indexes: - unique:username - unique:email - - flags + - role,flags properties: id: type: integer @@ -66,6 +66,11 @@ components: password: type: string format: password + role: + type: string + maxLength: 20 + x-faker: "$faker->randomElement(['admin', 'editor', 'reader'])" + default: reader flags: type: integer default: 0 diff --git a/tests/specs/blog/migrations/m200000_000001_create_table_users.php b/tests/specs/blog/migrations/m200000_000001_create_table_users.php index 7afd35d4..f8cd744a 100644 --- a/tests/specs/blog/migrations/m200000_000001_create_table_users.php +++ b/tests/specs/blog/migrations/m200000_000001_create_table_users.php @@ -12,17 +12,18 @@ public function up() 'username' => $this->string(200)->notNull(), 'email' => $this->string(200)->notNull(), 'password' => $this->string()->notNull(), + 'role' => $this->string(20)->null()->defaultValue("reader"), 'flags' => $this->integer()->null()->defaultValue(0), 'created_at' => $this->timestamp()->null()->defaultExpression("CURRENT_TIMESTAMP"), ]); $this->createIndex('users_username_key', '{{%users}}', 'username', true); $this->createIndex('users_email_key', '{{%users}}', 'email', true); - $this->createIndex('users_flags_index', '{{%users}}', 'flags', false); + $this->createIndex('users_role_flags_index', '{{%users}}', 'role,flags', false); } public function down() { - $this->dropIndex('users_flags_index', '{{%users}}'); + $this->dropIndex('users_role_flags_index', '{{%users}}'); $this->dropIndex('users_email_key', '{{%users}}'); $this->dropIndex('users_username_key', '{{%users}}'); $this->dropTable('{{%users}}'); diff --git a/tests/specs/blog/migrations_maria_db/m200000_000001_create_table_users.php b/tests/specs/blog/migrations_maria_db/m200000_000001_create_table_users.php index 7afd35d4..f8cd744a 100644 --- a/tests/specs/blog/migrations_maria_db/m200000_000001_create_table_users.php +++ b/tests/specs/blog/migrations_maria_db/m200000_000001_create_table_users.php @@ -12,17 +12,18 @@ public function up() 'username' => $this->string(200)->notNull(), 'email' => $this->string(200)->notNull(), 'password' => $this->string()->notNull(), + 'role' => $this->string(20)->null()->defaultValue("reader"), 'flags' => $this->integer()->null()->defaultValue(0), 'created_at' => $this->timestamp()->null()->defaultExpression("CURRENT_TIMESTAMP"), ]); $this->createIndex('users_username_key', '{{%users}}', 'username', true); $this->createIndex('users_email_key', '{{%users}}', 'email', true); - $this->createIndex('users_flags_index', '{{%users}}', 'flags', false); + $this->createIndex('users_role_flags_index', '{{%users}}', 'role,flags', false); } public function down() { - $this->dropIndex('users_flags_index', '{{%users}}'); + $this->dropIndex('users_role_flags_index', '{{%users}}'); $this->dropIndex('users_email_key', '{{%users}}'); $this->dropIndex('users_username_key', '{{%users}}'); $this->dropTable('{{%users}}'); diff --git a/tests/specs/blog/migrations_mysql_db/m200000_000001_create_table_users.php b/tests/specs/blog/migrations_mysql_db/m200000_000001_create_table_users.php index 7afd35d4..f8cd744a 100644 --- a/tests/specs/blog/migrations_mysql_db/m200000_000001_create_table_users.php +++ b/tests/specs/blog/migrations_mysql_db/m200000_000001_create_table_users.php @@ -12,17 +12,18 @@ public function up() 'username' => $this->string(200)->notNull(), 'email' => $this->string(200)->notNull(), 'password' => $this->string()->notNull(), + 'role' => $this->string(20)->null()->defaultValue("reader"), 'flags' => $this->integer()->null()->defaultValue(0), 'created_at' => $this->timestamp()->null()->defaultExpression("CURRENT_TIMESTAMP"), ]); $this->createIndex('users_username_key', '{{%users}}', 'username', true); $this->createIndex('users_email_key', '{{%users}}', 'email', true); - $this->createIndex('users_flags_index', '{{%users}}', 'flags', false); + $this->createIndex('users_role_flags_index', '{{%users}}', 'role,flags', false); } public function down() { - $this->dropIndex('users_flags_index', '{{%users}}'); + $this->dropIndex('users_role_flags_index', '{{%users}}'); $this->dropIndex('users_email_key', '{{%users}}'); $this->dropIndex('users_username_key', '{{%users}}'); $this->dropTable('{{%users}}'); diff --git a/tests/specs/blog/migrations_pgsql_db/m200000_000001_create_table_users.php b/tests/specs/blog/migrations_pgsql_db/m200000_000001_create_table_users.php index ceeb4494..23fadf71 100644 --- a/tests/specs/blog/migrations_pgsql_db/m200000_000001_create_table_users.php +++ b/tests/specs/blog/migrations_pgsql_db/m200000_000001_create_table_users.php @@ -12,17 +12,18 @@ public function safeUp() 'username' => $this->string(200)->notNull(), 'email' => $this->string(200)->notNull(), 'password' => $this->string()->notNull(), + 'role' => $this->string(20)->null()->defaultValue("reader"), 'flags' => $this->integer()->null()->defaultValue(0), 'created_at' => $this->timestamp()->null()->defaultExpression("CURRENT_TIMESTAMP"), ]); $this->createIndex('users_username_key', '{{%users}}', 'username', true); $this->createIndex('users_email_key', '{{%users}}', 'email', true); - $this->createIndex('users_flags_index', '{{%users}}', 'flags', false); + $this->createIndex('users_role_flags_index', '{{%users}}', 'role,flags', false); } public function safeDown() { - $this->dropIndex('users_flags_index', '{{%users}}'); + $this->dropIndex('users_role_flags_index', '{{%users}}'); $this->dropIndex('users_email_key', '{{%users}}'); $this->dropIndex('users_username_key', '{{%users}}'); $this->dropTable('{{%users}}'); diff --git a/tests/specs/blog/migrations_pgsql_db/m200000_000002_create_table_blog_posts.php b/tests/specs/blog/migrations_pgsql_db/m200000_000002_create_table_blog_posts.php index 780ed900..9e9d85dd 100644 --- a/tests/specs/blog/migrations_pgsql_db/m200000_000002_create_table_blog_posts.php +++ b/tests/specs/blog/migrations_pgsql_db/m200000_000002_create_table_blog_posts.php @@ -8,7 +8,7 @@ class m200000_000002_create_table_blog_posts extends \yii\db\Migration public function safeUp() { $this->createTable('{{%blog_posts}}', [ - 0 => 'uid varchar(128) NOT NULL', + 0 => '"uid" varchar(128) NOT NULL', 'title' => $this->string(255)->notNull(), 'slug' => $this->string(200)->null()->defaultValue(null), 'category_id' => $this->integer()->notNull(), diff --git a/tests/specs/blog/migrations_pgsql_db/m200000_000004_create_table_post_comments.php b/tests/specs/blog/migrations_pgsql_db/m200000_000004_create_table_post_comments.php index 731ec10e..2aa48549 100644 --- a/tests/specs/blog/migrations_pgsql_db/m200000_000004_create_table_post_comments.php +++ b/tests/specs/blog/migrations_pgsql_db/m200000_000004_create_table_post_comments.php @@ -11,8 +11,8 @@ public function safeUp() 'id' => $this->bigPrimaryKey(), 'post_id' => $this->string(128)->notNull(), 'author_id' => $this->integer()->notNull(), - 0 => 'message json NOT NULL DEFAULT \'[]\'', - 1 => 'meta_data json NOT NULL DEFAULT \'[]\'', + 0 => '"message" json NOT NULL DEFAULT \'[]\'', + 1 => '"meta_data" json NOT NULL DEFAULT \'[]\'', 'created_at' => $this->integer()->notNull(), ]); $this->addForeignKey('fk_post_comments_post_id_blog_posts_uid', '{{%post_comments}}', 'post_id', '{{%blog_posts}}', 'uid'); diff --git a/tests/specs/blog/models/UserFaker.php b/tests/specs/blog/models/UserFaker.php index 943eea86..d42fb940 100644 --- a/tests/specs/blog/models/UserFaker.php +++ b/tests/specs/blog/models/UserFaker.php @@ -33,6 +33,7 @@ public function generateModel($attributes = []) $model->username = substr($faker->userName, 0, 200); $model->email = substr($faker->safeEmail, 0, 200); $model->password = $faker->password; + $model->role = $faker->randomElement(['admin', 'editor', 'reader']); $model->flags = $faker->numberBetween(0, 1000000); $model->created_at = $faker->dateTimeThisYear('now', 'UTC')->format(DATE_ATOM); if (!is_callable($attributes)) { diff --git a/tests/specs/blog/models/base/User.php b/tests/specs/blog/models/base/User.php index bc2f5493..614718da 100644 --- a/tests/specs/blog/models/base/User.php +++ b/tests/specs/blog/models/base/User.php @@ -9,6 +9,7 @@ * @property string $username * @property string $email * @property string $password + * @property string $role * @property int $flags * @property string $created_at * @@ -23,7 +24,7 @@ public static function tableName() public function rules() { return [ - 'trim' => [['username', 'email', 'password', 'created_at'], 'trim'], + 'trim' => [['username', 'email', 'password', 'role', 'created_at'], 'trim'], 'required' => [['username', 'email', 'password'], 'required'], 'username_unique' => [['username'], 'unique'], 'email_unique' => [['email'], 'unique'], @@ -31,6 +32,7 @@ public function rules() 'email_string' => [['email'], 'string', 'max' => 200], 'email_email' => [['email'], 'email'], 'password_string' => [['password'], 'string'], + 'role_string' => [['role'], 'string', 'max' => 20], 'flags_integer' => [['flags'], 'integer'], 'created_at_datetime' => [['created_at'], 'datetime'], ]; diff --git a/tests/specs/blog_v2.yaml b/tests/specs/blog_v2.yaml index 81076078..68d09367 100644 --- a/tests/specs/blog_v2.yaml +++ b/tests/specs/blog_v2.yaml @@ -241,7 +241,7 @@ components: x-indexes: - unique:login - unique:email - - hash:flags + - hash:role,flags required: - id - login @@ -261,6 +261,13 @@ components: password: type: string format: password + role: + type: string + enum: + - admin + - editor + - reader + x-faker: "$faker->randomElement(['admin', 'editor', 'reader'])" flags: type: integer default: 0 @@ -325,12 +332,12 @@ components: type: string minLength: 1 maxLength: 200 - # lang: - # type: string - # enum: - # - ru - # - eng - # default: ru + lang: + type: string + enum: + - ru + - eng + default: ru category: $ref: "#/components/schemas/Category" active: @@ -372,7 +379,7 @@ components: type: string meta_data: type: string - example: "type=='ticket'" + example: "type=='ticket' && status=='closed'" minLength: 1 maxLength: 300 default: '' @@ -390,7 +397,7 @@ components: required: - id - name - # - lang + - lang properties: id: type: integer @@ -400,11 +407,11 @@ components: type: string x-db-type: VARCHAR maxLength: 100 - # lang: - # type: string - # enum: - # - ru - # - eng + lang: + type: string + enum: + - ru + - eng posts: type: array items: diff --git a/tests/specs/blog_v2/migrations/m200000_000001_create_table_v2_users.php b/tests/specs/blog_v2/migrations/m200000_000001_create_table_v2_users.php index fd61f856..5dbcb200 100644 --- a/tests/specs/blog_v2/migrations/m200000_000001_create_table_v2_users.php +++ b/tests/specs/blog_v2/migrations/m200000_000001_create_table_v2_users.php @@ -12,17 +12,18 @@ public function up() 'login' => $this->text()->notNull(), 'email' => $this->text()->notNull(), 'password' => $this->string()->notNull(), + 'role' => 'enum(\'admin\', \'editor\', \'reader\') NULL DEFAULT NULL', 'flags' => $this->integer()->null()->defaultValue(0), 'created_at' => $this->timestamp()->null()->defaultValue(null), ]); $this->createIndex('v2_users_login_key', '{{%v2_users}}', 'login', true); $this->createIndex('v2_users_email_key', '{{%v2_users}}', 'email', true); - $this->createIndex('v2_users_flags_hash_index', '{{%v2_users}}', 'flags', 'hash'); + $this->createIndex('v2_users_role_flags_hash_index', '{{%v2_users}}', 'role,flags', 'hash'); } public function down() { - $this->dropIndex('v2_users_flags_hash_index', '{{%v2_users}}'); + $this->dropIndex('v2_users_role_flags_hash_index', '{{%v2_users}}'); $this->dropIndex('v2_users_email_key', '{{%v2_users}}'); $this->dropIndex('v2_users_login_key', '{{%v2_users}}'); $this->dropTable('{{%v2_users}}'); diff --git a/tests/specs/blog_v2/migrations/m200000_000002_create_table_v2_posts.php b/tests/specs/blog_v2/migrations/m200000_000002_create_table_v2_posts.php index cf3ca27a..ba307de6 100644 --- a/tests/specs/blog_v2/migrations/m200000_000002_create_table_v2_posts.php +++ b/tests/specs/blog_v2/migrations/m200000_000002_create_table_v2_posts.php @@ -11,6 +11,7 @@ public function up() 'id' => $this->bigPrimaryKey(), 'title' => $this->string(255)->notNull(), 'slug' => $this->string(200)->null()->defaultValue(null), + 'lang' => 'enum(\'ru\', \'eng\') NULL DEFAULT \'ru\'', 'category_id' => $this->bigInteger()->notNull(), 'active' => $this->boolean()->notNull(), 'created_at' => $this->date()->null()->defaultValue(null), diff --git a/tests/specs/blog_v2/migrations/m200000_000003_create_table_v2_tags.php b/tests/specs/blog_v2/migrations/m200000_000003_create_table_v2_tags.php index f27f11fe..32aefd34 100644 --- a/tests/specs/blog_v2/migrations/m200000_000003_create_table_v2_tags.php +++ b/tests/specs/blog_v2/migrations/m200000_000003_create_table_v2_tags.php @@ -10,6 +10,7 @@ public function up() $this->createTable('{{%v2_tags}}', [ 'id' => $this->bigPrimaryKey(), 'name' => $this->string(100)->notNull(), + 'lang' => 'enum(\'ru\', \'eng\') NOT NULL', ]); $this->createIndex('v2_tags_name_key', '{{%v2_tags}}', 'name', true); } diff --git a/tests/specs/blog_v2/migrations_maria_db/m200000_000000_change_table_v2_posts.php b/tests/specs/blog_v2/migrations_maria_db/m200000_000000_change_table_v2_posts.php index c7f6a2a3..e42208b9 100644 --- a/tests/specs/blog_v2/migrations_maria_db/m200000_000000_change_table_v2_posts.php +++ b/tests/specs/blog_v2/migrations_maria_db/m200000_000000_change_table_v2_posts.php @@ -8,6 +8,7 @@ class m200000_000000_change_table_v2_posts extends \yii\db\Migration public function up() { $this->addColumn('{{%v2_posts}}', 'id', $this->bigPrimaryKey()); + $this->addColumn('{{%v2_posts}}', 'lang', 'enum("ru", "eng") NULL DEFAULT \'ru\''); $this->dropColumn('{{%v2_posts}}', 'uid'); $this->alterColumn('{{%v2_posts}}', 'active', $this->tinyInteger(1)->notNull()); $this->alterColumn('{{%v2_posts}}', 'category_id', $this->bigInteger()->notNull()); @@ -22,6 +23,7 @@ public function down() $this->alterColumn('{{%v2_posts}}', 'category_id', $this->integer(11)->notNull()); $this->alterColumn('{{%v2_posts}}', 'active', $this->tinyInteger(1)->notNull()->defaultValue(0)); $this->addColumn('{{%v2_posts}}', 'uid', $this->bigInteger(20)->notNull()); + $this->dropColumn('{{%v2_posts}}', 'lang'); $this->dropColumn('{{%v2_posts}}', 'id'); } } diff --git a/tests/specs/blog_v2/migrations_maria_db/m200000_000001_create_table_v2_tags.php b/tests/specs/blog_v2/migrations_maria_db/m200000_000001_create_table_v2_tags.php index 50ffc28d..1e671e96 100644 --- a/tests/specs/blog_v2/migrations_maria_db/m200000_000001_create_table_v2_tags.php +++ b/tests/specs/blog_v2/migrations_maria_db/m200000_000001_create_table_v2_tags.php @@ -10,6 +10,7 @@ public function up() $this->createTable('{{%v2_tags}}', [ 'id' => $this->bigPrimaryKey(), 0 => 'name varchar(100) NOT NULL', + 'lang' => 'enum("ru", "eng") NOT NULL', ]); $this->createIndex('v2_tags_name_key', '{{%v2_tags}}', 'name', true); } diff --git a/tests/specs/blog_v2/migrations_maria_db/m200000_000004_change_table_v2_users.php b/tests/specs/blog_v2/migrations_maria_db/m200000_000004_change_table_v2_users.php index 59003105..c175f1b5 100644 --- a/tests/specs/blog_v2/migrations_maria_db/m200000_000004_change_table_v2_users.php +++ b/tests/specs/blog_v2/migrations_maria_db/m200000_000004_change_table_v2_users.php @@ -11,16 +11,18 @@ public function up() $this->dropColumn('{{%v2_users}}', 'username'); $this->alterColumn('{{%v2_users}}', 'created_at', $this->timestamp()->null()->defaultValue(null)); $this->alterColumn('{{%v2_users}}', 'email', $this->string(255)->notNull()); + $this->alterColumn('{{%v2_users}}', 'role', 'enum("admin", "editor", "reader") NULL DEFAULT NULL'); $this->dropIndex('v2_users_username_key', '{{%v2_users}}'); $this->createIndex('v2_users_login_key', '{{%v2_users}}', 'login', true); - $this->createIndex('v2_users_flags_hash_index', '{{%v2_users}}', 'flags', 'hash'); + $this->createIndex('v2_users_role_flags_hash_index', '{{%v2_users}}', 'role,flags', 'hash'); } public function down() { - $this->dropIndex('v2_users_flags_hash_index', '{{%v2_users}}'); + $this->dropIndex('v2_users_role_flags_hash_index', '{{%v2_users}}'); $this->dropIndex('v2_users_login_key', '{{%v2_users}}'); $this->createIndex('v2_users_username_key', '{{%v2_users}}', 'username', true); + $this->alterColumn('{{%v2_users}}', 'role', $this->string(20)->null()->defaultValue("reader")); $this->alterColumn('{{%v2_users}}', 'email', $this->string(200)->notNull()); $this->alterColumn('{{%v2_users}}', 'created_at', $this->timestamp()->null()->defaultExpression("current_timestamp()")); $this->addColumn('{{%v2_users}}', 'username', $this->string(200)->notNull()); diff --git a/tests/specs/blog_v2/migrations_mysql_db/m200000_000000_change_table_v2_posts.php b/tests/specs/blog_v2/migrations_mysql_db/m200000_000000_change_table_v2_posts.php index c7f6a2a3..e42208b9 100644 --- a/tests/specs/blog_v2/migrations_mysql_db/m200000_000000_change_table_v2_posts.php +++ b/tests/specs/blog_v2/migrations_mysql_db/m200000_000000_change_table_v2_posts.php @@ -8,6 +8,7 @@ class m200000_000000_change_table_v2_posts extends \yii\db\Migration public function up() { $this->addColumn('{{%v2_posts}}', 'id', $this->bigPrimaryKey()); + $this->addColumn('{{%v2_posts}}', 'lang', 'enum("ru", "eng") NULL DEFAULT \'ru\''); $this->dropColumn('{{%v2_posts}}', 'uid'); $this->alterColumn('{{%v2_posts}}', 'active', $this->tinyInteger(1)->notNull()); $this->alterColumn('{{%v2_posts}}', 'category_id', $this->bigInteger()->notNull()); @@ -22,6 +23,7 @@ public function down() $this->alterColumn('{{%v2_posts}}', 'category_id', $this->integer(11)->notNull()); $this->alterColumn('{{%v2_posts}}', 'active', $this->tinyInteger(1)->notNull()->defaultValue(0)); $this->addColumn('{{%v2_posts}}', 'uid', $this->bigInteger(20)->notNull()); + $this->dropColumn('{{%v2_posts}}', 'lang'); $this->dropColumn('{{%v2_posts}}', 'id'); } } diff --git a/tests/specs/blog_v2/migrations_mysql_db/m200000_000001_create_table_v2_tags.php b/tests/specs/blog_v2/migrations_mysql_db/m200000_000001_create_table_v2_tags.php index 50ffc28d..1e671e96 100644 --- a/tests/specs/blog_v2/migrations_mysql_db/m200000_000001_create_table_v2_tags.php +++ b/tests/specs/blog_v2/migrations_mysql_db/m200000_000001_create_table_v2_tags.php @@ -10,6 +10,7 @@ public function up() $this->createTable('{{%v2_tags}}', [ 'id' => $this->bigPrimaryKey(), 0 => 'name varchar(100) NOT NULL', + 'lang' => 'enum("ru", "eng") NOT NULL', ]); $this->createIndex('v2_tags_name_key', '{{%v2_tags}}', 'name', true); } diff --git a/tests/specs/blog_v2/migrations_mysql_db/m200000_000004_change_table_v2_users.php b/tests/specs/blog_v2/migrations_mysql_db/m200000_000004_change_table_v2_users.php index db190e42..87d83448 100644 --- a/tests/specs/blog_v2/migrations_mysql_db/m200000_000004_change_table_v2_users.php +++ b/tests/specs/blog_v2/migrations_mysql_db/m200000_000004_change_table_v2_users.php @@ -11,16 +11,18 @@ public function up() $this->dropColumn('{{%v2_users}}', 'username'); $this->alterColumn('{{%v2_users}}', 'created_at', $this->timestamp()->null()->defaultValue(null)); $this->alterColumn('{{%v2_users}}', 'email', $this->string(255)->notNull()); + $this->alterColumn('{{%v2_users}}', 'role', 'enum("admin", "editor", "reader") NULL DEFAULT NULL'); $this->dropIndex('v2_users_username_key', '{{%v2_users}}'); $this->createIndex('v2_users_login_key', '{{%v2_users}}', 'login', true); - $this->createIndex('v2_users_flags_hash_index', '{{%v2_users}}', 'flags', 'hash'); + $this->createIndex('v2_users_role_flags_hash_index', '{{%v2_users}}', 'role,flags', 'hash'); } public function down() { - $this->dropIndex('v2_users_flags_hash_index', '{{%v2_users}}'); + $this->dropIndex('v2_users_role_flags_hash_index', '{{%v2_users}}'); $this->dropIndex('v2_users_login_key', '{{%v2_users}}'); $this->createIndex('v2_users_username_key', '{{%v2_users}}', 'username', true); + $this->alterColumn('{{%v2_users}}', 'role', $this->string(20)->null()->defaultValue("reader")); $this->alterColumn('{{%v2_users}}', 'email', $this->string(200)->notNull()); $this->alterColumn('{{%v2_users}}', 'created_at', $this->timestamp()->null()->defaultExpression("CURRENT_TIMESTAMP")); $this->addColumn('{{%v2_users}}', 'username', $this->string(200)->notNull()); diff --git a/tests/specs/blog_v2/migrations_pgsql_db/m200000_000000_change_table_v2_posts.php b/tests/specs/blog_v2/migrations_pgsql_db/m200000_000000_change_table_v2_posts.php index a03de14a..e98488cc 100644 --- a/tests/specs/blog_v2/migrations_pgsql_db/m200000_000000_change_table_v2_posts.php +++ b/tests/specs/blog_v2/migrations_pgsql_db/m200000_000000_change_table_v2_posts.php @@ -8,20 +8,24 @@ class m200000_000000_change_table_v2_posts extends \yii\db\Migration public function safeUp() { $this->addColumn('{{%v2_posts}}', 'id', $this->bigPrimaryKey()); + $this->execute('CREATE TYPE "enum_itt_v2_posts_lang" AS ENUM(\'ru\', \'eng\')'); + $this->addColumn('{{%v2_posts}}', 'lang', '"enum_itt_v2_posts_lang" NULL DEFAULT \'ru\''); $this->dropColumn('{{%v2_posts}}', 'uid'); $this->alterColumn('{{%v2_posts}}', 'active', "DROP DEFAULT"); - $this->alterColumn('{{%v2_posts}}', 'category_id', $this->bigInteger()->notNull()); - $this->alterColumn('{{%v2_posts}}', 'created_by_id', $this->bigInteger()->null()); + $this->alterColumn('{{%v2_posts}}', 'category_id', 'bigint NOT NULL USING "category_id"::bigint'); + $this->alterColumn('{{%v2_posts}}', 'created_by_id', 'bigint NULL USING "created_by_id"::bigint'); $this->dropIndex('v2_posts_slug_key', '{{%v2_posts}}'); } public function safeDown() { $this->createIndex('v2_posts_slug_key', '{{%v2_posts}}', 'slug', true); - $this->alterColumn('{{%v2_posts}}', 'created_by_id', $this->integer()->null()); - $this->alterColumn('{{%v2_posts}}', 'category_id', $this->integer()->notNull()); + $this->alterColumn('{{%v2_posts}}', 'created_by_id', 'int4 NULL USING "created_by_id"::int4'); + $this->alterColumn('{{%v2_posts}}', 'category_id', 'int4 NOT NULL USING "category_id"::int4'); $this->addColumn('{{%v2_posts}}', 'uid', $this->bigInteger()->notNull()); + $this->dropColumn('{{%v2_posts}}', 'lang'); $this->dropColumn('{{%v2_posts}}', 'id'); + $this->execute('DROP TYPE "enum_itt_v2_posts_lang"'); $this->alterColumn('{{%v2_posts}}', 'active', "SET DEFAULT 'f'"); } } diff --git a/tests/specs/blog_v2/migrations_pgsql_db/m200000_000001_create_table_v2_tags.php b/tests/specs/blog_v2/migrations_pgsql_db/m200000_000001_create_table_v2_tags.php index a8d8a98c..2466cff0 100644 --- a/tests/specs/blog_v2/migrations_pgsql_db/m200000_000001_create_table_v2_tags.php +++ b/tests/specs/blog_v2/migrations_pgsql_db/m200000_000001_create_table_v2_tags.php @@ -7,9 +7,11 @@ class m200000_000001_create_table_v2_tags extends \yii\db\Migration { public function safeUp() { + $this->execute('CREATE TYPE "enum_itt_v2_tags_lang" AS ENUM(\'ru\', \'eng\')'); $this->createTable('{{%v2_tags}}', [ 'id' => $this->bigPrimaryKey(), - 0 => 'name varchar(100) NOT NULL', + 0 => '"name" varchar(100) NOT NULL', + 'lang' => '"enum_itt_v2_tags_lang" NOT NULL', ]); $this->createIndex('v2_tags_name_key', '{{%v2_tags}}', 'name', true); } @@ -18,5 +20,6 @@ public function safeDown() { $this->dropIndex('v2_tags_name_key', '{{%v2_tags}}'); $this->dropTable('{{%v2_tags}}'); + $this->execute('DROP TYPE "enum_itt_v2_tags_lang"'); } } diff --git a/tests/specs/blog_v2/migrations_pgsql_db/m200000_000003_change_table_v2_categories.php b/tests/specs/blog_v2/migrations_pgsql_db/m200000_000003_change_table_v2_categories.php index 6e30984f..79990cfd 100644 --- a/tests/specs/blog_v2/migrations_pgsql_db/m200000_000003_change_table_v2_categories.php +++ b/tests/specs/blog_v2/migrations_pgsql_db/m200000_000003_change_table_v2_categories.php @@ -9,7 +9,7 @@ public function safeUp() { $this->addColumn('{{%v2_categories}}', 'cover', $this->text()->notNull()); $this->alterColumn('{{%v2_categories}}', 'active', "DROP DEFAULT"); - $this->alterColumn('{{%v2_categories}}', 'title', $this->string(100)->notNull()); + $this->alterColumn('{{%v2_categories}}', 'title', 'string(100) NOT NULL USING "title"::string'); $this->dropIndex('v2_categories_title_key', '{{%v2_categories}}'); $this->createIndex('v2_categories_title_index', '{{%v2_categories}}', 'title', false); } @@ -18,7 +18,7 @@ public function safeDown() { $this->dropIndex('v2_categories_title_index', '{{%v2_categories}}'); $this->createIndex('v2_categories_title_key', '{{%v2_categories}}', 'title', true); - $this->alterColumn('{{%v2_categories}}', 'title', $this->string(255)->notNull()); + $this->alterColumn('{{%v2_categories}}', 'title', 'varchar(255) NOT NULL USING "title"::varchar'); $this->dropColumn('{{%v2_categories}}', 'cover'); $this->alterColumn('{{%v2_categories}}', 'active', "SET DEFAULT 'f'"); } diff --git a/tests/specs/blog_v2/migrations_pgsql_db/m200000_000004_change_table_v2_users.php b/tests/specs/blog_v2/migrations_pgsql_db/m200000_000004_change_table_v2_users.php index 8dbf692d..96459926 100644 --- a/tests/specs/blog_v2/migrations_pgsql_db/m200000_000004_change_table_v2_users.php +++ b/tests/specs/blog_v2/migrations_pgsql_db/m200000_000004_change_table_v2_users.php @@ -7,23 +7,29 @@ class m200000_000004_change_table_v2_users extends \yii\db\Migration { public function safeUp() { + $this->execute('CREATE TYPE "enum_itt_v2_users_role" AS ENUM(\'admin\', \'editor\', \'reader\')'); $this->addColumn('{{%v2_users}}', 'login', $this->text()->notNull()); $this->dropColumn('{{%v2_users}}', 'username'); $this->alterColumn('{{%v2_users}}', 'created_at', "DROP DEFAULT"); - $this->db->createCommand('ALTER TABLE {{%v2_users}} ALTER COLUMN email SET DATA TYPE varchar(255)')->execute(); + $this->db->createCommand('ALTER TABLE {{%v2_users}} ALTER COLUMN "email" SET DATA TYPE varchar(255)')->execute(); + $this->alterColumn('{{%v2_users}}', 'role', '"enum_itt_v2_users_role" USING "role"::"enum_itt_v2_users_role"'); + $this->alterColumn('{{%v2_users}}', 'role', "DROP DEFAULT"); $this->dropIndex('v2_users_username_key', '{{%v2_users}}'); $this->createIndex('v2_users_login_key', '{{%v2_users}}', 'login', true); - $this->createIndex('v2_users_flags_hash_index', '{{%v2_users}}', 'flags', 'hash'); + $this->createIndex('v2_users_role_flags_hash_index', '{{%v2_users}}', 'role,flags', 'hash'); } public function safeDown() { - $this->dropIndex('v2_users_flags_hash_index', '{{%v2_users}}'); + $this->dropIndex('v2_users_role_flags_hash_index', '{{%v2_users}}'); $this->dropIndex('v2_users_login_key', '{{%v2_users}}'); $this->createIndex('v2_users_username_key', '{{%v2_users}}', 'username', true); + $this->alterColumn('{{%v2_users}}', 'role', 'varchar(20) NULL USING "role"::varchar'); $this->alterColumn('{{%v2_users}}', 'email', $this->string(200)->notNull()); $this->addColumn('{{%v2_users}}', 'username', $this->string(200)->notNull()); $this->dropColumn('{{%v2_users}}', 'login'); $this->alterColumn('{{%v2_users}}', 'created_at', "SET DEFAULT CURRENT_TIMESTAMP"); + $this->alterColumn('{{%v2_users}}', 'role', "SET DEFAULT 'reader'"); + $this->execute('DROP TYPE "enum_itt_v2_users_role"'); } } diff --git a/tests/specs/blog_v2/migrations_pgsql_db/m200000_000005_change_table_v2_comments.php b/tests/specs/blog_v2/migrations_pgsql_db/m200000_000005_change_table_v2_comments.php index 3d24ee30..782080d7 100644 --- a/tests/specs/blog_v2/migrations_pgsql_db/m200000_000005_change_table_v2_comments.php +++ b/tests/specs/blog_v2/migrations_pgsql_db/m200000_000005_change_table_v2_comments.php @@ -11,10 +11,10 @@ public function safeUp() $this->dropForeignKey('fk_v2_comments_post_id_v2_posts_uid', '{{%v2_comments}}'); $this->addColumn('{{%v2_comments}}', 'user_id', $this->bigInteger()->null()->defaultValue(null)); $this->dropColumn('{{%v2_comments}}', 'author_id'); - $this->alterColumn('{{%v2_comments}}', 'created_at', $this->timestamp()->notNull()); - $this->alterColumn('{{%v2_comments}}', 'message', $this->text()->notNull()); + $this->alterColumn('{{%v2_comments}}', 'created_at', 'datetime NOT NULL USING "created_at"::datetime'); + $this->alterColumn('{{%v2_comments}}', 'message', 'text NOT NULL USING "message"::text'); $this->alterColumn('{{%v2_comments}}', 'message', "DROP DEFAULT"); - $this->alterColumn('{{%v2_comments}}', 'meta_data', $this->string(300)->null()); + $this->alterColumn('{{%v2_comments}}', 'meta_data', 'string(300) NULL USING "meta_data"::string'); $this->alterColumn('{{%v2_comments}}', 'meta_data', "DROP NOT NULL"); $this->alterColumn('{{%v2_comments}}', 'meta_data', "SET DEFAULT ''"); $this->addForeignKey('fk_v2_comments_post_id_v2_posts_id', '{{%v2_comments}}', 'post_id', '{{%v2_posts}}', 'id'); diff --git a/tests/specs/blog_v2/models/PostFaker.php b/tests/specs/blog_v2/models/PostFaker.php index 6fc36c0e..a1e8eb81 100644 --- a/tests/specs/blog_v2/models/PostFaker.php +++ b/tests/specs/blog_v2/models/PostFaker.php @@ -32,6 +32,7 @@ public function generateModel($attributes = []) //$model->id = $uniqueFaker->numberBetween(0, 1000000); $model->title = substr($faker->sentence, 0, 255); $model->slug = substr($uniqueFaker->slug, 0, 200); + $model->lang = $faker->randomElement(['ru','eng']); $model->active = $faker->boolean; $model->created_at = $faker->dateTimeThisCentury->format('Y-m-d'); if (!is_callable($attributes)) { diff --git a/tests/specs/blog_v2/models/TagFaker.php b/tests/specs/blog_v2/models/TagFaker.php index 6308fa68..8e0af887 100644 --- a/tests/specs/blog_v2/models/TagFaker.php +++ b/tests/specs/blog_v2/models/TagFaker.php @@ -31,6 +31,7 @@ public function generateModel($attributes = []) $model = new Tag(); //$model->id = $uniqueFaker->numberBetween(0, 1000000); $model->name = substr($faker->text(100), 0, 100); + $model->lang = $faker->randomElement(['ru','eng']); if (!is_callable($attributes)) { $model->setAttributes($attributes, false); } else { diff --git a/tests/specs/blog_v2/models/UserFaker.php b/tests/specs/blog_v2/models/UserFaker.php index 9810c37a..9e2344f9 100644 --- a/tests/specs/blog_v2/models/UserFaker.php +++ b/tests/specs/blog_v2/models/UserFaker.php @@ -33,6 +33,7 @@ public function generateModel($attributes = []) $model->login = $faker->userName; $model->email = substr($faker->safeEmail, 0, 255); $model->password = $faker->password; + $model->role = $faker->randomElement(['admin', 'editor', 'reader']); $model->flags = $faker->numberBetween(0, 1000000); $model->created_at = $faker->dateTimeThisYear('now', 'UTC')->format(DATE_ATOM); if (!is_callable($attributes)) { diff --git a/tests/specs/blog_v2/models/base/Post.php b/tests/specs/blog_v2/models/base/Post.php index 3599eb90..aec86342 100644 --- a/tests/specs/blog_v2/models/base/Post.php +++ b/tests/specs/blog_v2/models/base/Post.php @@ -8,6 +8,7 @@ * @property int $id * @property string $title * @property string $slug + * @property string $lang * @property int $category_id Category of posts * @property bool $active * @property string $created_at @@ -28,7 +29,7 @@ public static function tableName() public function rules() { return [ - 'trim' => [['title', 'slug', 'created_at'], 'trim'], + 'trim' => [['title', 'slug', 'lang', 'created_at'], 'trim'], 'required' => [['title', 'category_id', 'active'], 'required'], 'category_id_integer' => [['category_id'], 'integer'], 'category_id_exist' => [['category_id'], 'exist', 'targetRelation' => 'Category'], @@ -37,6 +38,8 @@ public function rules() 'title_unique' => [['title'], 'unique'], 'title_string' => [['title'], 'string', 'max' => 255], 'slug_string' => [['slug'], 'string', 'min' => 1, 'max' => 200], + 'lang_string' => [['lang'], 'string'], + 'lang_in' => [['lang'], 'in', 'range' => ['ru', 'eng']], 'active_boolean' => [['active'], 'boolean'], 'created_at_date' => [['created_at'], 'date'], ]; diff --git a/tests/specs/blog_v2/models/base/Tag.php b/tests/specs/blog_v2/models/base/Tag.php index 761507a8..2d0e7d6c 100644 --- a/tests/specs/blog_v2/models/base/Tag.php +++ b/tests/specs/blog_v2/models/base/Tag.php @@ -7,6 +7,7 @@ * * @property int $id * @property string $name + * @property string $lang * * @property array|\app\models\Post[] $posts */ @@ -20,10 +21,12 @@ public static function tableName() public function rules() { return [ - 'trim' => [['name'], 'trim'], - 'required' => [['name'], 'required'], + 'trim' => [['name', 'lang'], 'trim'], + 'required' => [['name', 'lang'], 'required'], 'name_unique' => [['name'], 'unique'], 'name_string' => [['name'], 'string', 'max' => 100], + 'lang_string' => [['lang'], 'string'], + 'lang_in' => [['lang'], 'in', 'range' => ['ru', 'eng']], ]; } diff --git a/tests/specs/blog_v2/models/base/User.php b/tests/specs/blog_v2/models/base/User.php index 3470798f..3ac6d337 100644 --- a/tests/specs/blog_v2/models/base/User.php +++ b/tests/specs/blog_v2/models/base/User.php @@ -9,6 +9,7 @@ * @property string $login * @property string $email * @property string $password + * @property string $role * @property int $flags * @property string $created_at * @@ -23,7 +24,7 @@ public static function tableName() public function rules() { return [ - 'trim' => [['login', 'email', 'password', 'created_at'], 'trim'], + 'trim' => [['login', 'email', 'password', 'role', 'created_at'], 'trim'], 'required' => [['login', 'email', 'password'], 'required'], 'login_unique' => [['login'], 'unique'], 'email_unique' => [['email'], 'unique'], @@ -31,6 +32,8 @@ public function rules() 'email_string' => [['email'], 'string', 'max' => 255], 'email_email' => [['email'], 'email'], 'password_string' => [['password'], 'string'], + 'role_string' => [['role'], 'string'], + 'role_in' => [['role'], 'in', 'range' => ['admin', 'editor', 'reader']], 'flags_integer' => [['flags'], 'integer'], 'created_at_datetime' => [['created_at'], 'datetime'], ]; diff --git a/tests/specs/change_column_name/maria/app/migrations_maria_db/m200000_000000_change_table_column_name_changes.php b/tests/specs/change_column_name/maria/app/migrations_maria_db/m200000_000000_change_table_column_name_changes.php new file mode 100644 index 00000000..1a75dbd3 --- /dev/null +++ b/tests/specs/change_column_name/maria/app/migrations_maria_db/m200000_000000_change_table_column_name_changes.php @@ -0,0 +1,19 @@ +db->createCommand('ALTER TABLE {{%column_name_changes}} ADD COLUMN updated_at_2 datetime NOT NULL')->execute(); + $this->dropColumn('{{%column_name_changes}}', 'updated_at'); + } + + public function down() + { + $this->addColumn('{{%column_name_changes}}', 'updated_at', $this->datetime()->notNull()); + $this->dropColumn('{{%column_name_changes}}', 'updated_at_2'); + } +} diff --git a/tests/specs/change_column_name/maria/app/models/BaseModelFaker.php b/tests/specs/change_column_name/maria/app/models/BaseModelFaker.php new file mode 100644 index 00000000..c367fbb4 --- /dev/null +++ b/tests/specs/change_column_name/maria/app/models/BaseModelFaker.php @@ -0,0 +1,144 @@ +faker = FakerFactory::create(str_replace('-', '_', \Yii::$app->language)); + $this->uniqueFaker = new UniqueGenerator($this->faker); + } + + abstract public function generateModel($attributes = []); + + public function getFaker():Generator + { + return $this->faker; + } + + public function getUniqueFaker():UniqueGenerator + { + return $this->uniqueFaker; + } + + public function setFaker(Generator $faker):void + { + $this->faker = $faker; + } + + public function setUniqueFaker(UniqueGenerator $faker):void + { + $this->uniqueFaker = $faker; + } + + /** + * Generate and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::makeOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::makeOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + $model = $fakeBuilder->generateModel($attributes); + return $model; + } + + /** + * Generate, save and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::saveOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::saveOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $model = static::makeOne($attributes, $uniqueFaker); + $model->save(); + return $model; + } + + /** + * Generate and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::make(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::make(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + return $model; + }, range(0, $number -1)); + } + + /** + * Generate, save and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::save(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::save(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + $model->save(); + return $model; + }, range(0, $number -1)); + } +} diff --git a/tests/specs/change_column_name/maria/app/models/ColumnNameChange.php b/tests/specs/change_column_name/maria/app/models/ColumnNameChange.php new file mode 100644 index 00000000..a6fd1c91 --- /dev/null +++ b/tests/specs/change_column_name/maria/app/models/ColumnNameChange.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new ColumnNameChange(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->name = $faker->sentence; + $model->updated_at_2 = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/change_column_name/maria/app/models/base/ColumnNameChange.php b/tests/specs/change_column_name/maria/app/models/base/ColumnNameChange.php new file mode 100644 index 00000000..2289ab14 --- /dev/null +++ b/tests/specs/change_column_name/maria/app/models/base/ColumnNameChange.php @@ -0,0 +1,28 @@ + [['name'], 'trim'], + 'required' => [['name'], 'required'], + 'name_string' => [['name'], 'string'], + ]; + } +} diff --git a/tests/specs/change_column_name/mysql/app/migrations_mysql_db/m200000_000000_change_table_column_name_changes.php b/tests/specs/change_column_name/mysql/app/migrations_mysql_db/m200000_000000_change_table_column_name_changes.php new file mode 100644 index 00000000..1a75dbd3 --- /dev/null +++ b/tests/specs/change_column_name/mysql/app/migrations_mysql_db/m200000_000000_change_table_column_name_changes.php @@ -0,0 +1,19 @@ +db->createCommand('ALTER TABLE {{%column_name_changes}} ADD COLUMN updated_at_2 datetime NOT NULL')->execute(); + $this->dropColumn('{{%column_name_changes}}', 'updated_at'); + } + + public function down() + { + $this->addColumn('{{%column_name_changes}}', 'updated_at', $this->datetime()->notNull()); + $this->dropColumn('{{%column_name_changes}}', 'updated_at_2'); + } +} diff --git a/tests/specs/change_column_name/mysql/app/models/BaseModelFaker.php b/tests/specs/change_column_name/mysql/app/models/BaseModelFaker.php new file mode 100644 index 00000000..c367fbb4 --- /dev/null +++ b/tests/specs/change_column_name/mysql/app/models/BaseModelFaker.php @@ -0,0 +1,144 @@ +faker = FakerFactory::create(str_replace('-', '_', \Yii::$app->language)); + $this->uniqueFaker = new UniqueGenerator($this->faker); + } + + abstract public function generateModel($attributes = []); + + public function getFaker():Generator + { + return $this->faker; + } + + public function getUniqueFaker():UniqueGenerator + { + return $this->uniqueFaker; + } + + public function setFaker(Generator $faker):void + { + $this->faker = $faker; + } + + public function setUniqueFaker(UniqueGenerator $faker):void + { + $this->uniqueFaker = $faker; + } + + /** + * Generate and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::makeOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::makeOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + $model = $fakeBuilder->generateModel($attributes); + return $model; + } + + /** + * Generate, save and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::saveOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::saveOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $model = static::makeOne($attributes, $uniqueFaker); + $model->save(); + return $model; + } + + /** + * Generate and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::make(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::make(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + return $model; + }, range(0, $number -1)); + } + + /** + * Generate, save and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::save(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::save(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + $model->save(); + return $model; + }, range(0, $number -1)); + } +} diff --git a/tests/specs/change_column_name/mysql/app/models/ColumnNameChange.php b/tests/specs/change_column_name/mysql/app/models/ColumnNameChange.php new file mode 100644 index 00000000..a6fd1c91 --- /dev/null +++ b/tests/specs/change_column_name/mysql/app/models/ColumnNameChange.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new ColumnNameChange(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->name = $faker->sentence; + $model->updated_at_2 = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/change_column_name/mysql/app/models/base/ColumnNameChange.php b/tests/specs/change_column_name/mysql/app/models/base/ColumnNameChange.php new file mode 100644 index 00000000..2289ab14 --- /dev/null +++ b/tests/specs/change_column_name/mysql/app/models/base/ColumnNameChange.php @@ -0,0 +1,28 @@ + [['name'], 'trim'], + 'required' => [['name'], 'required'], + 'name_string' => [['name'], 'string'], + ]; + } +} diff --git a/tests/specs/change_column_name/mysql/change_column_name.php b/tests/specs/change_column_name/mysql/change_column_name.php new file mode 100644 index 00000000..9784a19b --- /dev/null +++ b/tests/specs/change_column_name/mysql/change_column_name.php @@ -0,0 +1,13 @@ + '@specs/change_column_name/mysql/change_column_name.yaml', + 'generateUrls' => false, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => true, +]; diff --git a/tests/specs/change_column_name/mysql/change_column_name.yaml b/tests/specs/change_column_name/mysql/change_column_name.yaml new file mode 100644 index 00000000..fb34c6b7 --- /dev/null +++ b/tests/specs/change_column_name/mysql/change_column_name.yaml @@ -0,0 +1,33 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Change column name test +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Column_name_change: + type: object + description: Test model for change in column name test + required: + - id + - name + properties: + id: + type: integer + name: + type: string + x-db-type: varchar(255) + updated_at_2: + readOnly: true + type: string + format: datetime + nullable: false + x-db-type: datetime diff --git a/tests/specs/change_column_name/pgsql/app/migrations_pgsql_db/m200000_000000_change_table_column_name_changes.php b/tests/specs/change_column_name/pgsql/app/migrations_pgsql_db/m200000_000000_change_table_column_name_changes.php new file mode 100644 index 00000000..803cb366 --- /dev/null +++ b/tests/specs/change_column_name/pgsql/app/migrations_pgsql_db/m200000_000000_change_table_column_name_changes.php @@ -0,0 +1,19 @@ +db->createCommand('ALTER TABLE {{%column_name_changes}} ADD COLUMN "updated_at_2" timestamp NOT NULL')->execute(); + $this->dropColumn('{{%column_name_changes}}', 'updated_at'); + } + + public function safeDown() + { + $this->addColumn('{{%column_name_changes}}', 'updated_at', $this->timestamp()->notNull()); + $this->dropColumn('{{%column_name_changes}}', 'updated_at_2'); + } +} diff --git a/tests/specs/change_column_name/pgsql/app/models/BaseModelFaker.php b/tests/specs/change_column_name/pgsql/app/models/BaseModelFaker.php new file mode 100644 index 00000000..c367fbb4 --- /dev/null +++ b/tests/specs/change_column_name/pgsql/app/models/BaseModelFaker.php @@ -0,0 +1,144 @@ +faker = FakerFactory::create(str_replace('-', '_', \Yii::$app->language)); + $this->uniqueFaker = new UniqueGenerator($this->faker); + } + + abstract public function generateModel($attributes = []); + + public function getFaker():Generator + { + return $this->faker; + } + + public function getUniqueFaker():UniqueGenerator + { + return $this->uniqueFaker; + } + + public function setFaker(Generator $faker):void + { + $this->faker = $faker; + } + + public function setUniqueFaker(UniqueGenerator $faker):void + { + $this->uniqueFaker = $faker; + } + + /** + * Generate and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::makeOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::makeOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + $model = $fakeBuilder->generateModel($attributes); + return $model; + } + + /** + * Generate, save and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::saveOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::saveOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $model = static::makeOne($attributes, $uniqueFaker); + $model->save(); + return $model; + } + + /** + * Generate and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::make(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::make(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + return $model; + }, range(0, $number -1)); + } + + /** + * Generate, save and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::save(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::save(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + $model->save(); + return $model; + }, range(0, $number -1)); + } +} diff --git a/tests/specs/change_column_name/pgsql/app/models/ColumnNameChange.php b/tests/specs/change_column_name/pgsql/app/models/ColumnNameChange.php new file mode 100644 index 00000000..a6fd1c91 --- /dev/null +++ b/tests/specs/change_column_name/pgsql/app/models/ColumnNameChange.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new ColumnNameChange(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->name = $faker->sentence; + $model->updated_at_2 = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/change_column_name/pgsql/app/models/base/ColumnNameChange.php b/tests/specs/change_column_name/pgsql/app/models/base/ColumnNameChange.php new file mode 100644 index 00000000..6af1a5ac --- /dev/null +++ b/tests/specs/change_column_name/pgsql/app/models/base/ColumnNameChange.php @@ -0,0 +1,28 @@ + [['name'], 'trim'], + 'required' => [['name'], 'required'], + 'name_string' => [['name'], 'string'], + ]; + } +} diff --git a/tests/specs/change_column_name/pgsql/change_column_name.php b/tests/specs/change_column_name/pgsql/change_column_name.php new file mode 100644 index 00000000..e15f2c06 --- /dev/null +++ b/tests/specs/change_column_name/pgsql/change_column_name.php @@ -0,0 +1,13 @@ + '@specs/change_column_name/pgsql/change_column_name.yaml', + 'generateUrls' => false, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => true, +]; diff --git a/tests/specs/change_column_name/pgsql/change_column_name.yaml b/tests/specs/change_column_name/pgsql/change_column_name.yaml new file mode 100644 index 00000000..ece7f2d2 --- /dev/null +++ b/tests/specs/change_column_name/pgsql/change_column_name.yaml @@ -0,0 +1,33 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Change column name test for Pgsql +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Column_name_change: + type: object + description: Test model for change in column name test for Pgsql + required: + - id + - name + properties: + id: + type: integer + name: + type: string + x-db-type: varchar(255) + updated_at_2: + readOnly: true + type: string + format: datetime + nullable: false + x-db-type: timestamp diff --git a/tests/specs/enum/change/maria/app/migrations_maria_db/m200000_000000_change_table_editcolumns.php b/tests/specs/enum/change/maria/app/migrations_maria_db/m200000_000000_change_table_editcolumns.php new file mode 100644 index 00000000..36a599c6 --- /dev/null +++ b/tests/specs/enum/change/maria/app/migrations_maria_db/m200000_000000_change_table_editcolumns.php @@ -0,0 +1,21 @@ +alterColumn('{{%editcolumns}}', 'camelCaseCol', 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'TWO\''); + $this->alterColumn('{{%editcolumns}}', 'connection', 'enum("WIRED", "WIRELESS") NOT NULL DEFAULT \'WIRED\''); + $this->alterColumn('{{%editcolumns}}', 'device', $this->text()->null()->defaultValue(null)); + } + + public function down() + { + $this->alterColumn('{{%editcolumns}}', 'device', 'enum("MOBILE", "TV", "COMPUTER") NOT NULL DEFAULT \'TV\''); + $this->alterColumn('{{%editcolumns}}', 'connection', $this->string(255)->null()->defaultValue(null)); + $this->alterColumn('{{%editcolumns}}', 'camelCaseCol', $this->string(255)->null()->defaultValue(null)); + } +} diff --git a/tests/specs/enum/change/maria/app/migrations_maria_db/m200000_000001_create_table_newcolumns.php b/tests/specs/enum/change/maria/app/migrations_maria_db/m200000_000001_create_table_newcolumns.php new file mode 100644 index 00000000..36971de6 --- /dev/null +++ b/tests/specs/enum/change/maria/app/migrations_maria_db/m200000_000001_create_table_newcolumns.php @@ -0,0 +1,20 @@ +createTable('{{%newcolumns}}', [ + 'id' => $this->primaryKey(), + 'new_column' => 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'ONE\'', + ]); + } + + public function down() + { + $this->dropTable('{{%newcolumns}}'); + } +} diff --git a/tests/specs/enum/change/maria/app/migrations_maria_db/m200000_000002_create_table_pristines.php b/tests/specs/enum/change/maria/app/migrations_maria_db/m200000_000002_create_table_pristines.php new file mode 100644 index 00000000..bdd46f98 --- /dev/null +++ b/tests/specs/enum/change/maria/app/migrations_maria_db/m200000_000002_create_table_pristines.php @@ -0,0 +1,20 @@ +createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'device' => 'enum("MOBILE", "TV", "COMPUTER") NOT NULL DEFAULT \'TV\'', + ]); + } + + public function down() + { + $this->dropTable('{{%pristines}}'); + } +} diff --git a/tests/specs/enum/change/mysql/app/migrations_mysql_db/m200000_000000_change_table_editcolumns.php b/tests/specs/enum/change/mysql/app/migrations_mysql_db/m200000_000000_change_table_editcolumns.php new file mode 100644 index 00000000..3ad3b894 --- /dev/null +++ b/tests/specs/enum/change/mysql/app/migrations_mysql_db/m200000_000000_change_table_editcolumns.php @@ -0,0 +1,21 @@ +alterColumn('{{%editcolumns}}', 'camelCaseCol', 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'TWO\''); + $this->alterColumn('{{%editcolumns}}', 'connection', 'enum("WIRED", "WIRELESS") NOT NULL DEFAULT \'WIRED\''); + $this->alterColumn('{{%editcolumns}}', 'device', $this->text()->null()); + } + + public function down() + { + $this->alterColumn('{{%editcolumns}}', 'device', 'enum("MOBILE", "TV", "COMPUTER") NOT NULL DEFAULT \'TV\''); + $this->alterColumn('{{%editcolumns}}', 'connection', $this->string(255)->null()->defaultValue(null)); + $this->alterColumn('{{%editcolumns}}', 'camelCaseCol', $this->string(255)->null()->defaultValue(null)); + } +} diff --git a/tests/specs/enum/change/mysql/app/migrations_mysql_db/m200000_000001_create_table_newcolumns.php b/tests/specs/enum/change/mysql/app/migrations_mysql_db/m200000_000001_create_table_newcolumns.php new file mode 100644 index 00000000..36971de6 --- /dev/null +++ b/tests/specs/enum/change/mysql/app/migrations_mysql_db/m200000_000001_create_table_newcolumns.php @@ -0,0 +1,20 @@ +createTable('{{%newcolumns}}', [ + 'id' => $this->primaryKey(), + 'new_column' => 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'ONE\'', + ]); + } + + public function down() + { + $this->dropTable('{{%newcolumns}}'); + } +} diff --git a/tests/specs/enum/change/mysql/app/migrations_mysql_db/m200000_000002_create_table_pristines.php b/tests/specs/enum/change/mysql/app/migrations_mysql_db/m200000_000002_create_table_pristines.php new file mode 100644 index 00000000..bdd46f98 --- /dev/null +++ b/tests/specs/enum/change/mysql/app/migrations_mysql_db/m200000_000002_create_table_pristines.php @@ -0,0 +1,20 @@ +createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'device' => 'enum("MOBILE", "TV", "COMPUTER") NOT NULL DEFAULT \'TV\'', + ]); + } + + public function down() + { + $this->dropTable('{{%pristines}}'); + } +} diff --git a/tests/specs/enum/change/pgsql/app/migrations_pgsql_db/m200000_000000_change_table_editcolumns.php b/tests/specs/enum/change/pgsql/app/migrations_pgsql_db/m200000_000000_change_table_editcolumns.php new file mode 100644 index 00000000..fee56988 --- /dev/null +++ b/tests/specs/enum/change/pgsql/app/migrations_pgsql_db/m200000_000000_change_table_editcolumns.php @@ -0,0 +1,39 @@ +execute('CREATE TYPE "enum_itt_editcolumns_connection" AS ENUM(\'WIRED\', \'WIRELESS\')'); + $this->execute('CREATE TYPE "enum_itt_editcolumns_camelCaseCol" AS ENUM(\'ONE\', \'TWO\', \'THREE\')'); + $this->alterColumn('{{%editcolumns}}', 'camelCaseCol', '"enum_itt_editcolumns_camelCaseCol" USING "camelCaseCol"::"enum_itt_editcolumns_camelCaseCol"'); + $this->alterColumn('{{%editcolumns}}', 'camelCaseCol', "SET NOT NULL"); + $this->alterColumn('{{%editcolumns}}', 'camelCaseCol', "SET DEFAULT 'TWO'"); + $this->alterColumn('{{%editcolumns}}', 'connection', '"enum_itt_editcolumns_connection" USING "connection"::"enum_itt_editcolumns_connection"'); + $this->alterColumn('{{%editcolumns}}', 'connection', "SET NOT NULL"); + $this->alterColumn('{{%editcolumns}}', 'connection', "SET DEFAULT 'WIRED'"); + $this->alterColumn('{{%editcolumns}}', 'device', 'text NULL USING "device"::text'); + $this->alterColumn('{{%editcolumns}}', 'device', "DROP NOT NULL"); + $this->alterColumn('{{%editcolumns}}', 'device', "DROP DEFAULT"); + $this->execute('DROP TYPE "enum_itt_editcolumns_device"'); + } + + public function safeDown() + { + $this->execute('CREATE TYPE "enum_itt_editcolumns_device" AS ENUM(\'MOBILE\', \'TV\', \'COMPUTER\')'); + $this->alterColumn('{{%editcolumns}}', 'device', '"enum_itt_editcolumns_device" USING "device"::"enum_itt_editcolumns_device"'); + $this->alterColumn('{{%editcolumns}}', 'connection', 'varchar(255) NULL USING "connection"::varchar'); + $this->alterColumn('{{%editcolumns}}', 'camelCaseCol', 'varchar(255) NULL USING "camelCaseCol"::varchar'); + $this->alterColumn('{{%editcolumns}}', 'camelCaseCol', "DROP NOT NULL"); + $this->alterColumn('{{%editcolumns}}', 'camelCaseCol', "DROP DEFAULT"); + $this->execute('DROP TYPE "enum_itt_editcolumns_camelCaseCol"'); + $this->alterColumn('{{%editcolumns}}', 'connection', "DROP NOT NULL"); + $this->alterColumn('{{%editcolumns}}', 'connection', "DROP DEFAULT"); + $this->execute('DROP TYPE "enum_itt_editcolumns_connection"'); + $this->alterColumn('{{%editcolumns}}', 'device', "SET NOT NULL"); + $this->alterColumn('{{%editcolumns}}', 'device', "SET DEFAULT 'TV'"); + } +} diff --git a/tests/specs/enum/change/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_newcolumns.php b/tests/specs/enum/change/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_newcolumns.php new file mode 100644 index 00000000..dc4901ee --- /dev/null +++ b/tests/specs/enum/change/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_newcolumns.php @@ -0,0 +1,22 @@ +execute('CREATE TYPE "enum_itt_newcolumns_new_column" AS ENUM(\'ONE\', \'TWO\', \'THREE\')'); + $this->createTable('{{%newcolumns}}', [ + 'id' => $this->primaryKey(), + 'new_column' => '"enum_itt_newcolumns_new_column" NOT NULL DEFAULT \'ONE\'', + ]); + } + + public function safeDown() + { + $this->dropTable('{{%newcolumns}}'); + $this->execute('DROP TYPE "enum_itt_newcolumns_new_column"'); + } +} diff --git a/tests/specs/enum/change/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_pristines.php b/tests/specs/enum/change/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_pristines.php new file mode 100644 index 00000000..45b63115 --- /dev/null +++ b/tests/specs/enum/change/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_pristines.php @@ -0,0 +1,22 @@ +execute('CREATE TYPE "enum_itt_pristines_device" AS ENUM(\'MOBILE\', \'TV\', \'COMPUTER\')'); + $this->createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'device' => '"enum_itt_pristines_device" NOT NULL DEFAULT \'TV\'', + ]); + } + + public function safeDown() + { + $this->dropTable('{{%pristines}}'); + $this->execute('DROP TYPE "enum_itt_pristines_device"'); + } +} diff --git a/tests/specs/enum/fresh/maria/app/migrations_maria_db/m200000_000000_create_table_editcolumns.php b/tests/specs/enum/fresh/maria/app/migrations_maria_db/m200000_000000_create_table_editcolumns.php new file mode 100644 index 00000000..1d2581bf --- /dev/null +++ b/tests/specs/enum/fresh/maria/app/migrations_maria_db/m200000_000000_create_table_editcolumns.php @@ -0,0 +1,22 @@ +createTable('{{%editcolumns}}', [ + 'id' => $this->primaryKey(), + 'device' => $this->text()->null()->defaultValue(null), + 'connection' => 'enum("WIRED", "WIRELESS") NOT NULL DEFAULT \'WIRED\'', + 'camelCaseCol' => 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'TWO\'', + ]); + } + + public function down() + { + $this->dropTable('{{%editcolumns}}'); + } +} diff --git a/tests/specs/enum/fresh/maria/app/migrations_maria_db/m200000_000001_create_table_newcolumns.php b/tests/specs/enum/fresh/maria/app/migrations_maria_db/m200000_000001_create_table_newcolumns.php new file mode 100644 index 00000000..36971de6 --- /dev/null +++ b/tests/specs/enum/fresh/maria/app/migrations_maria_db/m200000_000001_create_table_newcolumns.php @@ -0,0 +1,20 @@ +createTable('{{%newcolumns}}', [ + 'id' => $this->primaryKey(), + 'new_column' => 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'ONE\'', + ]); + } + + public function down() + { + $this->dropTable('{{%newcolumns}}'); + } +} diff --git a/tests/specs/enum/fresh/maria/app/migrations_maria_db/m200000_000002_create_table_pristines.php b/tests/specs/enum/fresh/maria/app/migrations_maria_db/m200000_000002_create_table_pristines.php new file mode 100644 index 00000000..bdd46f98 --- /dev/null +++ b/tests/specs/enum/fresh/maria/app/migrations_maria_db/m200000_000002_create_table_pristines.php @@ -0,0 +1,20 @@ +createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'device' => 'enum("MOBILE", "TV", "COMPUTER") NOT NULL DEFAULT \'TV\'', + ]); + } + + public function down() + { + $this->dropTable('{{%pristines}}'); + } +} diff --git a/tests/specs/enum/fresh/mysql/app/migrations_mysql_db/m200000_000000_create_table_editcolumns.php b/tests/specs/enum/fresh/mysql/app/migrations_mysql_db/m200000_000000_create_table_editcolumns.php new file mode 100644 index 00000000..3aeb5b25 --- /dev/null +++ b/tests/specs/enum/fresh/mysql/app/migrations_mysql_db/m200000_000000_create_table_editcolumns.php @@ -0,0 +1,22 @@ +createTable('{{%editcolumns}}', [ + 'id' => $this->primaryKey(), + 'device' => $this->text()->null(), + 'connection' => 'enum("WIRED", "WIRELESS") NOT NULL DEFAULT \'WIRED\'', + 'camelCaseCol' => 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'TWO\'', + ]); + } + + public function down() + { + $this->dropTable('{{%editcolumns}}'); + } +} diff --git a/tests/specs/enum/fresh/mysql/app/migrations_mysql_db/m200000_000001_create_table_newcolumns.php b/tests/specs/enum/fresh/mysql/app/migrations_mysql_db/m200000_000001_create_table_newcolumns.php new file mode 100644 index 00000000..36971de6 --- /dev/null +++ b/tests/specs/enum/fresh/mysql/app/migrations_mysql_db/m200000_000001_create_table_newcolumns.php @@ -0,0 +1,20 @@ +createTable('{{%newcolumns}}', [ + 'id' => $this->primaryKey(), + 'new_column' => 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'ONE\'', + ]); + } + + public function down() + { + $this->dropTable('{{%newcolumns}}'); + } +} diff --git a/tests/specs/enum/fresh/mysql/app/migrations_mysql_db/m200000_000002_create_table_pristines.php b/tests/specs/enum/fresh/mysql/app/migrations_mysql_db/m200000_000002_create_table_pristines.php new file mode 100644 index 00000000..bdd46f98 --- /dev/null +++ b/tests/specs/enum/fresh/mysql/app/migrations_mysql_db/m200000_000002_create_table_pristines.php @@ -0,0 +1,20 @@ +createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'device' => 'enum("MOBILE", "TV", "COMPUTER") NOT NULL DEFAULT \'TV\'', + ]); + } + + public function down() + { + $this->dropTable('{{%pristines}}'); + } +} diff --git a/tests/specs/enum/fresh/mysql/enum.php b/tests/specs/enum/fresh/mysql/enum.php new file mode 100644 index 00000000..fa0cac3a --- /dev/null +++ b/tests/specs/enum/fresh/mysql/enum.php @@ -0,0 +1,13 @@ + '@specs/enum/fresh/mysql/enum.yaml', + 'generateUrls' => false, + 'generateModels' => false, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => false, +]; diff --git a/tests/specs/enum/fresh/mysql/enum.yaml b/tests/specs/enum/fresh/mysql/enum.yaml new file mode 100644 index 00000000..2dcc0a94 --- /dev/null +++ b/tests/specs/enum/fresh/mysql/enum.yaml @@ -0,0 +1,125 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Enum test +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Pristine: + type: object + description: Enum for migration code generation + required: + - id + properties: + id: + type: integer + device: + type: string + maxLength: 8 + enum: + - MOBILE + - TV + - COMPUTER + default: + TV + nullable: false + + Newcolumn: + type: object + description: New Fresh table with new enum column for migration code generation + required: + - id + properties: + id: + type: integer + # device: + # type: string + # maxLength: 8 + # enum: + # - MOBILE + # - TV + # - COMPUTER + # default: + # TV + # nullable: false + new_column: + type: string + enum: + - ONE + - TWO + - THREE + default: + ONE + nullable: false + + Editcolumn: + type: object + description: Table with edit enum columns for migration code generation + required: + - id + properties: + id: + type: integer + device: + type: string + connection: + type: string + enum: + - WIRED + - WIRELESS + default: + WIRED + nullable: false + camelCaseCol: + type: string + enum: + - ONE + - TWO + - THREE + default: + TWO + nullable: false + + # Enumvaluechange: + # type: object + # description: Table with enum value change for migration code generation + # required: + # - id + # properties: + # id: + # type: integer + # add_one_mood_at_last: + # type: string + # enum: + # # admiration, adoration, appreciation of beauty, amusement, anger, anxiety, awe, awkwardness, boredom, calmness, confusion, craving, disgust, empathic pain, entrancement, excitement, fear, horror, interest, joy, nostalgia, relief + # - INTEREST + # - JOY + # - NOSTALGIA + # - RELIEF # this is it + # remove_last_mood: + # type: string + # enum: + # - INTEREST + # - JOY + # add_mood_in_between: + # type: string + # enum: + # - INTEREST + # - RELIEF # this is it + # - JOY + # - NOSTALGIA + # rename_last_mood: + # type: string + # enum: + # - INTEREST + # - JOY + # - NOSTALGIA_2 + diff --git a/tests/specs/enum/fresh/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_editcolumns.php b/tests/specs/enum/fresh/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_editcolumns.php new file mode 100644 index 00000000..5180bf54 --- /dev/null +++ b/tests/specs/enum/fresh/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_editcolumns.php @@ -0,0 +1,26 @@ +execute('CREATE TYPE "enum_itt_editcolumns_camelCaseCol" AS ENUM(\'ONE\', \'TWO\', \'THREE\')'); + $this->execute('CREATE TYPE "enum_itt_editcolumns_connection" AS ENUM(\'WIRED\', \'WIRELESS\')'); + $this->createTable('{{%editcolumns}}', [ + 'id' => $this->primaryKey(), + 'device' => $this->text()->null()->defaultValue(null), + 'connection' => '"enum_itt_editcolumns_connection" NOT NULL DEFAULT \'WIRED\'', + 'camelCaseCol' => '"enum_itt_editcolumns_camelCaseCol" NOT NULL DEFAULT \'TWO\'', + ]); + } + + public function safeDown() + { + $this->dropTable('{{%editcolumns}}'); + $this->execute('DROP TYPE "enum_itt_editcolumns_connection"'); + $this->execute('DROP TYPE "enum_itt_editcolumns_camelCaseCol"'); + } +} diff --git a/tests/specs/enum/fresh/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_newcolumns.php b/tests/specs/enum/fresh/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_newcolumns.php new file mode 100644 index 00000000..dc4901ee --- /dev/null +++ b/tests/specs/enum/fresh/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_newcolumns.php @@ -0,0 +1,22 @@ +execute('CREATE TYPE "enum_itt_newcolumns_new_column" AS ENUM(\'ONE\', \'TWO\', \'THREE\')'); + $this->createTable('{{%newcolumns}}', [ + 'id' => $this->primaryKey(), + 'new_column' => '"enum_itt_newcolumns_new_column" NOT NULL DEFAULT \'ONE\'', + ]); + } + + public function safeDown() + { + $this->dropTable('{{%newcolumns}}'); + $this->execute('DROP TYPE "enum_itt_newcolumns_new_column"'); + } +} diff --git a/tests/specs/enum/fresh/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_pristines.php b/tests/specs/enum/fresh/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_pristines.php new file mode 100644 index 00000000..45b63115 --- /dev/null +++ b/tests/specs/enum/fresh/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_pristines.php @@ -0,0 +1,22 @@ +execute('CREATE TYPE "enum_itt_pristines_device" AS ENUM(\'MOBILE\', \'TV\', \'COMPUTER\')'); + $this->createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'device' => '"enum_itt_pristines_device" NOT NULL DEFAULT \'TV\'', + ]); + } + + public function safeDown() + { + $this->dropTable('{{%pristines}}'); + $this->execute('DROP TYPE "enum_itt_pristines_device"'); + } +} diff --git a/tests/specs/enum/new_column/maria/app/migrations_maria_db/m200000_000000_create_table_editcolumns.php b/tests/specs/enum/new_column/maria/app/migrations_maria_db/m200000_000000_create_table_editcolumns.php new file mode 100644 index 00000000..1d2581bf --- /dev/null +++ b/tests/specs/enum/new_column/maria/app/migrations_maria_db/m200000_000000_create_table_editcolumns.php @@ -0,0 +1,22 @@ +createTable('{{%editcolumns}}', [ + 'id' => $this->primaryKey(), + 'device' => $this->text()->null()->defaultValue(null), + 'connection' => 'enum("WIRED", "WIRELESS") NOT NULL DEFAULT \'WIRED\'', + 'camelCaseCol' => 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'TWO\'', + ]); + } + + public function down() + { + $this->dropTable('{{%editcolumns}}'); + } +} diff --git a/tests/specs/enum/new_column/maria/app/migrations_maria_db/m200000_000001_change_table_newcolumns.php b/tests/specs/enum/new_column/maria/app/migrations_maria_db/m200000_000001_change_table_newcolumns.php new file mode 100644 index 00000000..4ef6a191 --- /dev/null +++ b/tests/specs/enum/new_column/maria/app/migrations_maria_db/m200000_000001_change_table_newcolumns.php @@ -0,0 +1,19 @@ +addColumn('{{%newcolumns}}', 'new_column', 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'ONE\''); + $this->dropColumn('{{%newcolumns}}', 'delete_col'); + } + + public function down() + { + $this->addColumn('{{%newcolumns}}', 'delete_col', 'enum("FOUR", "FIVE", "SIX") NULL DEFAULT NULL'); + $this->dropColumn('{{%newcolumns}}', 'new_column'); + } +} diff --git a/tests/specs/enum/new_column/maria/app/migrations_maria_db/m200000_000002_create_table_pristines.php b/tests/specs/enum/new_column/maria/app/migrations_maria_db/m200000_000002_create_table_pristines.php new file mode 100644 index 00000000..bdd46f98 --- /dev/null +++ b/tests/specs/enum/new_column/maria/app/migrations_maria_db/m200000_000002_create_table_pristines.php @@ -0,0 +1,20 @@ +createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'device' => 'enum("MOBILE", "TV", "COMPUTER") NOT NULL DEFAULT \'TV\'', + ]); + } + + public function down() + { + $this->dropTable('{{%pristines}}'); + } +} diff --git a/tests/specs/enum/new_column/mysql/app/migrations_mysql_db/m200000_000000_create_table_editcolumns.php b/tests/specs/enum/new_column/mysql/app/migrations_mysql_db/m200000_000000_create_table_editcolumns.php new file mode 100644 index 00000000..3aeb5b25 --- /dev/null +++ b/tests/specs/enum/new_column/mysql/app/migrations_mysql_db/m200000_000000_create_table_editcolumns.php @@ -0,0 +1,22 @@ +createTable('{{%editcolumns}}', [ + 'id' => $this->primaryKey(), + 'device' => $this->text()->null(), + 'connection' => 'enum("WIRED", "WIRELESS") NOT NULL DEFAULT \'WIRED\'', + 'camelCaseCol' => 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'TWO\'', + ]); + } + + public function down() + { + $this->dropTable('{{%editcolumns}}'); + } +} diff --git a/tests/specs/enum/new_column/mysql/app/migrations_mysql_db/m200000_000001_change_table_newcolumns.php b/tests/specs/enum/new_column/mysql/app/migrations_mysql_db/m200000_000001_change_table_newcolumns.php new file mode 100644 index 00000000..4ef6a191 --- /dev/null +++ b/tests/specs/enum/new_column/mysql/app/migrations_mysql_db/m200000_000001_change_table_newcolumns.php @@ -0,0 +1,19 @@ +addColumn('{{%newcolumns}}', 'new_column', 'enum("ONE", "TWO", "THREE") NOT NULL DEFAULT \'ONE\''); + $this->dropColumn('{{%newcolumns}}', 'delete_col'); + } + + public function down() + { + $this->addColumn('{{%newcolumns}}', 'delete_col', 'enum("FOUR", "FIVE", "SIX") NULL DEFAULT NULL'); + $this->dropColumn('{{%newcolumns}}', 'new_column'); + } +} diff --git a/tests/specs/enum/new_column/mysql/app/migrations_mysql_db/m200000_000002_create_table_pristines.php b/tests/specs/enum/new_column/mysql/app/migrations_mysql_db/m200000_000002_create_table_pristines.php new file mode 100644 index 00000000..bdd46f98 --- /dev/null +++ b/tests/specs/enum/new_column/mysql/app/migrations_mysql_db/m200000_000002_create_table_pristines.php @@ -0,0 +1,20 @@ +createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'device' => 'enum("MOBILE", "TV", "COMPUTER") NOT NULL DEFAULT \'TV\'', + ]); + } + + public function down() + { + $this->dropTable('{{%pristines}}'); + } +} diff --git a/tests/specs/enum/new_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_editcolumns.php b/tests/specs/enum/new_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_editcolumns.php new file mode 100644 index 00000000..5180bf54 --- /dev/null +++ b/tests/specs/enum/new_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_editcolumns.php @@ -0,0 +1,26 @@ +execute('CREATE TYPE "enum_itt_editcolumns_camelCaseCol" AS ENUM(\'ONE\', \'TWO\', \'THREE\')'); + $this->execute('CREATE TYPE "enum_itt_editcolumns_connection" AS ENUM(\'WIRED\', \'WIRELESS\')'); + $this->createTable('{{%editcolumns}}', [ + 'id' => $this->primaryKey(), + 'device' => $this->text()->null()->defaultValue(null), + 'connection' => '"enum_itt_editcolumns_connection" NOT NULL DEFAULT \'WIRED\'', + 'camelCaseCol' => '"enum_itt_editcolumns_camelCaseCol" NOT NULL DEFAULT \'TWO\'', + ]); + } + + public function safeDown() + { + $this->dropTable('{{%editcolumns}}'); + $this->execute('DROP TYPE "enum_itt_editcolumns_connection"'); + $this->execute('DROP TYPE "enum_itt_editcolumns_camelCaseCol"'); + } +} diff --git a/tests/specs/enum/new_column/pgsql/app/migrations_pgsql_db/m200000_000001_change_table_newcolumns.php b/tests/specs/enum/new_column/pgsql/app/migrations_pgsql_db/m200000_000001_change_table_newcolumns.php new file mode 100644 index 00000000..a1d79e66 --- /dev/null +++ b/tests/specs/enum/new_column/pgsql/app/migrations_pgsql_db/m200000_000001_change_table_newcolumns.php @@ -0,0 +1,23 @@ +execute('CREATE TYPE "enum_itt_newcolumns_new_column" AS ENUM(\'ONE\', \'TWO\', \'THREE\')'); + $this->addColumn('{{%newcolumns}}', 'new_column', '"enum_itt_newcolumns_new_column" NOT NULL DEFAULT \'ONE\''); + $this->dropColumn('{{%newcolumns}}', 'delete_col'); + $this->execute('DROP TYPE "enum_itt_newcolumns_delete_col"'); + } + + public function safeDown() + { + $this->execute('CREATE TYPE "enum_itt_newcolumns_delete_col" AS ENUM(\'FOUR\', \'FIVE\', \'SIX\')'); + $this->addColumn('{{%newcolumns}}', 'delete_col', '"enum_itt_newcolumns_delete_col" NULL DEFAULT NULL'); + $this->dropColumn('{{%newcolumns}}', 'new_column'); + $this->execute('DROP TYPE "enum_itt_newcolumns_new_column"'); + } +} diff --git a/tests/specs/enum/new_column/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_pristines.php b/tests/specs/enum/new_column/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_pristines.php new file mode 100644 index 00000000..45b63115 --- /dev/null +++ b/tests/specs/enum/new_column/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_pristines.php @@ -0,0 +1,22 @@ +execute('CREATE TYPE "enum_itt_pristines_device" AS ENUM(\'MOBILE\', \'TV\', \'COMPUTER\')'); + $this->createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'device' => '"enum_itt_pristines_device" NOT NULL DEFAULT \'TV\'', + ]); + } + + public function safeDown() + { + $this->dropTable('{{%pristines}}'); + $this->execute('DROP TYPE "enum_itt_pristines_device"'); + } +} diff --git a/tests/specs/id_not_in_rules/app/models/BaseModelFaker.php b/tests/specs/id_not_in_rules/app/models/BaseModelFaker.php new file mode 100644 index 00000000..c367fbb4 --- /dev/null +++ b/tests/specs/id_not_in_rules/app/models/BaseModelFaker.php @@ -0,0 +1,144 @@ +faker = FakerFactory::create(str_replace('-', '_', \Yii::$app->language)); + $this->uniqueFaker = new UniqueGenerator($this->faker); + } + + abstract public function generateModel($attributes = []); + + public function getFaker():Generator + { + return $this->faker; + } + + public function getUniqueFaker():UniqueGenerator + { + return $this->uniqueFaker; + } + + public function setFaker(Generator $faker):void + { + $this->faker = $faker; + } + + public function setUniqueFaker(UniqueGenerator $faker):void + { + $this->uniqueFaker = $faker; + } + + /** + * Generate and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::makeOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::makeOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + $model = $fakeBuilder->generateModel($attributes); + return $model; + } + + /** + * Generate, save and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::saveOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::saveOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $model = static::makeOne($attributes, $uniqueFaker); + $model->save(); + return $model; + } + + /** + * Generate and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::make(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::make(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + return $model; + }, range(0, $number -1)); + } + + /** + * Generate, save and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::save(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::save(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + $model->save(); + return $model; + }, range(0, $number -1)); + } +} diff --git a/tests/specs/id_not_in_rules/app/models/Fruit.php b/tests/specs/id_not_in_rules/app/models/Fruit.php new file mode 100644 index 00000000..c74c53d9 --- /dev/null +++ b/tests/specs/id_not_in_rules/app/models/Fruit.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new Fruit(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->name = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/id_not_in_rules/app/models/base/Fruit.php b/tests/specs/id_not_in_rules/app/models/base/Fruit.php new file mode 100644 index 00000000..4b1fcd72 --- /dev/null +++ b/tests/specs/id_not_in_rules/app/models/base/Fruit.php @@ -0,0 +1,27 @@ + [['name'], 'trim'], + 'required' => [['name'], 'required'], + 'name_string' => [['name'], 'string'], + ]; + } +} diff --git a/tests/specs/id_not_in_rules/id_not_in_rules.php b/tests/specs/id_not_in_rules/id_not_in_rules.php new file mode 100644 index 00000000..73a9ccc7 --- /dev/null +++ b/tests/specs/id_not_in_rules/id_not_in_rules.php @@ -0,0 +1,13 @@ + '@specs/id_not_in_rules/id_not_in_rules.yaml', + 'generateUrls' => false, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => false, + 'generateModelFaker' => true, +]; diff --git a/tests/specs/id_not_in_rules/id_not_in_rules.yaml b/tests/specs/id_not_in_rules/id_not_in_rules.yaml new file mode 100644 index 00000000..0d684370 --- /dev/null +++ b/tests/specs/id_not_in_rules/id_not_in_rules.yaml @@ -0,0 +1,26 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: ID not in rules test +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Fruit: + type: object + description: Test model for model code generation that should not contain id column in rules + required: + - id + - name + properties: + id: + type: integer + name: + type: string diff --git a/tests/specs/issue_fix/camel_case_127/camel_case_127.php b/tests/specs/issue_fix/camel_case_127/camel_case_127.php new file mode 100644 index 00000000..4bce1f41 --- /dev/null +++ b/tests/specs/issue_fix/camel_case_127/camel_case_127.php @@ -0,0 +1,13 @@ + '@specs/issue_fix/camel_case_127/camel_case_127.yaml', + 'generateUrls' => false, + 'generateModels' => false, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => false, +]; diff --git a/tests/specs/issue_fix/camel_case_127/camel_case_127.yaml b/tests/specs/issue_fix/camel_case_127/camel_case_127.yaml new file mode 100644 index 00000000..c904c7d3 --- /dev/null +++ b/tests/specs/issue_fix/camel_case_127/camel_case_127.yaml @@ -0,0 +1,28 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Camel case column name issue \#127 +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Pristine: + type: object + description: Camel Case column name test + required: + - id + properties: + id: + type: integer + firstName: + type: string + newColumn: + type: string + x-db-type: varchar(255) diff --git a/tests/specs/issue_fix/camel_case_127/mysql/app/migrations_mysql_db/m200000_000000_create_table_pristines.php b/tests/specs/issue_fix/camel_case_127/mysql/app/migrations_mysql_db/m200000_000000_create_table_pristines.php new file mode 100644 index 00000000..a99836ac --- /dev/null +++ b/tests/specs/issue_fix/camel_case_127/mysql/app/migrations_mysql_db/m200000_000000_create_table_pristines.php @@ -0,0 +1,21 @@ +createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'firstName' => $this->text()->null(), + 0 => 'newColumn varchar(255) NULL DEFAULT NULL', + ]); + } + + public function down() + { + $this->dropTable('{{%pristines}}'); + } +} diff --git a/tests/specs/issue_fix/camel_case_127/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_pristines.php b/tests/specs/issue_fix/camel_case_127/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_pristines.php new file mode 100644 index 00000000..8b22758a --- /dev/null +++ b/tests/specs/issue_fix/camel_case_127/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_pristines.php @@ -0,0 +1,21 @@ +createTable('{{%pristines}}', [ + 'id' => $this->primaryKey(), + 'firstName' => $this->text()->null()->defaultValue(null), + 0 => '"newColumn" varchar(255) NULL DEFAULT NULL', + ]); + } + + public function safeDown() + { + $this->dropTable('{{%pristines}}'); + } +} diff --git a/tests/specs/issue_fix/float_issue/float_issue.php b/tests/specs/issue_fix/float_issue/float_issue.php new file mode 100644 index 00000000..c3be4693 --- /dev/null +++ b/tests/specs/issue_fix/float_issue/float_issue.php @@ -0,0 +1,13 @@ + '@specs/issue_fix/float_issue/float_issue.yaml', + 'generateUrls' => false, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => false, +]; diff --git a/tests/specs/issue_fix/float_issue/float_issue.yaml b/tests/specs/issue_fix/float_issue/float_issue.yaml new file mode 100644 index 00000000..cc02ef67 --- /dev/null +++ b/tests/specs/issue_fix/float_issue/float_issue.yaml @@ -0,0 +1,28 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: float_issue +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Fruit: + type: object + description: Test model for float_issue + required: + - id + - name + properties: + id: + type: integer + vat_percent: + type: number + format: float + default: 0 diff --git a/tests/specs/issue_fix/no_syntax_error_107/mysql/app/migrations_mysql_db/m200000_000000_change_table_fruits.php b/tests/specs/issue_fix/no_syntax_error_107/mysql/app/migrations_mysql_db/m200000_000000_change_table_fruits.php new file mode 100644 index 00000000..2905aec3 --- /dev/null +++ b/tests/specs/issue_fix/no_syntax_error_107/mysql/app/migrations_mysql_db/m200000_000000_change_table_fruits.php @@ -0,0 +1,19 @@ +db->createCommand('ALTER TABLE {{%fruits}} ADD COLUMN test_emails json NOT NULL')->execute(); + $this->alterColumn('{{%fruits}}', 'name', $this->text()->notNull()); + } + + public function down() + { + $this->alterColumn('{{%fruits}}', 'name', $this->string(255)->null()->defaultValue(null)); + $this->dropColumn('{{%fruits}}', 'test_emails'); + } +} diff --git a/tests/specs/issue_fix/no_syntax_error_107/mysql/no_syntax_error_107.php b/tests/specs/issue_fix/no_syntax_error_107/mysql/no_syntax_error_107.php new file mode 100644 index 00000000..0056078e --- /dev/null +++ b/tests/specs/issue_fix/no_syntax_error_107/mysql/no_syntax_error_107.php @@ -0,0 +1,13 @@ + '@specs/issue_fix/no_syntax_error_107/mysql/no_syntax_error_107.yaml', + 'generateUrls' => false, + 'generateModels' => false, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => false, +]; diff --git a/tests/specs/issue_fix/no_syntax_error_107/mysql/no_syntax_error_107.yaml b/tests/specs/issue_fix/no_syntax_error_107/mysql/no_syntax_error_107.yaml new file mode 100644 index 00000000..cf06addd --- /dev/null +++ b/tests/specs/issue_fix/no_syntax_error_107/mysql/no_syntax_error_107.yaml @@ -0,0 +1,41 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Fix https://github.com/cebe/yii2-openapi/issues/107 Migrations are generated with syntax error and wrong data type in MySQL +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Fruit: + type: object + description: A table to fix \#107 + required: + - id + - name + properties: + id: + type: integer + name: + # type: array + # x-db-type: JSON + # nullable: false + # default: '{}' + + type: array + x-db-type: text + nullable: false + # default: '{}' + + + test_emails: + type: array + x-db-type: JSON + nullable: false + default: '[]' diff --git a/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/migrations_pgsql_db/m200000_000000_change_table_fruits.php b/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/migrations_pgsql_db/m200000_000000_change_table_fruits.php new file mode 100644 index 00000000..0472aa35 --- /dev/null +++ b/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/migrations_pgsql_db/m200000_000000_change_table_fruits.php @@ -0,0 +1,17 @@ +alterColumn('{{%fruits}}', 'colourName', 'text NULL USING "colourName"::text'); + } + + public function safeDown() + { + $this->alterColumn('{{%fruits}}', 'colourName', 'varchar(255) NULL USING "colourName"::varchar'); + } +} diff --git a/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/models/BaseModelFaker.php b/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/models/BaseModelFaker.php new file mode 100644 index 00000000..c367fbb4 --- /dev/null +++ b/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/models/BaseModelFaker.php @@ -0,0 +1,144 @@ +faker = FakerFactory::create(str_replace('-', '_', \Yii::$app->language)); + $this->uniqueFaker = new UniqueGenerator($this->faker); + } + + abstract public function generateModel($attributes = []); + + public function getFaker():Generator + { + return $this->faker; + } + + public function getUniqueFaker():UniqueGenerator + { + return $this->uniqueFaker; + } + + public function setFaker(Generator $faker):void + { + $this->faker = $faker; + } + + public function setUniqueFaker(UniqueGenerator $faker):void + { + $this->uniqueFaker = $faker; + } + + /** + * Generate and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::makeOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::makeOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + $model = $fakeBuilder->generateModel($attributes); + return $model; + } + + /** + * Generate, save and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::saveOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::saveOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $model = static::makeOne($attributes, $uniqueFaker); + $model->save(); + return $model; + } + + /** + * Generate and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::make(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::make(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + return $model; + }, range(0, $number -1)); + } + + /** + * Generate, save and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::save(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::save(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + $model->save(); + return $model; + }, range(0, $number -1)); + } +} diff --git a/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/models/Fruit.php b/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/models/Fruit.php new file mode 100644 index 00000000..c74c53d9 --- /dev/null +++ b/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/models/Fruit.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new Fruit(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->colourName = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/models/base/Fruit.php b/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/models/base/Fruit.php new file mode 100644 index 00000000..51d59253 --- /dev/null +++ b/tests/specs/issue_fix/quote_in_alter_table/pgsql/app/models/base/Fruit.php @@ -0,0 +1,26 @@ + [['colourName'], 'trim'], + 'colourName_string' => [['colourName'], 'string'], + ]; + } +} diff --git a/tests/specs/issue_fix/quote_in_alter_table/pgsql/quote_in_alter_table.php b/tests/specs/issue_fix/quote_in_alter_table/pgsql/quote_in_alter_table.php new file mode 100644 index 00000000..53efa3df --- /dev/null +++ b/tests/specs/issue_fix/quote_in_alter_table/pgsql/quote_in_alter_table.php @@ -0,0 +1,13 @@ + '@specs/issue_fix/quote_in_alter_table/pgsql/quote_in_alter_table.yaml', + 'generateUrls' => false, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => true, +]; diff --git a/tests/specs/issue_fix/quote_in_alter_table/pgsql/quote_in_alter_table.yaml b/tests/specs/issue_fix/quote_in_alter_table/pgsql/quote_in_alter_table.yaml new file mode 100644 index 00000000..3c26bd47 --- /dev/null +++ b/tests/specs/issue_fix/quote_in_alter_table/pgsql/quote_in_alter_table.yaml @@ -0,0 +1,26 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Quote in alter column in Pgsql +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Fruit: + type: object + description: Quote in alter column in Pgsql test + required: + - id + properties: + id: + type: integer + colourName: + type: string + # x-db-type: pg_lsn diff --git a/tests/specs/menu/migrations/m200000_000000_create_table_menus.php b/tests/specs/menu/migrations/m200000_000000_create_table_menus.php index 03cde247..c26156c3 100644 --- a/tests/specs/menu/migrations/m200000_000000_create_table_menus.php +++ b/tests/specs/menu/migrations/m200000_000000_create_table_menus.php @@ -11,8 +11,8 @@ public function safeUp() 'id' => $this->bigPrimaryKey(), 'name' => $this->string(100)->notNull(), 'parent_id' => $this->bigInteger()->null()->defaultValue(null), - 0 => 'args text[] NULL DEFAULT \'{"foo","bar","baz"}\'', - 1 => 'kwargs json NOT NULL DEFAULT \'[{"foo":"bar"},{"buzz":"fizz"}]\'', + 0 => '"args" text[] NULL DEFAULT \'{"foo","bar","baz"}\'', + 1 => '"kwargs" json NOT NULL DEFAULT \'[{"foo":"bar"},{"buzz":"fizz"}]\'', ]); $this->addForeignKey('fk_menus_parent_id_menus_id', '{{%menus}}', 'parent_id', '{{%menus}}', 'id'); } diff --git a/tests/specs/postgres_custom.yaml b/tests/specs/postgres_custom.yaml index fce6664c..519af1ab 100644 --- a/tests/specs/postgres_custom.yaml +++ b/tests/specs/postgres_custom.yaml @@ -35,7 +35,7 @@ components: Custom: x-table: v3_pgcustom x-indexes: - - "gin(to_tsvector('english')):search" + - "gin(to_tsvector('english', status)):search" required: - id properties: @@ -48,28 +48,28 @@ components: default: 0 json1: type: array - x-db-type: json + x-db-type: jsonb default: [] json2: type: array - x-db-type: json + x-db-type: jsonb default: '{}' json3: type: array - x-db-type: json + x-db-type: jsonb default: - foo: foobar - xxx: yyy json4: type: array - x-db-type: json + x-db-type: jsonb default: '{"foo": "bar", "bar": "baz"}' - # status: - # type: string - # default: draft - # enum: - # - active - # - draft + status: + type: string + default: draft + enum: + - active + - draft search: type: string x-db-type: tsvector diff --git a/tests/specs/postgres_custom/migrations/m200000_000000_create_table_v3_pgcustom.php b/tests/specs/postgres_custom/migrations/m200000_000000_create_table_v3_pgcustom.php index 6855df2a..fbf76227 100644 --- a/tests/specs/postgres_custom/migrations/m200000_000000_create_table_v3_pgcustom.php +++ b/tests/specs/postgres_custom/migrations/m200000_000000_create_table_v3_pgcustom.php @@ -14,9 +14,10 @@ public function up() 'json2' => 'json NOT NULL DEFAULT \'[]\'', 'json3' => 'json NOT NULL DEFAULT \'[{"foo":"foobar"},{"xxx":"yyy"}]\'', 'json4' => 'json NOT NULL DEFAULT \'{"foo":"bar","bar":"baz"}\'', + 'status' => 'enum(\'active\', \'draft\') NULL DEFAULT \'draft\'', 'search' => 'tsvector NULL', ]); - $this->createIndex('v3_pgcustom_search_gin_index', '{{%v3_pgcustom}}', 'search', 'gin(to_tsvector(\'english\'))'); + $this->createIndex('v3_pgcustom_search_gin_index', '{{%v3_pgcustom}}', 'search', 'gin(to_tsvector(\'english\', status))'); } public function down() diff --git a/tests/specs/postgres_custom/migrations_pgsql_db/m200000_000000_change_table_v3_pgcustom.php b/tests/specs/postgres_custom/migrations_pgsql_db/m200000_000000_change_table_v3_pgcustom.php index f0608474..c04adc88 100644 --- a/tests/specs/postgres_custom/migrations_pgsql_db/m200000_000000_change_table_v3_pgcustom.php +++ b/tests/specs/postgres_custom/migrations_pgsql_db/m200000_000000_change_table_v3_pgcustom.php @@ -15,7 +15,8 @@ public function safeUp() $this->alterColumn('{{%v3_pgcustom}}', 'json3', "SET DEFAULT '[{\"foo\":\"foobar\"},{\"xxx\":\"yyy\"}]'"); $this->alterColumn('{{%v3_pgcustom}}', 'json4', "SET NOT NULL"); $this->alterColumn('{{%v3_pgcustom}}', 'json4', "SET DEFAULT '{\"foo\":\"bar\",\"bar\":\"baz\"}'"); - $this->createIndex('v3_pgcustom_search_gin_index', '{{%v3_pgcustom}}', 'search', 'gin(to_tsvector(\'english\'))'); + $this->alterColumn('{{%v3_pgcustom}}', 'status', "SET DEFAULT 'draft'"); + $this->createIndex('v3_pgcustom_search_gin_index', '{{%v3_pgcustom}}', 'search', 'gin(to_tsvector(\'english\', status))'); } public function safeDown() @@ -29,5 +30,6 @@ public function safeDown() $this->alterColumn('{{%v3_pgcustom}}', 'json3', "SET DEFAULT '{\"bar\":\"baz\",\"foo\":\"bar\"}'"); $this->alterColumn('{{%v3_pgcustom}}', 'json4', "DROP NOT NULL"); $this->alterColumn('{{%v3_pgcustom}}', 'json4', "SET DEFAULT '{\"ffo\":\"bar\"}'"); + $this->alterColumn('{{%v3_pgcustom}}', 'status', "DROP DEFAULT"); } } diff --git a/tests/specs/postgres_custom/models/CustomFaker.php b/tests/specs/postgres_custom/models/CustomFaker.php index 373217df..6c7de598 100644 --- a/tests/specs/postgres_custom/models/CustomFaker.php +++ b/tests/specs/postgres_custom/models/CustomFaker.php @@ -35,6 +35,7 @@ public function generateModel($attributes = []) $model->json2 = []; $model->json3 = []; $model->json4 = []; + $model->status = $faker->randomElement(['active','draft']); if (!is_callable($attributes)) { $model->setAttributes($attributes, false); } else { diff --git a/tests/specs/postgres_custom/models/base/Custom.php b/tests/specs/postgres_custom/models/base/Custom.php index 9190b60a..e19f3700 100644 --- a/tests/specs/postgres_custom/models/base/Custom.php +++ b/tests/specs/postgres_custom/models/base/Custom.php @@ -11,6 +11,7 @@ * @property array $json2 * @property array $json3 * @property array $json4 + * @property string $status * @property string $search * */ @@ -24,7 +25,10 @@ public static function tableName() public function rules() { return [ + 'trim' => [['status'], 'trim'], 'num_integer' => [['num'], 'integer'], + 'status_string' => [['status'], 'string'], + 'status_in' => [['status'], 'in', 'range' => ['active', 'draft']], 'safe' => [['json1', 'json2', 'json3', 'json4'], 'safe'], ]; } diff --git a/tests/specs/x_db_type/edit_column/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php b/tests/specs/x_db_type/edit_column/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php index 4d1b1590..6e7ab8a7 100644 --- a/tests/specs/x_db_type/edit_column/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php +++ b/tests/specs/x_db_type/edit_column/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php @@ -19,6 +19,7 @@ public function up() 7 => 'col_9 varchar(9) NULL DEFAULT NULL', 8 => 'col_10 varchar(10) NULL DEFAULT NULL', 9 => 'col_11 text NULL DEFAULT NULL', + 10 => 'price decimal(10,2) NULL DEFAULT 0', ]); } diff --git a/tests/specs/x_db_type/edit_column/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php b/tests/specs/x_db_type/edit_column/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php index aeed5fe1..3e9e8e02 100644 --- a/tests/specs/x_db_type/edit_column/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php +++ b/tests/specs/x_db_type/edit_column/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php @@ -19,6 +19,7 @@ public function up() 7 => 'col_9 varchar(9) NULL DEFAULT NULL', 8 => 'col_10 varchar(10) NULL DEFAULT NULL', 9 => 'col_11 text NULL', + 10 => 'price decimal(10,2) NULL DEFAULT 0', ]); } diff --git a/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php b/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php index 53498798..e0cac52a 100644 --- a/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php +++ b/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php @@ -9,99 +9,99 @@ public function safeUp() { $this->createTable('{{%alldbdatatypes}}', [ 'id' => $this->bigPrimaryKey(), - 0 => 'string_col varchar NULL DEFAULT NULL', - 1 => 'varchar_col varchar NULL DEFAULT NULL', - 2 => 'text_col text NULL DEFAULT NULL', - 3 => 'text_col_array text[] NULL DEFAULT NULL', - 4 => 'varchar_4_col varchar(4) NULL DEFAULT NULL', - 5 => 'varchar_5_col varchar(5) NULL DEFAULT NULL', - 6 => 'char_4_col char(4) NULL DEFAULT NULL', - 7 => 'char_5_col char NULL DEFAULT NULL', - 8 => 'char_6_col char NOT NULL', - 9 => 'char_7_col char(6) NOT NULL', - 10 => 'char_8_col char NULL DEFAULT \'d\'', - 11 => 'decimal_col decimal(12,3) NULL DEFAULT NULL', - 12 => 'bytea_col_2 bytea NULL DEFAULT NULL', - 13 => 'bit_col bit NULL DEFAULT NULL', - 14 => 'bit_2 bit(1) NULL DEFAULT NULL', - 15 => 'bit_3 bit(64) NULL DEFAULT NULL', - 16 => 'ti smallint NULL DEFAULT NULL', - 17 => 'int2_col int2 NULL DEFAULT NULL', - 18 => 'smallserial_col smallserial NOT NULL', - 19 => 'serial2_col serial2 NOT NULL', - 20 => 'si_col smallint NULL DEFAULT NULL', - 21 => 'si_col_2 smallint NULL DEFAULT NULL', - 22 => 'bi bigint NULL DEFAULT NULL', - 23 => 'bi2 int8 NULL DEFAULT NULL', - 24 => 'int4_col int4 NULL DEFAULT NULL', - 25 => 'bigserial_col bigserial NOT NULL', - 26 => 'bigserial_col_2 serial8 NOT NULL', - 27 => 'int_col int NULL DEFAULT NULL', - 28 => 'int_col_2 integer NULL DEFAULT NULL', - 29 => 'numeric_col numeric NULL DEFAULT NULL', - 30 => 'numeric_col_2 numeric(10) NULL DEFAULT NULL', - 31 => 'numeric_col_3 numeric(10,2) NULL DEFAULT NULL', - 32 => 'double_p_2 double precision NULL DEFAULT NULL', - 33 => 'double_p_3 double precision NULL DEFAULT NULL', - 34 => 'real_col real NULL DEFAULT NULL', - 35 => 'float4_col float4 NULL DEFAULT NULL', - 36 => 'date_col date NULL DEFAULT NULL', - 37 => 'time_col time NULL DEFAULT NULL', - 38 => 'time_col_2 time with time zone NULL DEFAULT NULL', - 39 => 'time_col_3 time without time zone NULL DEFAULT NULL', - 40 => 'time_col_4 time(3) without time zone NULL DEFAULT NULL', - 41 => 'timetz_col timetz NULL DEFAULT NULL', - 42 => 'timetz_col_2 timetz(3) NULL DEFAULT NULL', - 43 => 'timestamp_col timestamp NULL DEFAULT NULL', - 44 => 'timestamp_col_2 timestamp with time zone NULL DEFAULT NULL', - 45 => 'timestamp_col_3 timestamp without time zone NULL DEFAULT NULL', - 46 => 'timestamp_col_4 timestamp(3) without time zone NULL DEFAULT NULL', - 47 => 'timestamptz_col timestamptz NULL DEFAULT NULL', - 48 => 'timestamptz_col_2 timestamptz(3) NULL DEFAULT NULL', - 49 => 'date2 date NULL DEFAULT NULL', - 50 => 'timestamp_col_z timestamp NULL DEFAULT NULL', - 51 => 'bit_varying bit varying NULL DEFAULT NULL', - 52 => 'bit_varying_n bit varying(8) NULL DEFAULT NULL', - 53 => 'bit_varying_n_2 varbit NULL DEFAULT NULL', - 54 => 'bit_varying_n_3 varbit(3) NULL DEFAULT NULL', - 55 => 'bool_col boolean NULL DEFAULT NULL', - 56 => 'bool_col_2 bool NULL DEFAULT NULL', - 57 => 'box_col box NULL DEFAULT NULL', - 58 => 'character_col character NULL DEFAULT NULL', - 59 => 'character_n character(12) NULL DEFAULT NULL', - 60 => 'character_varying character varying NULL DEFAULT NULL', - 61 => 'character_varying_n character varying(12) NULL DEFAULT NULL', - 62 => 'json_col json NOT NULL', - 63 => 'jsonb_col jsonb NOT NULL', - 64 => 'json_col_def json NOT NULL DEFAULT \'[]\'', - 65 => 'json_col_def_2 json NOT NULL DEFAULT \'[]\'', - 66 => 'bytea_def bytea NULL DEFAULT \'the bytea blob default\'', - 67 => 'text_def text NULL DEFAULT \'the text\'', - 68 => 'json_def json NOT NULL DEFAULT \'{"a":"b"}\'', - 69 => 'jsonb_def jsonb NOT NULL DEFAULT \'{"ba":"bb"}\'', - 70 => 'cidr_col cidr NULL DEFAULT NULL', - 71 => 'circle_col circle NULL DEFAULT NULL', - 72 => 'date_col_z date NULL DEFAULT NULL', - 73 => 'float8_col float8 NULL DEFAULT NULL', - 74 => 'inet_col inet NULL DEFAULT NULL', - 75 => 'interval_col interval NULL DEFAULT NULL', - 76 => 'interval_col_2 interval year NULL DEFAULT NULL', - 77 => 'interval_col_3 interval day to second(3) NULL DEFAULT NULL', - 78 => 'line_col line NULL DEFAULT NULL', - 79 => 'lseg_col lseg NULL DEFAULT NULL', - 80 => 'macaddr_col macaddr NULL DEFAULT NULL', - 81 => 'money_col money NULL DEFAULT NULL', - 82 => 'path_col path NULL DEFAULT NULL', - 83 => 'pg_lsn_col pg_lsn NULL DEFAULT NULL', - 84 => 'point_col point NULL DEFAULT NULL', - 85 => 'polygon_col polygon NULL DEFAULT NULL', - 86 => 'serial_col serial NOT NULL', - 87 => 'serial4_col serial4 NOT NULL', - 88 => 'tsquery_col tsquery NULL DEFAULT NULL', - 89 => 'tsvector_col tsvector NULL', - 90 => 'txid_snapshot_col txid_snapshot NULL DEFAULT NULL', - 91 => 'uuid_col uuid NULL DEFAULT NULL', - 92 => 'xml_col xml NULL DEFAULT NULL', + 0 => '"string_col" varchar NULL DEFAULT NULL', + 1 => '"varchar_col" varchar NULL DEFAULT NULL', + 2 => '"text_col" text NULL DEFAULT NULL', + 3 => '"text_col_array" text[] NULL DEFAULT NULL', + 4 => '"varchar_4_col" varchar(4) NULL DEFAULT NULL', + 5 => '"varchar_5_col" varchar(5) NULL DEFAULT NULL', + 6 => '"char_4_col" char(4) NULL DEFAULT NULL', + 7 => '"char_5_col" char NULL DEFAULT NULL', + 8 => '"char_6_col" char NOT NULL', + 9 => '"char_7_col" char(6) NOT NULL', + 10 => '"char_8_col" char NULL DEFAULT \'d\'', + 11 => '"decimal_col" decimal(12,3) NULL DEFAULT NULL', + 12 => '"bytea_col_2" bytea NULL DEFAULT NULL', + 13 => '"bit_col" bit NULL DEFAULT NULL', + 14 => '"bit_2" bit(1) NULL DEFAULT NULL', + 15 => '"bit_3" bit(64) NULL DEFAULT NULL', + 16 => '"ti" smallint NULL DEFAULT NULL', + 17 => '"int2_col" int2 NULL DEFAULT NULL', + 18 => '"smallserial_col" smallserial NOT NULL', + 19 => '"serial2_col" serial2 NOT NULL', + 20 => '"si_col" smallint NULL DEFAULT NULL', + 21 => '"si_col_2" smallint NULL DEFAULT NULL', + 22 => '"bi" bigint NULL DEFAULT NULL', + 23 => '"bi2" int8 NULL DEFAULT NULL', + 24 => '"int4_col" int4 NULL DEFAULT NULL', + 25 => '"bigserial_col" bigserial NOT NULL', + 26 => '"bigserial_col_2" serial8 NOT NULL', + 27 => '"int_col" int NULL DEFAULT NULL', + 28 => '"int_col_2" integer NULL DEFAULT NULL', + 29 => '"numeric_col" numeric NULL DEFAULT NULL', + 30 => '"numeric_col_2" numeric(10) NULL DEFAULT NULL', + 31 => '"numeric_col_3" numeric(10,2) NULL DEFAULT NULL', + 32 => '"double_p_2" double precision NULL DEFAULT NULL', + 33 => '"double_p_3" double precision NULL DEFAULT NULL', + 34 => '"real_col" real NULL DEFAULT NULL', + 35 => '"float4_col" float4 NULL DEFAULT NULL', + 36 => '"date_col" date NULL DEFAULT NULL', + 37 => '"time_col" time NULL DEFAULT NULL', + 38 => '"time_col_2" time with time zone NULL DEFAULT NULL', + 39 => '"time_col_3" time without time zone NULL DEFAULT NULL', + 40 => '"time_col_4" time(3) without time zone NULL DEFAULT NULL', + 41 => '"timetz_col" timetz NULL DEFAULT NULL', + 42 => '"timetz_col_2" timetz(3) NULL DEFAULT NULL', + 43 => '"timestamp_col" timestamp NULL DEFAULT NULL', + 44 => '"timestamp_col_2" timestamp with time zone NULL DEFAULT NULL', + 45 => '"timestamp_col_3" timestamp without time zone NULL DEFAULT NULL', + 46 => '"timestamp_col_4" timestamp(3) without time zone NULL DEFAULT NULL', + 47 => '"timestamptz_col" timestamptz NULL DEFAULT NULL', + 48 => '"timestamptz_col_2" timestamptz(3) NULL DEFAULT NULL', + 49 => '"date2" date NULL DEFAULT NULL', + 50 => '"timestamp_col_z" timestamp NULL DEFAULT NULL', + 51 => '"bit_varying" bit varying NULL DEFAULT NULL', + 52 => '"bit_varying_n" bit varying(8) NULL DEFAULT NULL', + 53 => '"bit_varying_n_2" varbit NULL DEFAULT NULL', + 54 => '"bit_varying_n_3" varbit(3) NULL DEFAULT NULL', + 55 => '"bool_col" boolean NULL DEFAULT NULL', + 56 => '"bool_col_2" bool NULL DEFAULT NULL', + 57 => '"box_col" box NULL DEFAULT NULL', + 58 => '"character_col" character NULL DEFAULT NULL', + 59 => '"character_n" character(12) NULL DEFAULT NULL', + 60 => '"character_varying" character varying NULL DEFAULT NULL', + 61 => '"character_varying_n" character varying(12) NULL DEFAULT NULL', + 62 => '"json_col" json NOT NULL', + 63 => '"jsonb_col" jsonb NOT NULL', + 64 => '"json_col_def" json NOT NULL DEFAULT \'[]\'', + 65 => '"json_col_def_2" json NOT NULL DEFAULT \'[]\'', + 66 => '"bytea_def" bytea NULL DEFAULT \'the bytea blob default\'', + 67 => '"text_def" text NULL DEFAULT \'the text\'', + 68 => '"json_def" json NOT NULL DEFAULT \'{"a":"b"}\'', + 69 => '"jsonb_def" jsonb NOT NULL DEFAULT \'{"ba":"bb"}\'', + 70 => '"cidr_col" cidr NULL DEFAULT NULL', + 71 => '"circle_col" circle NULL DEFAULT NULL', + 72 => '"date_col_z" date NULL DEFAULT NULL', + 73 => '"float8_col" float8 NULL DEFAULT NULL', + 74 => '"inet_col" inet NULL DEFAULT NULL', + 75 => '"interval_col" interval NULL DEFAULT NULL', + 76 => '"interval_col_2" interval year NULL DEFAULT NULL', + 77 => '"interval_col_3" interval day to second(3) NULL DEFAULT NULL', + 78 => '"line_col" line NULL DEFAULT NULL', + 79 => '"lseg_col" lseg NULL DEFAULT NULL', + 80 => '"macaddr_col" macaddr NULL DEFAULT NULL', + 81 => '"money_col" money NULL DEFAULT NULL', + 82 => '"path_col" path NULL DEFAULT NULL', + 83 => '"pg_lsn_col" pg_lsn NULL DEFAULT NULL', + 84 => '"point_col" point NULL DEFAULT NULL', + 85 => '"polygon_col" polygon NULL DEFAULT NULL', + 86 => '"serial_col" serial NOT NULL', + 87 => '"serial4_col" serial4 NOT NULL', + 88 => '"tsquery_col" tsquery NULL DEFAULT NULL', + 89 => '"tsvector_col" tsvector NULL', + 90 => '"txid_snapshot_col" txid_snapshot NULL DEFAULT NULL', + 91 => '"uuid_col" uuid NULL DEFAULT NULL', + 92 => '"xml_col" xml NULL DEFAULT NULL', ]); } diff --git a/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000001_change_table_editcolumns.php b/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000001_change_table_editcolumns.php index d412271c..1c34a89a 100644 --- a/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000001_change_table_editcolumns.php +++ b/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000001_change_table_editcolumns.php @@ -7,31 +7,33 @@ class m200000_000001_change_table_editcolumns extends \yii\db\Migration { public function safeUp() { - $this->db->createCommand('ALTER TABLE {{%editcolumns}} ADD COLUMN first_name varchar NULL DEFAULT NULL')->execute(); - $this->db->createCommand('ALTER TABLE {{%editcolumns}} ADD COLUMN json_col_def_n json NOT NULL DEFAULT \'[]\'')->execute(); - $this->db->createCommand('ALTER TABLE {{%editcolumns}} ADD COLUMN json_col_def_n_2 json NOT NULL DEFAULT \'[]\'')->execute(); - $this->db->createCommand('ALTER TABLE {{%editcolumns}} ADD COLUMN text_col_array text[] NULL DEFAULT NULL')->execute(); + $this->db->createCommand('ALTER TABLE {{%editcolumns}} ADD COLUMN "first_name" varchar NULL DEFAULT NULL')->execute(); + $this->db->createCommand('ALTER TABLE {{%editcolumns}} ADD COLUMN "json_col_def_n" json NOT NULL DEFAULT \'[]\'')->execute(); + $this->db->createCommand('ALTER TABLE {{%editcolumns}} ADD COLUMN "json_col_def_n_2" json NOT NULL DEFAULT \'[]\'')->execute(); + $this->db->createCommand('ALTER TABLE {{%editcolumns}} ADD COLUMN "text_col_array" text[] NULL DEFAULT NULL')->execute(); + $this->db->createCommand('ALTER TABLE {{%editcolumns}} ALTER COLUMN "dec_col" SET DATA TYPE decimal(12,2) USING "dec_col"::decimal(12,2)')->execute(); $this->alterColumn('{{%editcolumns}}', 'dec_col', "SET DEFAULT 3.14"); - $this->db->createCommand('ALTER TABLE {{%editcolumns}} ALTER COLUMN json_col SET DATA TYPE text')->execute(); + $this->db->createCommand('ALTER TABLE {{%editcolumns}} ALTER COLUMN "json_col" SET DATA TYPE text USING "json_col"::text')->execute(); $this->alterColumn('{{%editcolumns}}', 'json_col', "SET NOT NULL"); $this->alterColumn('{{%editcolumns}}', 'json_col', "SET DEFAULT 'fox jumps over dog'"); $this->alterColumn('{{%editcolumns}}', 'json_col_2', "SET NOT NULL"); $this->alterColumn('{{%editcolumns}}', 'json_col_2', "SET DEFAULT '[]'"); - $this->db->createCommand('ALTER TABLE {{%editcolumns}} ALTER COLUMN name SET DATA TYPE varchar(254)')->execute(); + $this->db->createCommand('ALTER TABLE {{%editcolumns}} ALTER COLUMN "name" SET DATA TYPE varchar(254)')->execute(); $this->alterColumn('{{%editcolumns}}', 'name', "SET DEFAULT 'Horse-2'"); - $this->db->createCommand('ALTER TABLE {{%editcolumns}} ALTER COLUMN numeric_col SET DATA TYPE double precision')->execute(); + $this->db->createCommand('ALTER TABLE {{%editcolumns}} ALTER COLUMN "numeric_col" SET DATA TYPE double precision USING "numeric_col"::double precision')->execute(); $this->alterColumn('{{%editcolumns}}', 'str_col_def', "SET NOT NULL"); $this->alterColumn('{{%editcolumns}}', 'str_col_def', "DROP DEFAULT"); - $this->alterColumn('{{%editcolumns}}', 'string_col', $this->text()->null()); + $this->alterColumn('{{%editcolumns}}', 'string_col', 'text NULL USING "string_col"::text'); $this->alterColumn('{{%editcolumns}}', 'string_col', "DROP NOT NULL"); } public function safeDown() { - $this->alterColumn('{{%editcolumns}}', 'string_col', $this->string(255)->notNull()); + $this->alterColumn('{{%editcolumns}}', 'string_col', 'varchar(255) NOT NULL USING "string_col"::varchar'); $this->alterColumn('{{%editcolumns}}', 'numeric_col', 'int4 NULL USING "numeric_col"::int4'); $this->alterColumn('{{%editcolumns}}', 'name', $this->string(255)->notNull()); $this->alterColumn('{{%editcolumns}}', 'json_col', 'jsonb NULL USING "json_col"::jsonb'); + $this->alterColumn('{{%editcolumns}}', 'dec_col', 'numeric NULL USING "dec_col"::numeric'); $this->dropColumn('{{%editcolumns}}', 'text_col_array'); $this->dropColumn('{{%editcolumns}}', 'json_col_def_n_2'); $this->dropColumn('{{%editcolumns}}', 'json_col_def_n'); diff --git a/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_newcolumns.php b/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_newcolumns.php index 3604dce0..4bd08302 100644 --- a/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_newcolumns.php +++ b/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_newcolumns.php @@ -9,16 +9,16 @@ public function safeUp() { $this->createTable('{{%newcolumns}}', [ 'id' => $this->primaryKey(), - 0 => 'name varchar NOT NULL', - 1 => 'first_name varchar NULL DEFAULT NULL', + 0 => '"name" varchar NOT NULL', + 1 => '"first_name" varchar NULL DEFAULT NULL', 'last_name' => $this->text()->null()->defaultValue(null), - 2 => 'dec_col decimal(12,4) NULL DEFAULT NULL', - 3 => 'json_col json NOT NULL', - 4 => 'varchar_col varchar NULL DEFAULT NULL', - 5 => 'numeric_col double precision NULL DEFAULT NULL', - 6 => 'json_col_def_n json NOT NULL DEFAULT \'[]\'', - 7 => 'json_col_def_n_2 json NOT NULL DEFAULT \'[]\'', - 8 => 'text_col_array text[] NULL DEFAULT NULL', + 2 => '"dec_col" decimal(12,4) NULL DEFAULT NULL', + 3 => '"json_col" json NOT NULL', + 4 => '"varchar_col" varchar NULL DEFAULT NULL', + 5 => '"numeric_col" double precision NULL DEFAULT NULL', + 6 => '"json_col_def_n" json NOT NULL DEFAULT \'[]\'', + 7 => '"json_col_def_n_2" json NOT NULL DEFAULT \'[]\'', + 8 => '"text_col_array" text[] NULL DEFAULT NULL', ]); } diff --git a/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php b/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php index e4090b6d..a5ac94cd 100644 --- a/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php +++ b/tests/specs/x_db_type/edit_column/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php @@ -8,17 +8,18 @@ class m200000_000003_create_table_pristines extends \yii\db\Migration public function safeUp() { $this->createTable('{{%pristines}}', [ - 0 => 'custom_id_col serial primary key NOT NULL', - 1 => 'name text NOT NULL', + 0 => '"custom_id_col" serial primary key NOT NULL', + 1 => '"name" text NOT NULL', 'tag' => $this->text()->null()->defaultValue("4 leg"), - 2 => 'new_col varchar NULL DEFAULT NULL', - 3 => 'col_5 decimal(12,4) NULL DEFAULT NULL', - 4 => 'col_6 decimal(11,2) NULL DEFAULT NULL', - 5 => 'col_7 decimal(10,2) NULL DEFAULT NULL', - 6 => 'col_8 json NOT NULL', - 7 => 'col_9 varchar NULL DEFAULT NULL', - 8 => 'col_10 varchar NULL DEFAULT NULL', - 9 => 'col_11 text NULL DEFAULT NULL', + 2 => '"new_col" varchar NULL DEFAULT NULL', + 3 => '"col_5" decimal(12,4) NULL DEFAULT NULL', + 4 => '"col_6" decimal(11,2) NULL DEFAULT NULL', + 5 => '"col_7" decimal(10,2) NULL DEFAULT NULL', + 6 => '"col_8" json NOT NULL', + 7 => '"col_9" varchar NULL DEFAULT NULL', + 8 => '"col_10" varchar NULL DEFAULT NULL', + 9 => '"col_11" text NULL DEFAULT NULL', + 10 => '"price" decimal(10,2) NULL DEFAULT 0', ]); } diff --git a/tests/specs/x_db_type/fresh/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php b/tests/specs/x_db_type/fresh/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php index 4d1b1590..6e7ab8a7 100644 --- a/tests/specs/x_db_type/fresh/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php +++ b/tests/specs/x_db_type/fresh/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php @@ -19,6 +19,7 @@ public function up() 7 => 'col_9 varchar(9) NULL DEFAULT NULL', 8 => 'col_10 varchar(10) NULL DEFAULT NULL', 9 => 'col_11 text NULL DEFAULT NULL', + 10 => 'price decimal(10,2) NULL DEFAULT 0', ]); } diff --git a/tests/specs/x_db_type/fresh/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php b/tests/specs/x_db_type/fresh/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php index aeed5fe1..3e9e8e02 100644 --- a/tests/specs/x_db_type/fresh/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php +++ b/tests/specs/x_db_type/fresh/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php @@ -19,6 +19,7 @@ public function up() 7 => 'col_9 varchar(9) NULL DEFAULT NULL', 8 => 'col_10 varchar(10) NULL DEFAULT NULL', 9 => 'col_11 text NULL', + 10 => 'price decimal(10,2) NULL DEFAULT 0', ]); } diff --git a/tests/specs/x_db_type/fresh/mysql/x_db_type_mysql.yaml b/tests/specs/x_db_type/fresh/mysql/x_db_type_mysql.yaml index a055caad..2a706468 100644 --- a/tests/specs/x_db_type/fresh/mysql/x_db_type_mysql.yaml +++ b/tests/specs/x_db_type/fresh/mysql/x_db_type_mysql.yaml @@ -54,6 +54,11 @@ components: col_11: type: string x-db-type: TEXT + price: + description: price in EUR + type: number + x-db-type: decimal(10,2) + default: 0 Alldbdatatype: # All DB data type diff --git a/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php b/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php index 53498798..e0cac52a 100644 --- a/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php +++ b/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php @@ -9,99 +9,99 @@ public function safeUp() { $this->createTable('{{%alldbdatatypes}}', [ 'id' => $this->bigPrimaryKey(), - 0 => 'string_col varchar NULL DEFAULT NULL', - 1 => 'varchar_col varchar NULL DEFAULT NULL', - 2 => 'text_col text NULL DEFAULT NULL', - 3 => 'text_col_array text[] NULL DEFAULT NULL', - 4 => 'varchar_4_col varchar(4) NULL DEFAULT NULL', - 5 => 'varchar_5_col varchar(5) NULL DEFAULT NULL', - 6 => 'char_4_col char(4) NULL DEFAULT NULL', - 7 => 'char_5_col char NULL DEFAULT NULL', - 8 => 'char_6_col char NOT NULL', - 9 => 'char_7_col char(6) NOT NULL', - 10 => 'char_8_col char NULL DEFAULT \'d\'', - 11 => 'decimal_col decimal(12,3) NULL DEFAULT NULL', - 12 => 'bytea_col_2 bytea NULL DEFAULT NULL', - 13 => 'bit_col bit NULL DEFAULT NULL', - 14 => 'bit_2 bit(1) NULL DEFAULT NULL', - 15 => 'bit_3 bit(64) NULL DEFAULT NULL', - 16 => 'ti smallint NULL DEFAULT NULL', - 17 => 'int2_col int2 NULL DEFAULT NULL', - 18 => 'smallserial_col smallserial NOT NULL', - 19 => 'serial2_col serial2 NOT NULL', - 20 => 'si_col smallint NULL DEFAULT NULL', - 21 => 'si_col_2 smallint NULL DEFAULT NULL', - 22 => 'bi bigint NULL DEFAULT NULL', - 23 => 'bi2 int8 NULL DEFAULT NULL', - 24 => 'int4_col int4 NULL DEFAULT NULL', - 25 => 'bigserial_col bigserial NOT NULL', - 26 => 'bigserial_col_2 serial8 NOT NULL', - 27 => 'int_col int NULL DEFAULT NULL', - 28 => 'int_col_2 integer NULL DEFAULT NULL', - 29 => 'numeric_col numeric NULL DEFAULT NULL', - 30 => 'numeric_col_2 numeric(10) NULL DEFAULT NULL', - 31 => 'numeric_col_3 numeric(10,2) NULL DEFAULT NULL', - 32 => 'double_p_2 double precision NULL DEFAULT NULL', - 33 => 'double_p_3 double precision NULL DEFAULT NULL', - 34 => 'real_col real NULL DEFAULT NULL', - 35 => 'float4_col float4 NULL DEFAULT NULL', - 36 => 'date_col date NULL DEFAULT NULL', - 37 => 'time_col time NULL DEFAULT NULL', - 38 => 'time_col_2 time with time zone NULL DEFAULT NULL', - 39 => 'time_col_3 time without time zone NULL DEFAULT NULL', - 40 => 'time_col_4 time(3) without time zone NULL DEFAULT NULL', - 41 => 'timetz_col timetz NULL DEFAULT NULL', - 42 => 'timetz_col_2 timetz(3) NULL DEFAULT NULL', - 43 => 'timestamp_col timestamp NULL DEFAULT NULL', - 44 => 'timestamp_col_2 timestamp with time zone NULL DEFAULT NULL', - 45 => 'timestamp_col_3 timestamp without time zone NULL DEFAULT NULL', - 46 => 'timestamp_col_4 timestamp(3) without time zone NULL DEFAULT NULL', - 47 => 'timestamptz_col timestamptz NULL DEFAULT NULL', - 48 => 'timestamptz_col_2 timestamptz(3) NULL DEFAULT NULL', - 49 => 'date2 date NULL DEFAULT NULL', - 50 => 'timestamp_col_z timestamp NULL DEFAULT NULL', - 51 => 'bit_varying bit varying NULL DEFAULT NULL', - 52 => 'bit_varying_n bit varying(8) NULL DEFAULT NULL', - 53 => 'bit_varying_n_2 varbit NULL DEFAULT NULL', - 54 => 'bit_varying_n_3 varbit(3) NULL DEFAULT NULL', - 55 => 'bool_col boolean NULL DEFAULT NULL', - 56 => 'bool_col_2 bool NULL DEFAULT NULL', - 57 => 'box_col box NULL DEFAULT NULL', - 58 => 'character_col character NULL DEFAULT NULL', - 59 => 'character_n character(12) NULL DEFAULT NULL', - 60 => 'character_varying character varying NULL DEFAULT NULL', - 61 => 'character_varying_n character varying(12) NULL DEFAULT NULL', - 62 => 'json_col json NOT NULL', - 63 => 'jsonb_col jsonb NOT NULL', - 64 => 'json_col_def json NOT NULL DEFAULT \'[]\'', - 65 => 'json_col_def_2 json NOT NULL DEFAULT \'[]\'', - 66 => 'bytea_def bytea NULL DEFAULT \'the bytea blob default\'', - 67 => 'text_def text NULL DEFAULT \'the text\'', - 68 => 'json_def json NOT NULL DEFAULT \'{"a":"b"}\'', - 69 => 'jsonb_def jsonb NOT NULL DEFAULT \'{"ba":"bb"}\'', - 70 => 'cidr_col cidr NULL DEFAULT NULL', - 71 => 'circle_col circle NULL DEFAULT NULL', - 72 => 'date_col_z date NULL DEFAULT NULL', - 73 => 'float8_col float8 NULL DEFAULT NULL', - 74 => 'inet_col inet NULL DEFAULT NULL', - 75 => 'interval_col interval NULL DEFAULT NULL', - 76 => 'interval_col_2 interval year NULL DEFAULT NULL', - 77 => 'interval_col_3 interval day to second(3) NULL DEFAULT NULL', - 78 => 'line_col line NULL DEFAULT NULL', - 79 => 'lseg_col lseg NULL DEFAULT NULL', - 80 => 'macaddr_col macaddr NULL DEFAULT NULL', - 81 => 'money_col money NULL DEFAULT NULL', - 82 => 'path_col path NULL DEFAULT NULL', - 83 => 'pg_lsn_col pg_lsn NULL DEFAULT NULL', - 84 => 'point_col point NULL DEFAULT NULL', - 85 => 'polygon_col polygon NULL DEFAULT NULL', - 86 => 'serial_col serial NOT NULL', - 87 => 'serial4_col serial4 NOT NULL', - 88 => 'tsquery_col tsquery NULL DEFAULT NULL', - 89 => 'tsvector_col tsvector NULL', - 90 => 'txid_snapshot_col txid_snapshot NULL DEFAULT NULL', - 91 => 'uuid_col uuid NULL DEFAULT NULL', - 92 => 'xml_col xml NULL DEFAULT NULL', + 0 => '"string_col" varchar NULL DEFAULT NULL', + 1 => '"varchar_col" varchar NULL DEFAULT NULL', + 2 => '"text_col" text NULL DEFAULT NULL', + 3 => '"text_col_array" text[] NULL DEFAULT NULL', + 4 => '"varchar_4_col" varchar(4) NULL DEFAULT NULL', + 5 => '"varchar_5_col" varchar(5) NULL DEFAULT NULL', + 6 => '"char_4_col" char(4) NULL DEFAULT NULL', + 7 => '"char_5_col" char NULL DEFAULT NULL', + 8 => '"char_6_col" char NOT NULL', + 9 => '"char_7_col" char(6) NOT NULL', + 10 => '"char_8_col" char NULL DEFAULT \'d\'', + 11 => '"decimal_col" decimal(12,3) NULL DEFAULT NULL', + 12 => '"bytea_col_2" bytea NULL DEFAULT NULL', + 13 => '"bit_col" bit NULL DEFAULT NULL', + 14 => '"bit_2" bit(1) NULL DEFAULT NULL', + 15 => '"bit_3" bit(64) NULL DEFAULT NULL', + 16 => '"ti" smallint NULL DEFAULT NULL', + 17 => '"int2_col" int2 NULL DEFAULT NULL', + 18 => '"smallserial_col" smallserial NOT NULL', + 19 => '"serial2_col" serial2 NOT NULL', + 20 => '"si_col" smallint NULL DEFAULT NULL', + 21 => '"si_col_2" smallint NULL DEFAULT NULL', + 22 => '"bi" bigint NULL DEFAULT NULL', + 23 => '"bi2" int8 NULL DEFAULT NULL', + 24 => '"int4_col" int4 NULL DEFAULT NULL', + 25 => '"bigserial_col" bigserial NOT NULL', + 26 => '"bigserial_col_2" serial8 NOT NULL', + 27 => '"int_col" int NULL DEFAULT NULL', + 28 => '"int_col_2" integer NULL DEFAULT NULL', + 29 => '"numeric_col" numeric NULL DEFAULT NULL', + 30 => '"numeric_col_2" numeric(10) NULL DEFAULT NULL', + 31 => '"numeric_col_3" numeric(10,2) NULL DEFAULT NULL', + 32 => '"double_p_2" double precision NULL DEFAULT NULL', + 33 => '"double_p_3" double precision NULL DEFAULT NULL', + 34 => '"real_col" real NULL DEFAULT NULL', + 35 => '"float4_col" float4 NULL DEFAULT NULL', + 36 => '"date_col" date NULL DEFAULT NULL', + 37 => '"time_col" time NULL DEFAULT NULL', + 38 => '"time_col_2" time with time zone NULL DEFAULT NULL', + 39 => '"time_col_3" time without time zone NULL DEFAULT NULL', + 40 => '"time_col_4" time(3) without time zone NULL DEFAULT NULL', + 41 => '"timetz_col" timetz NULL DEFAULT NULL', + 42 => '"timetz_col_2" timetz(3) NULL DEFAULT NULL', + 43 => '"timestamp_col" timestamp NULL DEFAULT NULL', + 44 => '"timestamp_col_2" timestamp with time zone NULL DEFAULT NULL', + 45 => '"timestamp_col_3" timestamp without time zone NULL DEFAULT NULL', + 46 => '"timestamp_col_4" timestamp(3) without time zone NULL DEFAULT NULL', + 47 => '"timestamptz_col" timestamptz NULL DEFAULT NULL', + 48 => '"timestamptz_col_2" timestamptz(3) NULL DEFAULT NULL', + 49 => '"date2" date NULL DEFAULT NULL', + 50 => '"timestamp_col_z" timestamp NULL DEFAULT NULL', + 51 => '"bit_varying" bit varying NULL DEFAULT NULL', + 52 => '"bit_varying_n" bit varying(8) NULL DEFAULT NULL', + 53 => '"bit_varying_n_2" varbit NULL DEFAULT NULL', + 54 => '"bit_varying_n_3" varbit(3) NULL DEFAULT NULL', + 55 => '"bool_col" boolean NULL DEFAULT NULL', + 56 => '"bool_col_2" bool NULL DEFAULT NULL', + 57 => '"box_col" box NULL DEFAULT NULL', + 58 => '"character_col" character NULL DEFAULT NULL', + 59 => '"character_n" character(12) NULL DEFAULT NULL', + 60 => '"character_varying" character varying NULL DEFAULT NULL', + 61 => '"character_varying_n" character varying(12) NULL DEFAULT NULL', + 62 => '"json_col" json NOT NULL', + 63 => '"jsonb_col" jsonb NOT NULL', + 64 => '"json_col_def" json NOT NULL DEFAULT \'[]\'', + 65 => '"json_col_def_2" json NOT NULL DEFAULT \'[]\'', + 66 => '"bytea_def" bytea NULL DEFAULT \'the bytea blob default\'', + 67 => '"text_def" text NULL DEFAULT \'the text\'', + 68 => '"json_def" json NOT NULL DEFAULT \'{"a":"b"}\'', + 69 => '"jsonb_def" jsonb NOT NULL DEFAULT \'{"ba":"bb"}\'', + 70 => '"cidr_col" cidr NULL DEFAULT NULL', + 71 => '"circle_col" circle NULL DEFAULT NULL', + 72 => '"date_col_z" date NULL DEFAULT NULL', + 73 => '"float8_col" float8 NULL DEFAULT NULL', + 74 => '"inet_col" inet NULL DEFAULT NULL', + 75 => '"interval_col" interval NULL DEFAULT NULL', + 76 => '"interval_col_2" interval year NULL DEFAULT NULL', + 77 => '"interval_col_3" interval day to second(3) NULL DEFAULT NULL', + 78 => '"line_col" line NULL DEFAULT NULL', + 79 => '"lseg_col" lseg NULL DEFAULT NULL', + 80 => '"macaddr_col" macaddr NULL DEFAULT NULL', + 81 => '"money_col" money NULL DEFAULT NULL', + 82 => '"path_col" path NULL DEFAULT NULL', + 83 => '"pg_lsn_col" pg_lsn NULL DEFAULT NULL', + 84 => '"point_col" point NULL DEFAULT NULL', + 85 => '"polygon_col" polygon NULL DEFAULT NULL', + 86 => '"serial_col" serial NOT NULL', + 87 => '"serial4_col" serial4 NOT NULL', + 88 => '"tsquery_col" tsquery NULL DEFAULT NULL', + 89 => '"tsvector_col" tsvector NULL', + 90 => '"txid_snapshot_col" txid_snapshot NULL DEFAULT NULL', + 91 => '"uuid_col" uuid NULL DEFAULT NULL', + 92 => '"xml_col" xml NULL DEFAULT NULL', ]); } diff --git a/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_editcolumns.php b/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_editcolumns.php index 93111403..b8f286b1 100644 --- a/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_editcolumns.php +++ b/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_editcolumns.php @@ -9,18 +9,18 @@ public function safeUp() { $this->createTable('{{%editcolumns}}', [ 'id' => $this->primaryKey(), - 0 => 'name varchar(254) NOT NULL DEFAULT \'Horse-2\'', + 0 => '"name" varchar(254) NOT NULL DEFAULT \'Horse-2\'', 'tag' => $this->text()->null()->defaultValue(null), - 1 => 'first_name varchar NULL DEFAULT NULL', + 1 => '"first_name" varchar NULL DEFAULT NULL', 'string_col' => $this->text()->null()->defaultValue(null), - 2 => 'dec_col decimal(12,2) NULL DEFAULT 3.14', - 3 => 'str_col_def varchar NOT NULL', - 4 => 'json_col text NOT NULL DEFAULT \'fox jumps over dog\'', - 5 => 'json_col_2 json NOT NULL DEFAULT \'[]\'', - 6 => 'numeric_col double precision NULL DEFAULT NULL', - 7 => 'json_col_def_n json NOT NULL DEFAULT \'[]\'', - 8 => 'json_col_def_n_2 json NOT NULL DEFAULT \'[]\'', - 9 => 'text_col_array text[] NULL DEFAULT NULL', + 2 => '"dec_col" decimal(12,2) NULL DEFAULT 3.14', + 3 => '"str_col_def" varchar NOT NULL', + 4 => '"json_col" text NOT NULL DEFAULT \'fox jumps over dog\'', + 5 => '"json_col_2" jsonb NOT NULL DEFAULT \'[]\'', + 6 => '"numeric_col" double precision NULL DEFAULT NULL', + 7 => '"json_col_def_n" json NOT NULL DEFAULT \'[]\'', + 8 => '"json_col_def_n_2" json NOT NULL DEFAULT \'[]\'', + 9 => '"text_col_array" text[] NULL DEFAULT NULL', ]); } diff --git a/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_newcolumns.php b/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_newcolumns.php index 3604dce0..4bd08302 100644 --- a/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_newcolumns.php +++ b/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000002_create_table_newcolumns.php @@ -9,16 +9,16 @@ public function safeUp() { $this->createTable('{{%newcolumns}}', [ 'id' => $this->primaryKey(), - 0 => 'name varchar NOT NULL', - 1 => 'first_name varchar NULL DEFAULT NULL', + 0 => '"name" varchar NOT NULL', + 1 => '"first_name" varchar NULL DEFAULT NULL', 'last_name' => $this->text()->null()->defaultValue(null), - 2 => 'dec_col decimal(12,4) NULL DEFAULT NULL', - 3 => 'json_col json NOT NULL', - 4 => 'varchar_col varchar NULL DEFAULT NULL', - 5 => 'numeric_col double precision NULL DEFAULT NULL', - 6 => 'json_col_def_n json NOT NULL DEFAULT \'[]\'', - 7 => 'json_col_def_n_2 json NOT NULL DEFAULT \'[]\'', - 8 => 'text_col_array text[] NULL DEFAULT NULL', + 2 => '"dec_col" decimal(12,4) NULL DEFAULT NULL', + 3 => '"json_col" json NOT NULL', + 4 => '"varchar_col" varchar NULL DEFAULT NULL', + 5 => '"numeric_col" double precision NULL DEFAULT NULL', + 6 => '"json_col_def_n" json NOT NULL DEFAULT \'[]\'', + 7 => '"json_col_def_n_2" json NOT NULL DEFAULT \'[]\'', + 8 => '"text_col_array" text[] NULL DEFAULT NULL', ]); } diff --git a/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php b/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php index e4090b6d..a5ac94cd 100644 --- a/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php +++ b/tests/specs/x_db_type/fresh/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php @@ -8,17 +8,18 @@ class m200000_000003_create_table_pristines extends \yii\db\Migration public function safeUp() { $this->createTable('{{%pristines}}', [ - 0 => 'custom_id_col serial primary key NOT NULL', - 1 => 'name text NOT NULL', + 0 => '"custom_id_col" serial primary key NOT NULL', + 1 => '"name" text NOT NULL', 'tag' => $this->text()->null()->defaultValue("4 leg"), - 2 => 'new_col varchar NULL DEFAULT NULL', - 3 => 'col_5 decimal(12,4) NULL DEFAULT NULL', - 4 => 'col_6 decimal(11,2) NULL DEFAULT NULL', - 5 => 'col_7 decimal(10,2) NULL DEFAULT NULL', - 6 => 'col_8 json NOT NULL', - 7 => 'col_9 varchar NULL DEFAULT NULL', - 8 => 'col_10 varchar NULL DEFAULT NULL', - 9 => 'col_11 text NULL DEFAULT NULL', + 2 => '"new_col" varchar NULL DEFAULT NULL', + 3 => '"col_5" decimal(12,4) NULL DEFAULT NULL', + 4 => '"col_6" decimal(11,2) NULL DEFAULT NULL', + 5 => '"col_7" decimal(10,2) NULL DEFAULT NULL', + 6 => '"col_8" json NOT NULL', + 7 => '"col_9" varchar NULL DEFAULT NULL', + 8 => '"col_10" varchar NULL DEFAULT NULL', + 9 => '"col_11" text NULL DEFAULT NULL', + 10 => '"price" decimal(10,2) NULL DEFAULT 0', ]); } diff --git a/tests/specs/x_db_type/fresh/pgsql/x_db_type_pgsql.yaml b/tests/specs/x_db_type/fresh/pgsql/x_db_type_pgsql.yaml index b472ecc3..ff629112 100644 --- a/tests/specs/x_db_type/fresh/pgsql/x_db_type_pgsql.yaml +++ b/tests/specs/x_db_type/fresh/pgsql/x_db_type_pgsql.yaml @@ -54,6 +54,11 @@ components: col_11: type: string x-db-type: TEXT + price: + description: price in EUR + type: number + x-db-type: decimal(10,2) + default: 0 Alldbdatatype: # All DB data type @@ -505,7 +510,7 @@ components: default: fox jumps over dog json_col_2: type: string - x-db-type: json + x-db-type: jsonb nullable: false default: [] numeric_col: diff --git a/tests/specs/x_db_type/new_column/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php b/tests/specs/x_db_type/new_column/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php index 4d1b1590..6e7ab8a7 100644 --- a/tests/specs/x_db_type/new_column/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php +++ b/tests/specs/x_db_type/new_column/maria/app/migrations_maria_db/m200000_000003_create_table_pristines.php @@ -19,6 +19,7 @@ public function up() 7 => 'col_9 varchar(9) NULL DEFAULT NULL', 8 => 'col_10 varchar(10) NULL DEFAULT NULL', 9 => 'col_11 text NULL DEFAULT NULL', + 10 => 'price decimal(10,2) NULL DEFAULT 0', ]); } diff --git a/tests/specs/x_db_type/new_column/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php b/tests/specs/x_db_type/new_column/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php index aeed5fe1..3e9e8e02 100644 --- a/tests/specs/x_db_type/new_column/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php +++ b/tests/specs/x_db_type/new_column/mysql/app/migrations_mysql_db/m200000_000003_create_table_pristines.php @@ -19,6 +19,7 @@ public function up() 7 => 'col_9 varchar(9) NULL DEFAULT NULL', 8 => 'col_10 varchar(10) NULL DEFAULT NULL', 9 => 'col_11 text NULL', + 10 => 'price decimal(10,2) NULL DEFAULT 0', ]); } diff --git a/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php b/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php index 53498798..e0cac52a 100644 --- a/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php +++ b/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000000_create_table_alldbdatatypes.php @@ -9,99 +9,99 @@ public function safeUp() { $this->createTable('{{%alldbdatatypes}}', [ 'id' => $this->bigPrimaryKey(), - 0 => 'string_col varchar NULL DEFAULT NULL', - 1 => 'varchar_col varchar NULL DEFAULT NULL', - 2 => 'text_col text NULL DEFAULT NULL', - 3 => 'text_col_array text[] NULL DEFAULT NULL', - 4 => 'varchar_4_col varchar(4) NULL DEFAULT NULL', - 5 => 'varchar_5_col varchar(5) NULL DEFAULT NULL', - 6 => 'char_4_col char(4) NULL DEFAULT NULL', - 7 => 'char_5_col char NULL DEFAULT NULL', - 8 => 'char_6_col char NOT NULL', - 9 => 'char_7_col char(6) NOT NULL', - 10 => 'char_8_col char NULL DEFAULT \'d\'', - 11 => 'decimal_col decimal(12,3) NULL DEFAULT NULL', - 12 => 'bytea_col_2 bytea NULL DEFAULT NULL', - 13 => 'bit_col bit NULL DEFAULT NULL', - 14 => 'bit_2 bit(1) NULL DEFAULT NULL', - 15 => 'bit_3 bit(64) NULL DEFAULT NULL', - 16 => 'ti smallint NULL DEFAULT NULL', - 17 => 'int2_col int2 NULL DEFAULT NULL', - 18 => 'smallserial_col smallserial NOT NULL', - 19 => 'serial2_col serial2 NOT NULL', - 20 => 'si_col smallint NULL DEFAULT NULL', - 21 => 'si_col_2 smallint NULL DEFAULT NULL', - 22 => 'bi bigint NULL DEFAULT NULL', - 23 => 'bi2 int8 NULL DEFAULT NULL', - 24 => 'int4_col int4 NULL DEFAULT NULL', - 25 => 'bigserial_col bigserial NOT NULL', - 26 => 'bigserial_col_2 serial8 NOT NULL', - 27 => 'int_col int NULL DEFAULT NULL', - 28 => 'int_col_2 integer NULL DEFAULT NULL', - 29 => 'numeric_col numeric NULL DEFAULT NULL', - 30 => 'numeric_col_2 numeric(10) NULL DEFAULT NULL', - 31 => 'numeric_col_3 numeric(10,2) NULL DEFAULT NULL', - 32 => 'double_p_2 double precision NULL DEFAULT NULL', - 33 => 'double_p_3 double precision NULL DEFAULT NULL', - 34 => 'real_col real NULL DEFAULT NULL', - 35 => 'float4_col float4 NULL DEFAULT NULL', - 36 => 'date_col date NULL DEFAULT NULL', - 37 => 'time_col time NULL DEFAULT NULL', - 38 => 'time_col_2 time with time zone NULL DEFAULT NULL', - 39 => 'time_col_3 time without time zone NULL DEFAULT NULL', - 40 => 'time_col_4 time(3) without time zone NULL DEFAULT NULL', - 41 => 'timetz_col timetz NULL DEFAULT NULL', - 42 => 'timetz_col_2 timetz(3) NULL DEFAULT NULL', - 43 => 'timestamp_col timestamp NULL DEFAULT NULL', - 44 => 'timestamp_col_2 timestamp with time zone NULL DEFAULT NULL', - 45 => 'timestamp_col_3 timestamp without time zone NULL DEFAULT NULL', - 46 => 'timestamp_col_4 timestamp(3) without time zone NULL DEFAULT NULL', - 47 => 'timestamptz_col timestamptz NULL DEFAULT NULL', - 48 => 'timestamptz_col_2 timestamptz(3) NULL DEFAULT NULL', - 49 => 'date2 date NULL DEFAULT NULL', - 50 => 'timestamp_col_z timestamp NULL DEFAULT NULL', - 51 => 'bit_varying bit varying NULL DEFAULT NULL', - 52 => 'bit_varying_n bit varying(8) NULL DEFAULT NULL', - 53 => 'bit_varying_n_2 varbit NULL DEFAULT NULL', - 54 => 'bit_varying_n_3 varbit(3) NULL DEFAULT NULL', - 55 => 'bool_col boolean NULL DEFAULT NULL', - 56 => 'bool_col_2 bool NULL DEFAULT NULL', - 57 => 'box_col box NULL DEFAULT NULL', - 58 => 'character_col character NULL DEFAULT NULL', - 59 => 'character_n character(12) NULL DEFAULT NULL', - 60 => 'character_varying character varying NULL DEFAULT NULL', - 61 => 'character_varying_n character varying(12) NULL DEFAULT NULL', - 62 => 'json_col json NOT NULL', - 63 => 'jsonb_col jsonb NOT NULL', - 64 => 'json_col_def json NOT NULL DEFAULT \'[]\'', - 65 => 'json_col_def_2 json NOT NULL DEFAULT \'[]\'', - 66 => 'bytea_def bytea NULL DEFAULT \'the bytea blob default\'', - 67 => 'text_def text NULL DEFAULT \'the text\'', - 68 => 'json_def json NOT NULL DEFAULT \'{"a":"b"}\'', - 69 => 'jsonb_def jsonb NOT NULL DEFAULT \'{"ba":"bb"}\'', - 70 => 'cidr_col cidr NULL DEFAULT NULL', - 71 => 'circle_col circle NULL DEFAULT NULL', - 72 => 'date_col_z date NULL DEFAULT NULL', - 73 => 'float8_col float8 NULL DEFAULT NULL', - 74 => 'inet_col inet NULL DEFAULT NULL', - 75 => 'interval_col interval NULL DEFAULT NULL', - 76 => 'interval_col_2 interval year NULL DEFAULT NULL', - 77 => 'interval_col_3 interval day to second(3) NULL DEFAULT NULL', - 78 => 'line_col line NULL DEFAULT NULL', - 79 => 'lseg_col lseg NULL DEFAULT NULL', - 80 => 'macaddr_col macaddr NULL DEFAULT NULL', - 81 => 'money_col money NULL DEFAULT NULL', - 82 => 'path_col path NULL DEFAULT NULL', - 83 => 'pg_lsn_col pg_lsn NULL DEFAULT NULL', - 84 => 'point_col point NULL DEFAULT NULL', - 85 => 'polygon_col polygon NULL DEFAULT NULL', - 86 => 'serial_col serial NOT NULL', - 87 => 'serial4_col serial4 NOT NULL', - 88 => 'tsquery_col tsquery NULL DEFAULT NULL', - 89 => 'tsvector_col tsvector NULL', - 90 => 'txid_snapshot_col txid_snapshot NULL DEFAULT NULL', - 91 => 'uuid_col uuid NULL DEFAULT NULL', - 92 => 'xml_col xml NULL DEFAULT NULL', + 0 => '"string_col" varchar NULL DEFAULT NULL', + 1 => '"varchar_col" varchar NULL DEFAULT NULL', + 2 => '"text_col" text NULL DEFAULT NULL', + 3 => '"text_col_array" text[] NULL DEFAULT NULL', + 4 => '"varchar_4_col" varchar(4) NULL DEFAULT NULL', + 5 => '"varchar_5_col" varchar(5) NULL DEFAULT NULL', + 6 => '"char_4_col" char(4) NULL DEFAULT NULL', + 7 => '"char_5_col" char NULL DEFAULT NULL', + 8 => '"char_6_col" char NOT NULL', + 9 => '"char_7_col" char(6) NOT NULL', + 10 => '"char_8_col" char NULL DEFAULT \'d\'', + 11 => '"decimal_col" decimal(12,3) NULL DEFAULT NULL', + 12 => '"bytea_col_2" bytea NULL DEFAULT NULL', + 13 => '"bit_col" bit NULL DEFAULT NULL', + 14 => '"bit_2" bit(1) NULL DEFAULT NULL', + 15 => '"bit_3" bit(64) NULL DEFAULT NULL', + 16 => '"ti" smallint NULL DEFAULT NULL', + 17 => '"int2_col" int2 NULL DEFAULT NULL', + 18 => '"smallserial_col" smallserial NOT NULL', + 19 => '"serial2_col" serial2 NOT NULL', + 20 => '"si_col" smallint NULL DEFAULT NULL', + 21 => '"si_col_2" smallint NULL DEFAULT NULL', + 22 => '"bi" bigint NULL DEFAULT NULL', + 23 => '"bi2" int8 NULL DEFAULT NULL', + 24 => '"int4_col" int4 NULL DEFAULT NULL', + 25 => '"bigserial_col" bigserial NOT NULL', + 26 => '"bigserial_col_2" serial8 NOT NULL', + 27 => '"int_col" int NULL DEFAULT NULL', + 28 => '"int_col_2" integer NULL DEFAULT NULL', + 29 => '"numeric_col" numeric NULL DEFAULT NULL', + 30 => '"numeric_col_2" numeric(10) NULL DEFAULT NULL', + 31 => '"numeric_col_3" numeric(10,2) NULL DEFAULT NULL', + 32 => '"double_p_2" double precision NULL DEFAULT NULL', + 33 => '"double_p_3" double precision NULL DEFAULT NULL', + 34 => '"real_col" real NULL DEFAULT NULL', + 35 => '"float4_col" float4 NULL DEFAULT NULL', + 36 => '"date_col" date NULL DEFAULT NULL', + 37 => '"time_col" time NULL DEFAULT NULL', + 38 => '"time_col_2" time with time zone NULL DEFAULT NULL', + 39 => '"time_col_3" time without time zone NULL DEFAULT NULL', + 40 => '"time_col_4" time(3) without time zone NULL DEFAULT NULL', + 41 => '"timetz_col" timetz NULL DEFAULT NULL', + 42 => '"timetz_col_2" timetz(3) NULL DEFAULT NULL', + 43 => '"timestamp_col" timestamp NULL DEFAULT NULL', + 44 => '"timestamp_col_2" timestamp with time zone NULL DEFAULT NULL', + 45 => '"timestamp_col_3" timestamp without time zone NULL DEFAULT NULL', + 46 => '"timestamp_col_4" timestamp(3) without time zone NULL DEFAULT NULL', + 47 => '"timestamptz_col" timestamptz NULL DEFAULT NULL', + 48 => '"timestamptz_col_2" timestamptz(3) NULL DEFAULT NULL', + 49 => '"date2" date NULL DEFAULT NULL', + 50 => '"timestamp_col_z" timestamp NULL DEFAULT NULL', + 51 => '"bit_varying" bit varying NULL DEFAULT NULL', + 52 => '"bit_varying_n" bit varying(8) NULL DEFAULT NULL', + 53 => '"bit_varying_n_2" varbit NULL DEFAULT NULL', + 54 => '"bit_varying_n_3" varbit(3) NULL DEFAULT NULL', + 55 => '"bool_col" boolean NULL DEFAULT NULL', + 56 => '"bool_col_2" bool NULL DEFAULT NULL', + 57 => '"box_col" box NULL DEFAULT NULL', + 58 => '"character_col" character NULL DEFAULT NULL', + 59 => '"character_n" character(12) NULL DEFAULT NULL', + 60 => '"character_varying" character varying NULL DEFAULT NULL', + 61 => '"character_varying_n" character varying(12) NULL DEFAULT NULL', + 62 => '"json_col" json NOT NULL', + 63 => '"jsonb_col" jsonb NOT NULL', + 64 => '"json_col_def" json NOT NULL DEFAULT \'[]\'', + 65 => '"json_col_def_2" json NOT NULL DEFAULT \'[]\'', + 66 => '"bytea_def" bytea NULL DEFAULT \'the bytea blob default\'', + 67 => '"text_def" text NULL DEFAULT \'the text\'', + 68 => '"json_def" json NOT NULL DEFAULT \'{"a":"b"}\'', + 69 => '"jsonb_def" jsonb NOT NULL DEFAULT \'{"ba":"bb"}\'', + 70 => '"cidr_col" cidr NULL DEFAULT NULL', + 71 => '"circle_col" circle NULL DEFAULT NULL', + 72 => '"date_col_z" date NULL DEFAULT NULL', + 73 => '"float8_col" float8 NULL DEFAULT NULL', + 74 => '"inet_col" inet NULL DEFAULT NULL', + 75 => '"interval_col" interval NULL DEFAULT NULL', + 76 => '"interval_col_2" interval year NULL DEFAULT NULL', + 77 => '"interval_col_3" interval day to second(3) NULL DEFAULT NULL', + 78 => '"line_col" line NULL DEFAULT NULL', + 79 => '"lseg_col" lseg NULL DEFAULT NULL', + 80 => '"macaddr_col" macaddr NULL DEFAULT NULL', + 81 => '"money_col" money NULL DEFAULT NULL', + 82 => '"path_col" path NULL DEFAULT NULL', + 83 => '"pg_lsn_col" pg_lsn NULL DEFAULT NULL', + 84 => '"point_col" point NULL DEFAULT NULL', + 85 => '"polygon_col" polygon NULL DEFAULT NULL', + 86 => '"serial_col" serial NOT NULL', + 87 => '"serial4_col" serial4 NOT NULL', + 88 => '"tsquery_col" tsquery NULL DEFAULT NULL', + 89 => '"tsvector_col" tsvector NULL', + 90 => '"txid_snapshot_col" txid_snapshot NULL DEFAULT NULL', + 91 => '"uuid_col" uuid NULL DEFAULT NULL', + 92 => '"xml_col" xml NULL DEFAULT NULL', ]); } diff --git a/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_editcolumns.php b/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_editcolumns.php index 93111403..b8f286b1 100644 --- a/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_editcolumns.php +++ b/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000001_create_table_editcolumns.php @@ -9,18 +9,18 @@ public function safeUp() { $this->createTable('{{%editcolumns}}', [ 'id' => $this->primaryKey(), - 0 => 'name varchar(254) NOT NULL DEFAULT \'Horse-2\'', + 0 => '"name" varchar(254) NOT NULL DEFAULT \'Horse-2\'', 'tag' => $this->text()->null()->defaultValue(null), - 1 => 'first_name varchar NULL DEFAULT NULL', + 1 => '"first_name" varchar NULL DEFAULT NULL', 'string_col' => $this->text()->null()->defaultValue(null), - 2 => 'dec_col decimal(12,2) NULL DEFAULT 3.14', - 3 => 'str_col_def varchar NOT NULL', - 4 => 'json_col text NOT NULL DEFAULT \'fox jumps over dog\'', - 5 => 'json_col_2 json NOT NULL DEFAULT \'[]\'', - 6 => 'numeric_col double precision NULL DEFAULT NULL', - 7 => 'json_col_def_n json NOT NULL DEFAULT \'[]\'', - 8 => 'json_col_def_n_2 json NOT NULL DEFAULT \'[]\'', - 9 => 'text_col_array text[] NULL DEFAULT NULL', + 2 => '"dec_col" decimal(12,2) NULL DEFAULT 3.14', + 3 => '"str_col_def" varchar NOT NULL', + 4 => '"json_col" text NOT NULL DEFAULT \'fox jumps over dog\'', + 5 => '"json_col_2" jsonb NOT NULL DEFAULT \'[]\'', + 6 => '"numeric_col" double precision NULL DEFAULT NULL', + 7 => '"json_col_def_n" json NOT NULL DEFAULT \'[]\'', + 8 => '"json_col_def_n_2" json NOT NULL DEFAULT \'[]\'', + 9 => '"text_col_array" text[] NULL DEFAULT NULL', ]); } diff --git a/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000002_change_table_newcolumns.php b/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000002_change_table_newcolumns.php index 72747e62..aab2451b 100644 --- a/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000002_change_table_newcolumns.php +++ b/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000002_change_table_newcolumns.php @@ -7,15 +7,15 @@ class m200000_000002_change_table_newcolumns extends \yii\db\Migration { public function safeUp() { - $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN dec_col decimal(12,4) NULL DEFAULT NULL')->execute(); - $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN first_name varchar NULL DEFAULT NULL')->execute(); - $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN json_col json NOT NULL')->execute(); - $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN json_col_def_n json NOT NULL DEFAULT \'[]\'')->execute(); - $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN json_col_def_n_2 json NOT NULL DEFAULT \'[]\'')->execute(); + $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN "dec_col" decimal(12,4) NULL DEFAULT NULL')->execute(); + $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN "first_name" varchar NULL DEFAULT NULL')->execute(); + $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN "json_col" json NOT NULL')->execute(); + $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN "json_col_def_n" json NOT NULL DEFAULT \'[]\'')->execute(); + $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN "json_col_def_n_2" json NOT NULL DEFAULT \'[]\'')->execute(); $this->addColumn('{{%newcolumns}}', 'last_name', $this->text()->null()->defaultValue(null)); - $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN numeric_col double precision NULL DEFAULT NULL')->execute(); - $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN text_col_array text[] NULL DEFAULT NULL')->execute(); - $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN varchar_col varchar NULL DEFAULT NULL')->execute(); + $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN "numeric_col" double precision NULL DEFAULT NULL')->execute(); + $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN "text_col_array" text[] NULL DEFAULT NULL')->execute(); + $this->db->createCommand('ALTER TABLE {{%newcolumns}} ADD COLUMN "varchar_col" varchar NULL DEFAULT NULL')->execute(); } public function safeDown() diff --git a/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php b/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php index e4090b6d..a5ac94cd 100644 --- a/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php +++ b/tests/specs/x_db_type/new_column/pgsql/app/migrations_pgsql_db/m200000_000003_create_table_pristines.php @@ -8,17 +8,18 @@ class m200000_000003_create_table_pristines extends \yii\db\Migration public function safeUp() { $this->createTable('{{%pristines}}', [ - 0 => 'custom_id_col serial primary key NOT NULL', - 1 => 'name text NOT NULL', + 0 => '"custom_id_col" serial primary key NOT NULL', + 1 => '"name" text NOT NULL', 'tag' => $this->text()->null()->defaultValue("4 leg"), - 2 => 'new_col varchar NULL DEFAULT NULL', - 3 => 'col_5 decimal(12,4) NULL DEFAULT NULL', - 4 => 'col_6 decimal(11,2) NULL DEFAULT NULL', - 5 => 'col_7 decimal(10,2) NULL DEFAULT NULL', - 6 => 'col_8 json NOT NULL', - 7 => 'col_9 varchar NULL DEFAULT NULL', - 8 => 'col_10 varchar NULL DEFAULT NULL', - 9 => 'col_11 text NULL DEFAULT NULL', + 2 => '"new_col" varchar NULL DEFAULT NULL', + 3 => '"col_5" decimal(12,4) NULL DEFAULT NULL', + 4 => '"col_6" decimal(11,2) NULL DEFAULT NULL', + 5 => '"col_7" decimal(10,2) NULL DEFAULT NULL', + 6 => '"col_8" json NOT NULL', + 7 => '"col_9" varchar NULL DEFAULT NULL', + 8 => '"col_10" varchar NULL DEFAULT NULL', + 9 => '"col_11" text NULL DEFAULT NULL', + 10 => '"price" decimal(10,2) NULL DEFAULT 0', ]); } diff --git a/tests/unit/ChangeColumnNameTest.php b/tests/unit/ChangeColumnNameTest.php new file mode 100644 index 00000000..b8cdf02b --- /dev/null +++ b/tests/unit/ChangeColumnNameTest.php @@ -0,0 +1,71 @@ +deleteTables(); + $this->createTableForTest(); + $testFile = Yii::getAlias("@specs/change_column_name/mysql/change_column_name.php"); + $this->runGenerator($testFile, 'mysql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_maria_db', 'migrations_pgsql_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/change_column_name/mysql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + + // Maria DB + $this->changeDbToMariadb(); + $this->deleteTables(); + $this->createTableForTest(); + $testFile = Yii::getAlias("@specs/change_column_name/mysql/change_column_name.php"); + $this->runGenerator($testFile, 'maria'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_mysql_db', 'migrations_pgsql_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/change_column_name/maria/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + + // Pgsql + $this->changeDbToPgsql(); + $this->deleteTables(); + $this->createTableForTest(); + $testFile = Yii::getAlias("@specs/change_column_name/pgsql/change_column_name.php"); + $this->runGenerator($testFile, 'pgsql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_mysql_db', 'migrations_maria_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/change_column_name/pgsql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + } + + private function createTableForTest() + { + Yii::$app->db->createCommand()->createTable('{{%column_name_changes}}', [ + 'id' => 'pk', + 'name' => 'varchar(255) NOT NULL', + 'updated_at' => 'datetime NOT NULL', + ])->execute(); + } + + private function deleteTables() + { + Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%column_name_changes}}')->execute(); + } +} diff --git a/tests/unit/EnumTest.php b/tests/unit/EnumTest.php new file mode 100644 index 00000000..2568b7f4 --- /dev/null +++ b/tests/unit/EnumTest.php @@ -0,0 +1,276 @@ +deleteTables(); + $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + $this->runGenerator($testFile, 'mysql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_maria_db', 'migrations_pgsql_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/enum/fresh/mysql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 3); + + $this->changeDbToMariadb(); + $this->deleteTables(); + $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + $this->runGenerator($testFile, 'maria'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_mysql_db', 'migrations_pgsql_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/enum/fresh/maria/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('maria', 3); + + $this->changeDbToPgsql(); + $this->deleteTables(); + $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + $this->runGenerator($testFile, 'pgsql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_mysql_db', 'migrations_maria_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/enum/fresh/pgsql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 3); + } + + public function testAddNewColumn() // and drop enum column + { + // MySQL + $this->deleteTables(); + $this->createTableForNewEnumColumn(); + $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + $this->runGenerator($testFile, 'mysql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_maria_db', 'migrations_pgsql_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/enum/new_column/mysql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 3); + + // Mariadb + $this->changeDbToMariadb(); + $this->deleteTables(); + $this->createTableForNewEnumColumn(); + $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + $this->runGenerator($testFile, 'maria'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_mysql_db', 'migrations_pgsql_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/enum/new_column/maria/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('maria', 3); + + // Pgsql + $this->changeDbToPgsql(); + $this->deleteTables(); + $this->createTableForNewEnumColumn(); + $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + $this->runGenerator($testFile, 'pgsql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_mysql_db', 'migrations_maria_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/enum/new_column/pgsql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 3); + } + + public function testChangeToAndFromEnum() // edit enum to string and vice versa + { + $this->deleteTables(); + $this->createTableForEditEnumToString(); + $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + $this->runGenerator($testFile, 'mysql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_maria_db', 'migrations_pgsql_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/enum/change/mysql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 3); + + // Mariadb + $this->changeDbToMariadb(); + $this->deleteTables(); + $this->createTableForEditEnumToString(); + $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + $this->runGenerator($testFile, 'maria'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_mysql_db', 'migrations_pgsql_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/enum/change/maria/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('maria', 3); + + + $this->changeDbToPgsql(); + $this->deleteTables(); + $this->createTableForEditEnumToString(); + $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + $this->runGenerator($testFile, 'pgsql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_mysql_db', 'migrations_maria_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/enum/change/pgsql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 3); + } + + // TODO ENH enum change is more work than just changing the eunm values. And for PgSQL it is even more + // public function testEnumValuesChange() + // { + // $this->deleteTables(); + // $this->createTableForEnumValueChange(); + // $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + // $this->runGenerator($testFile, 'mysql'); + + + // $this->changeDbToMariadb(); + // $this->deleteTables(); + // $this->createTableForEnumValueChange(); + // $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + // $this->runGenerator($testFile, 'maria'); + + + // $this->changeDbToPgsql(); + // $this->deleteTables(); + // $this->createTableForEnumValueChange(); + // $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + // $this->runGenerator($testFile, 'pgsql'); + // } + + // public function testStringToEnum() + // { + // $this->deleteTables(); + // $this->createTableForEditEnumToString(); + // $testFile = Yii::getAlias("@specs/enum/fresh/mysql/enum.php"); + // $this->runGenerator($testFile, 'mysql'); + // } + + // public function testChangeEnumValues() + // { + // // TODO + // // add a value to list + // // fix a typo in a enum value present in existing list + // // remove a value from list + // } + + private function deleteTables() + { + if (ApiGenerator::isPostgres()) { + Yii::$app->db->createCommand('DROP TYPE IF EXISTS enum_itt_pristines_device CASCADE')->execute(); + Yii::$app->db->createCommand('DROP TYPE IF EXISTS enum_itt_editcolumns_device CASCADE')->execute(); + Yii::$app->db->createCommand('DROP TYPE IF EXISTS enum_itt_editcolumns_connection CASCADE')->execute(); + Yii::$app->db->createCommand('DROP TYPE IF EXISTS "enum_itt_editcolumns_camelCaseCol" CASCADE')->execute(); + Yii::$app->db->createCommand('DROP TYPE IF EXISTS enum_itt_newcolumns_new_column CASCADE')->execute(); + Yii::$app->db->createCommand('DROP TYPE IF EXISTS enum_itt_newcolumns_delete_col CASCADE')->execute(); + } + Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%pristines}}')->execute(); + Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%newcolumns}}')->execute(); + Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%editcolumns}}')->execute(); + Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%alldbdatatypes}}')->execute(); + Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%enumvaluechanges}}')->execute(); + } + + private function createTableForEditEnumToString() // and vice versa + { + if (ApiGenerator::isPostgres()) { + Yii::$app->db->createCommand('CREATE TYPE enum_itt_editcolumns_device AS ENUM(\'MOBILE\', \'TV\', \'COMPUTER\')')->execute(); + Yii::$app->db->createCommand()->createTable('{{%editcolumns}}', [ + 'id' => 'pk', + 'device' => 'enum_itt_editcolumns_device NOT NULL DEFAULT \'TV\'', + 'connection' => 'string', + 'camelCaseCol' => 'string', + ])->execute(); + return; + } + Yii::$app->db->createCommand()->createTable('{{%editcolumns}}', [ + 'id' => 'pk', + 'device' => 'enum("MOBILE", "TV", "COMPUTER") NOT NULL DEFAULT \'TV\'', + 'connection' => 'string', + 'camelCaseCol' => 'string', + ])->execute(); + } + + private function createTableForNewEnumColumn() + { + if (ApiGenerator::isPostgres()) { + Yii::$app->db->createCommand('CREATE TYPE enum_itt_newcolumns_delete_col AS ENUM(\'FOUR\', \'FIVE\', \'SIX\')')->execute(); + Yii::$app->db->createCommand()->createTable('{{%newcolumns}}', [ + 'id' => 'pk', + 'delete_col' => 'enum_itt_newcolumns_delete_col' + ])->execute(); + return; + } + + Yii::$app->db->createCommand()->createTable('{{%newcolumns}}', [ + 'id' => 'pk', + 'delete_col' => 'enum("FOUR", "FIVE", "SIX")' + ])->execute(); + } + + // private function createTableForEnumValueChange() + // { + // // removing a enum value is directly not supported in PgSQL + // if (ApiGenerator::isPostgres()) { + // Yii::$app->db->createCommand('CREATE TYPE enum_add_one_mood_at_last AS ENUM(\'INTEREST\', \'JOY\', \'NOSTALGIA\')')->execute(); + // Yii::$app->db->createCommand()->createTable('{{%enumvaluechanges}}', [ + // 'id' => 'pk', + // 'add_one_mood_at_last' => 'enum_add_one_mood_at_last' + // ])->execute(); + // return; + // } + + // Yii::$app->db->createCommand()->createTable('{{%enumvaluechanges}}', [ + // 'id' => 'pk', + // 'add_one_mood_at_last' => 'enum("INTEREST", "JOY", "NOSTALGIA")', + // 'remove_last_mood' => 'enum("INTEREST", "JOY", "NOSTALGIA")', + // 'add_mood_in_between' => 'enum("INTEREST", "JOY", "NOSTALGIA")', + // 'rename_last_mood' => 'enum("INTEREST", "JOY", "NOSTALGIA")', + // ])->execute(); + // } +} diff --git a/tests/unit/IdNotInRulesTest.php b/tests/unit/IdNotInRulesTest.php new file mode 100644 index 00000000..021b3ac6 --- /dev/null +++ b/tests/unit/IdNotInRulesTest.php @@ -0,0 +1,23 @@ +runGenerator($testFile); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/id_not_in_rules/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + } +} diff --git a/tests/unit/IssueFixTest.php b/tests/unit/IssueFixTest.php new file mode 100644 index 00000000..fce08548 --- /dev/null +++ b/tests/unit/IssueFixTest.php @@ -0,0 +1,130 @@ +deleteTablesForNoSyntaxError107(); + $this->createTableForNoSyntaxError107(); + $this->runGenerator($testFile, 'mysql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/no_syntax_error_107/mysql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 1); + } + + private function deleteTablesForNoSyntaxError107() + { + Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute(); + } + + private function createTableForNoSyntaxError107() + { + Yii::$app->db->createCommand()->createTable('{{%fruits}}', [ + 'id' => 'pk', + 'name' => 'varchar(255)', + ])->execute(); + } + + public function testFloatIssue() + { + // test no migrations are generaeted + $this->changeDbToPgsql(); + $this->deleteTablesForFloatIssue(); + $this->createTableForFloatIssue(); + $testFile = Yii::getAlias("@specs/issue_fix/float_issue/float_issue.php"); + $this->runGenerator($testFile, 'pgsql'); + $this->expectException(\yii\base\InvalidArgumentException::class); + FileHelper::findDirectories(Yii::getAlias('@app').'/migration'); + FileHelper::findDirectories(Yii::getAlias('@app').'/migrations'); + FileHelper::findDirectories(Yii::getAlias('@app').'/migrations_mysql_db'); + FileHelper::findDirectories(Yii::getAlias('@app').'/migrations_maria_db'); + FileHelper::findDirectories(Yii::getAlias('@app').'/migrations_pgsql_db'); + } + + private function deleteTablesForFloatIssue() + { + Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute(); + } + + private function createTableForFloatIssue() + { + Yii::$app->db->createCommand()->createTable('{{%fruits}}', [ + 'id' => 'pk', + 'vat_percent' => 'float default 0', + ])->execute(); + } + + public function testCamelCaseColumnNameIssue127() + { + $testFile = Yii::getAlias("@specs/issue_fix/camel_case_127/camel_case_127.php"); + $this->runGenerator($testFile, 'mysql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_pgsql_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/camel_case_127/mysql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 1); + + $this->changeDbToPgsql(); + $testFile = Yii::getAlias("@specs/issue_fix/camel_case_127/camel_case_127.php"); + $this->runGenerator($testFile, 'pgsql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + 'except' => ['migrations_mysql_db'] + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/camel_case_127/pgsql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 1); + } + + public function testQuoteInAlterColumn() + { + $this->changeDbToPgsql(); + $this->deleteTableForQuoteInAlterColumn(); + $this->createTableForQuoteInAlterColumn(); + $testFile = Yii::getAlias("@specs/issue_fix/quote_in_alter_table/pgsql/quote_in_alter_table.php"); + $this->runGenerator($testFile, 'pgsql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/quote_in_alter_table/pgsql/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 1); + } + + private function deleteTableForQuoteInAlterColumn() + { + Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute(); + } + + private function createTableForQuoteInAlterColumn() + { + Yii::$app->db->createCommand()->createTable('{{%fruits}}', [ + 'id' => 'pk', + // 'colourName' => 'circle', + 'colourName' => 'varchar(255)', + ])->execute(); + } +} diff --git a/tests/unit/MultiDbFreshMigrationTest.php b/tests/unit/MultiDbFreshMigrationTest.php index 0a86726b..55abcd1e 100644 --- a/tests/unit/MultiDbFreshMigrationTest.php +++ b/tests/unit/MultiDbFreshMigrationTest.php @@ -2,10 +2,15 @@ namespace tests\unit; +use cebe\yii2openapi\lib\ColumnToCode; +use cebe\yii2openapi\lib\items\DbModel; +use cebe\yii2openapi\lib\items\Attribute; use cebe\yii2openapi\generator\ApiGenerator; +use cebe\yii2openapi\lib\migrations\MysqlMigrationBuilder; use tests\DbTestCase; use Yii; use yii\db\mysql\Schema as MySqlSchema; +use yii\db\ColumnSchema; use yii\db\pgsql\Schema as PgSqlSchema; use yii\helpers\FileHelper; use function array_filter; @@ -71,7 +76,7 @@ protected function tearDown() } } - protected function runGenerator($configFile, string $dbName) + protected function runGenerator($configFile, string $dbName = 'mysql') { $config = require $configFile; $config['migrationPath'] = "@app/migrations_{$dbName}_db/"; @@ -119,4 +124,83 @@ function($file) use ($dbName) { \sort($expectedFiles); return $expectedFiles; } + + public function testPreviousColumnName() + { + $dbName = 'mysql'; + Yii::$app->set('db', Yii::$app->mysql); + $this->assertInstanceOf(MySqlSchema::class, Yii::$app->db->schema); + + $table = Yii::$app->db->getTableSchema('{{%users_after}}'); + if (!$table) { + Yii::$app->db->createCommand()->createTable('{{%users_after}}', [ + 'id' => 'pk', + 'username' => 'string', + 'email' => 'string', + ])->execute(); + } + + $dbModel = new DbModel([ + 'name' => 'User', + 'tableName' => 'users_after', + 'description' => 'The User', + 'attributes' => [ + 'id' => (new Attribute('id', ['phpType' => 'int', 'dbType' => 'pk'])) + ->setReadOnly()->setRequired()->setIsPrimary()->setFakerStub('$uniqueFaker->numberBetween(0, 1000000)'), + 'username' => (new Attribute('username', ['phpType' => 'string', 'dbType' => 'string'])) + ->setSize(200)->setRequired()->setFakerStub('substr($faker->userName, 0, 200)'), + 'email' => (new Attribute('email', ['phpType' => 'string', 'dbType' => 'string'])) + ->setSize(200)->setRequired()->setFakerStub('substr($faker->safeEmail, 0, 200)'), + ], + ]); + + $builder = new MysqlMigrationBuilder(Yii::$app->db, $dbModel); + $builder->build(); + $name = $builder->previousColumnName(new ColumnSchema(['name' => 'email'])); + $this->assertSame($name, 'username'); + } + + public function testAfterKeyword() + { + $dbName = 'mysql'; + Yii::$app->set('db', Yii::$app->mysql); + $this->assertInstanceOf(MySqlSchema::class, Yii::$app->db->schema); + + $dbSchema = Yii::$app->db->schema; + $columnSchema = new ColumnSchema([ + 'type' => 'integer', + 'dbType' => \version_compare($version, '8.0.17', '>') ? 'int unsigned' : 'int(11) unsigned', + 'phpType' => 'integer', + 'allowNull' => true, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => \version_compare($version, '8.0.17', '>') ? null : 11, + 'precision' => \version_compare($version, '8.0.17', '>') ? null : 11, + 'scale' => null, + 'defaultValue' => 1, + ]); + + $column = new ColumnToCode( + $dbSchema, $columnSchema, false, false, 'username' + ); + $columnWithoutPreviousCol = new ColumnToCode( + $dbSchema, $columnSchema, false, false + ); + + $this->assertContains('AFTER username', $column->getCode()); + $this->assertNotContains('AFTER username', $columnWithoutPreviousCol->getCode()); + + // test `after` for fluent part in function call `after()` + unset($column, $columnWithoutPreviousCol); + + $column = new ColumnToCode( + $dbSchema, $columnSchema, true, false, 'username' + ); + $columnWithoutPreviousCol = new ColumnToCode( + $dbSchema, $columnSchema, true, false + ); + + $this->assertContains("->after('username')", $column->getCode()); + $this->assertNotContains("->after('username')", $columnWithoutPreviousCol->getCode()); + } } diff --git a/tests/unit/MultiDbSecondaryMigrationTest.php b/tests/unit/MultiDbSecondaryMigrationTest.php index 5680cc75..2ae0b662 100644 --- a/tests/unit/MultiDbSecondaryMigrationTest.php +++ b/tests/unit/MultiDbSecondaryMigrationTest.php @@ -85,7 +85,7 @@ protected function tearDown() } } - protected function runGenerator($configFile, string $dbName) + protected function runGenerator($configFile, string $dbName = 'mysql') { $config = require $configFile; $config['migrationPath'] = "@app/migrations_{$dbName}_db/"; diff --git a/tests/unit/PropertySchemaTest.php b/tests/unit/PropertySchemaTest.php index 417d91fd..68b6e07d 100644 --- a/tests/unit/PropertySchemaTest.php +++ b/tests/unit/PropertySchemaTest.php @@ -26,6 +26,7 @@ public function testPkProperty() self::assertEquals(128, $prop->getMaxLength()); self::assertEquals(null, $prop->getMinLength()); self::assertEquals(true, $prop->isReadonly()); + self::assertFalse($prop->hasEnum()); } public function testSimpleProperty() diff --git a/tests/unit/ValidatorRulesBuilderTest.php b/tests/unit/ValidatorRulesBuilderTest.php index 86e4d832..dbad43b9 100644 --- a/tests/unit/ValidatorRulesBuilderTest.php +++ b/tests/unit/ValidatorRulesBuilderTest.php @@ -28,6 +28,7 @@ public function testBuild() (new Attribute('active'))->setPhpType('bool')->setDbType('boolean'), (new Attribute('category'))->asReference('Category') ->setRequired(true)->setPhpType('int')->setDbType('integer'), + (new Attribute('state'))->setPhpType('string')->setDbType('string')->setEnumValues(['active', 'draft']), (new Attribute('created_at'))->setPhpType('string')->setDbType('datetime'), (new Attribute('contact_email'))->setPhpType('string')->setDbType('string'), (new Attribute('required_with_def'))->setPhpType('string') @@ -41,6 +42,7 @@ public function testBuild() 'trim' => new ValidationRule([ 'title', 'article', + 'state', 'created_at', 'contact_email', 'required_with_def', @@ -55,6 +57,8 @@ public function testBuild() 'title_string' => new ValidationRule(['title'], 'string', ['max' => 60]), 'article_string' => new ValidationRule(['article'], 'string'), 'active_boolean' => new ValidationRule(['active'], 'boolean'), + 'state_string' => new ValidationRule(['state'], 'string'), + 'state_in' => new ValidationRule(['state'], 'in', ['range' => ['active', 'draft']]), 'created_at_datetime' => new ValidationRule(['created_at'], 'datetime'), 'contact_email_string' => new ValidationRule(['contact_email'], 'string'), 'contact_email_email' => new ValidationRule(['contact_email'], 'email'), diff --git a/tests/unit/XDbTypeTest.php b/tests/unit/XDbTypeTest.php index 223a782b..7be7198e 100644 --- a/tests/unit/XDbTypeTest.php +++ b/tests/unit/XDbTypeTest.php @@ -28,7 +28,8 @@ public function testXDbTypeFresh() $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/x_db_type/fresh/mysql/app"), [ 'recursive' => true, ]); - $this->compareFiles($actualFiles, $expectedFiles); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 4); // same yaml file is used for MySQL and MariaDB ---------------------- $this->changeDbToMariadb(); @@ -42,7 +43,8 @@ public function testXDbTypeFresh() $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/x_db_type/fresh/maria/app"), [ 'recursive' => true, ]); - $this->compareFiles($actualFiles, $expectedFiles); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('maria', 4); // PgSQL ------------------------------------------------ $this->changeDbToPgsql(); @@ -56,7 +58,8 @@ public function testXDbTypeFresh() $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/x_db_type/fresh/pgsql/app"), [ 'recursive' => true, ]); - $this->compareFiles($actualFiles, $expectedFiles); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 4); } public function testXDbTypeSecondaryWithNewColumn() // v2 @@ -73,7 +76,8 @@ public function testXDbTypeSecondaryWithNewColumn() // v2 $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/x_db_type/new_column/mysql/app"), [ 'recursive' => true, ]); - $this->compareFiles($actualFiles, $expectedFiles); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 4); // same yaml file is used for MySQL and MariaDB ---------------------- $this->changeDbToMariadb(); @@ -89,7 +93,8 @@ public function testXDbTypeSecondaryWithNewColumn() // v2 $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/x_db_type/new_column/maria/app"), [ 'recursive' => true, ]); - $this->compareFiles($actualFiles, $expectedFiles); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('maria', 4); // PgSQL ------------------------------------------------ $this->changeDbToPgsql(); @@ -105,7 +110,8 @@ public function testXDbTypeSecondaryWithNewColumn() // v2 $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/x_db_type/new_column/pgsql/app"), [ 'recursive' => true, ]); - $this->compareFiles($actualFiles, $expectedFiles); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 4); } public function testXDbTypeSecondaryWithEditColumn() // v3 @@ -122,7 +128,8 @@ public function testXDbTypeSecondaryWithEditColumn() // v3 $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/x_db_type/edit_column/mysql/app"), [ 'recursive' => true, ]); - $this->compareFiles($actualFiles, $expectedFiles); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 4); // same yaml file is used for MySQL and MariaDB ---------------------- $this->changeDbToMariadb(); @@ -138,7 +145,8 @@ public function testXDbTypeSecondaryWithEditColumn() // v3 $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/x_db_type/edit_column/maria/app"), [ 'recursive' => true, ]); - $this->compareFiles($actualFiles, $expectedFiles); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('maria', 4); // PgSQL ------------------------------------------------ $this->changeDbToPgsql(); @@ -154,22 +162,8 @@ public function testXDbTypeSecondaryWithEditColumn() // v3 $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/x_db_type/edit_column/pgsql/app"), [ 'recursive' => true, ]); - $this->compareFiles($actualFiles, $expectedFiles); - } - - protected function compareFiles(array $actual, array $expected) - { - self::assertEquals( - count($actual), - count($expected) - ); - foreach ($actual as $index => $file) { - $expectedFilePath = $expected[$index]; - self::assertFileExists($file); - self::assertFileExists($expectedFilePath); - - $this->assertFileEquals($expectedFilePath, $file, "Failed asserting that file contents of\n$file\nare equal to file contents of\n$expectedFilePath"); - } + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 4); } private function deleteTables() @@ -197,7 +191,7 @@ private function createTableForEditColumns() 'string_col' => 'string not null', 'dec_col' => 'decimal(12, 4)', 'str_col_def' => 'string default \'hi there\'', - 'json_col' => 'json', + 'json_col' => 'json', // json is jsonb in Pgsql via Yii Pgsql Schema 'json_col_2' => 'json', 'numeric_col' => 'integer', ])->execute();