diff --git a/Makefile b/Makefile index 44086f91..346574f0 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,10 @@ up: echo "Waiting for mariadb to start up..." docker-compose exec -T mysql timeout 60s sh -c "while ! (mysql -udbuser -pdbpass -h maria --execute 'SELECT 1;' > /dev/null 2>&1); do echo -n '.'; sleep 0.1 ; done; echo 'ok'" || (docker-compose ps; docker-compose logs; exit 1) + # Solution to problem https://stackoverflow.com/questions/50026939/php-mysqli-connect-authentication-method-unknown-to-the-client-caching-sha2-pa + # if updated to PHP 7.4 or more, this command is not needed (TODO) + docker-compose exec -T mysql timeout 60s sh -c "while ! (mysql --execute \"ALTER USER 'dbuser'@'%' IDENTIFIED WITH mysql_native_password BY 'dbpass';\" > /dev/null 2>&1); do echo -n '.'; sleep 0.1 ; done; echo 'ok'" || (docker-compose ps; docker-compose logs; exit 1) + cli: docker-compose exec php bash diff --git a/README.md b/README.md index e75e00f6..f6a916bb 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,35 @@ Specify table indexes default: '{}' ``` +### `x-db-default-expression` + +Ability to provide default value by database expression + +```yaml +created_at: + readOnly: true + type: string + format: datetime + x-db-type: datetime + nullable: false + x-db-default-expression: current_timestamp() +``` + +Note: If both `default` and `x-db-default-expression` are present then `default` will be considered. + +```yaml +created_at: + readOnly: true + type: string + format: datetime + x-db-type: datetime + nullable: false + x-db-default-expression: current_timestamp() # this will be ignored + default: "2011-11-11" # this will be considered +``` + +Also see: https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html + ### Many-to-Many relation definition There are two ways for define many-to-many relations: diff --git a/docker-compose.yml b/docker-compose.yml index 2582e835..7354f954 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,7 +22,7 @@ services: - maria tty: true mysql: - image: mysql:5.7 + image: mysql:8 ports: - '13306:3306' volumes: diff --git a/src/generator/default/migration.php b/src/generator/default/migration.php index 835e8b76..d6195954 100644 --- a/src/generator/default/migration.php +++ b/src/generator/default/migration.php @@ -19,13 +19,13 @@ class fileClassName ?> extends \yii\db\Migration { public function () { -upCodeString) ?> +upCodeString ?> } public function () { -downCodeString) ?> +downCodeString ?> } } diff --git a/src/lib/AttributeResolver.php b/src/lib/AttributeResolver.php index 578de586..3da776e7 100644 --- a/src/lib/AttributeResolver.php +++ b/src/lib/AttributeResolver.php @@ -7,6 +7,7 @@ namespace cebe\yii2openapi\lib; +use cebe\yii2openapi\lib\CustomSpecAttr; use cebe\yii2openapi\lib\exceptions\InvalidDefinitionException; use cebe\yii2openapi\lib\items\Attribute; use cebe\yii2openapi\lib\items\AttributeRelation; @@ -203,7 +204,8 @@ protected function resolveProperty(PropertySchema $property, bool $isRequired):v ->setDescription($property->getAttr('description', '')) ->setReadOnly($property->isReadonly()) ->setDefault($property->guessDefault()) - ->setXDbType($property->getAttr('x-db-type')) + ->setXDbType($property->getAttr(CustomSpecAttr::DB_TYPE)) + ->setXDbDefaultExpression($property->getAttr(CustomSpecAttr::DB_DEFAULT_EXPRESSION)) ->setNullable($property->getProperty()->getSerializableData()->nullable ?? null) ->setIsPrimary($property->isPrimaryKey()); if ($property->isReference()) { diff --git a/src/lib/ColumnToCode.php b/src/lib/ColumnToCode.php index b8154898..87045697 100644 --- a/src/lib/ColumnToCode.php +++ b/src/lib/ColumnToCode.php @@ -156,7 +156,12 @@ 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'], $this->fluentParts['position']]; + $parts = [ + $this->fluentParts['type'], + $this->fluentParts['nullable'], + $this->fluentParts['default'], + $this->fluentParts['position'] + ]; array_unshift($parts, '$this'); return implode('->', array_filter(array_map('trim', $parts), 'trim')); } @@ -443,8 +448,9 @@ private function resolveDefaultValue():void $this->fluentParts['default'] = "defaultValue('" . Json::encode($value->getValue()) . "')"; $this->rawParts['default'] = $this->defaultValueArray($value->getValue()); } else { - $this->fluentParts['default'] = 'defaultExpression("' . self::escapeQuotes((string)$value) . '")'; - $this->rawParts['default'] = self::escapeQuotes((string)$value); + // $value instanceof \yii\db\Expression + $this->fluentParts['default'] = 'defaultExpression("' . (string)$value . '")'; + $this->rawParts['default'] = (string)$value; } break; case 'array': @@ -454,18 +460,10 @@ private function resolveDefaultValue():void : $this->defaultValueArray($value); 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->fluentParts['default'] = $expectInteger + ? 'defaultValue(' . $value . ')' : 'defaultValue("' . self::escapeQuotes((string)$value) . '")'; + $this->rawParts['default'] = $expectInteger ? $value : self::wrapQuotes($value); + if ((ApiGenerator::isMysql() || ApiGenerator::isMariaDb()) && $this->isEnum()) { $this->rawParts['default'] = self::escapeQuotes($this->rawParts['default']); } @@ -474,6 +472,11 @@ private function resolveDefaultValue():void private function isDefaultAllowed():bool { + // default expression with parenthases is allowed + if ($this->column->defaultValue instanceof \yii\db\Expression) { + return true; + } + $type = strtolower($this->column->dbType); switch ($type) { case 'tsvector': diff --git a/src/lib/CustomSpecAttr.php b/src/lib/CustomSpecAttr.php index f53f6eb4..3c2fe7f1 100644 --- a/src/lib/CustomSpecAttr.php +++ b/src/lib/CustomSpecAttr.php @@ -22,4 +22,11 @@ class CustomSpecAttr public const FAKER = 'x-faker'; // Custom db type (MUST CONTAINS ONLY DB TYPE! (json, jsonb, uuid, varchar etc)) public const DB_TYPE = 'x-db-type'; + /** + * Provide default value by database expression + * @example `current_timestamp()` + * @see https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html + * @see https://github.com/cebe/yii2-openapi/blob/master/README.md#x-db-default-expression + */ + public const DB_DEFAULT_EXPRESSION = 'x-db-default-expression'; } diff --git a/src/lib/items/Attribute.php b/src/lib/items/Attribute.php index 0c468f22..8c9b19cb 100644 --- a/src/lib/items/Attribute.php +++ b/src/lib/items/Attribute.php @@ -146,6 +146,15 @@ public function setXDbType($xDbType):Attribute return $this; } + public function setXDbDefaultExpression($xDbDefaultExpression): Attribute + { + // first priority is given to `default` and then to `x-db-default-expression` + if ($xDbDefaultExpression !== null && $this->defaultValue === null) { + $this->defaultValue = new \yii\db\Expression('('.$xDbDefaultExpression.')'); + } + return $this; + } + public function setNullable($nullable):Attribute { $this->nullable = $nullable; diff --git a/src/lib/migrations/MigrationRecordBuilder.php b/src/lib/migrations/MigrationRecordBuilder.php index 24989c4f..a46c093f 100644 --- a/src/lib/migrations/MigrationRecordBuilder.php +++ b/src/lib/migrations/MigrationRecordBuilder.php @@ -70,7 +70,8 @@ public function createTable(string $tableAlias, array $columns):string } } - $codeColumns = str_replace([PHP_EOL, "\\\'"], [PHP_EOL . self::INDENT, "'"], VarDumper::export($codeColumns)); + $codeColumns = static::makeString($codeColumns); + return sprintf(self::ADD_TABLE, $tableAlias, $codeColumns); } @@ -290,4 +291,28 @@ public static function quote(string $columnName): string } return $columnName; } + + /** + * Convert code columns array to comlpete syntactically correct PHP code string which will be written to migration file + */ + public static function makeString(array $codeColumns): string + { + $finalStr = ''.PHP_EOL; + foreach ($codeColumns as $key => $column) { + if (is_string($key)) { + if (substr($column, 0, 5) === '$this') { + $finalStr .= VarDumper::export($key).' => '.$column.','.PHP_EOL; + } else { + $finalStr .= VarDumper::export($key).' => '.VarDumper::export($column).','.PHP_EOL; + } + } else { + $finalStr .= VarDumper::export($key).' => '.VarDumper::export($column).','.PHP_EOL; + } + } + + $codeColumns = str_replace([PHP_EOL, "\\\'"], [PHP_EOL . self::INDENT.' ', "'"], $finalStr); + $codeColumns = trim($codeColumns); + $codeColumns = '['.PHP_EOL.self::INDENT.' '.$codeColumns.PHP_EOL . self::INDENT.']'; + return $codeColumns; + } } diff --git a/tests/fixtures/blog.php b/tests/fixtures/blog.php index deffbd6d..1d373c71 100644 --- a/tests/fixtures/blog.php +++ b/tests/fixtures/blog.php @@ -26,7 +26,7 @@ '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'])) - ->setDefault('CURRENT_TIMESTAMP')->setFakerStub('$faker->dateTimeThisYear(\'now\', \'UTC\')->format(DATE_ATOM)'), + ->setDefault(new \yii\db\Expression('(CURRENT_TIMESTAMP)'))->setFakerStub('$faker->dateTimeThisYear(\'now\', \'UTC\')->format(DATE_ATOM)'), ], 'relations' => [], 'indexes' => [ diff --git a/tests/specs/blog.yaml b/tests/specs/blog.yaml index 1021b843..4da49119 100644 --- a/tests/specs/blog.yaml +++ b/tests/specs/blog.yaml @@ -77,7 +77,7 @@ components: created_at: type: string format: date-time - default: CURRENT_TIMESTAMP + x-db-default-expression: CURRENT_TIMESTAMP Users: type: array items: 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 f8cd744a..69e23f8e 100644 --- a/tests/specs/blog/migrations/m200000_000001_create_table_users.php +++ b/tests/specs/blog/migrations/m200000_000001_create_table_users.php @@ -14,7 +14,7 @@ public function up() '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"), + 'created_at' => $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)"), ]); $this->createIndex('users_username_key', '{{%users}}', 'username', true); $this->createIndex('users_email_key', '{{%users}}', 'email', true); 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 f8cd744a..69e23f8e 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 @@ -14,7 +14,7 @@ public function up() '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"), + 'created_at' => $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)"), ]); $this->createIndex('users_username_key', '{{%users}}', 'username', true); $this->createIndex('users_email_key', '{{%users}}', 'email', true); 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 f8cd744a..69e23f8e 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 @@ -14,7 +14,7 @@ public function up() '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"), + 'created_at' => $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)"), ]); $this->createIndex('users_username_key', '{{%users}}', 'username', true); $this->createIndex('users_email_key', '{{%users}}', 'email', true); 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 23fadf71..00fd8c91 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 @@ -14,7 +14,7 @@ public function safeUp() '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"), + 'created_at' => $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)"), ]); $this->createIndex('users_username_key', '{{%users}}', 'username', true); $this->createIndex('users_email_key', '{{%users}}', 'email', true); 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 5c43dabf..be309829 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 @@ -19,10 +19,10 @@ public function up() public function down() { $this->createIndex('v2_posts_slug_key', '{{%v2_posts}}', 'slug', true); - $this->alterColumn('{{%v2_posts}}', 'created_by_id', $this->integer(11)->null()->defaultValue(null)); + $this->alterColumn('{{%v2_posts}}', 'created_by_id', $this->integer()->null()->defaultValue(null)); $this->alterColumn('{{%v2_posts}}', 'active', $this->tinyInteger(1)->notNull()->defaultValue(0)); - $this->alterColumn('{{%v2_posts}}', 'category_id', $this->integer(11)->notNull()); - $this->addColumn('{{%v2_posts}}', 'uid', $this->bigInteger(20)->notNull()->first()); + $this->alterColumn('{{%v2_posts}}', 'category_id', $this->integer()->notNull()); + $this->addColumn('{{%v2_posts}}', 'uid', $this->bigInteger()->notNull()->first()); $this->dropColumn('{{%v2_posts}}', 'lang'); $this->dropColumn('{{%v2_posts}}', 'id'); } diff --git a/tests/specs/blog_v2/migrations_mysql_db/m200000_000005_change_table_v2_comments.php b/tests/specs/blog_v2/migrations_mysql_db/m200000_000005_change_table_v2_comments.php index 8ac64b7b..1b4ac400 100644 --- a/tests/specs/blog_v2/migrations_mysql_db/m200000_000005_change_table_v2_comments.php +++ b/tests/specs/blog_v2/migrations_mysql_db/m200000_000005_change_table_v2_comments.php @@ -7,8 +7,8 @@ class m200000_000005_change_table_v2_comments extends \yii\db\Migration { public function up() { - $this->dropForeignKey('fk_v2_comments_post_id_v2_posts_uid', '{{%v2_comments}}'); $this->dropForeignKey('fk_v2_comments_author_id_v2_users_id', '{{%v2_comments}}'); + $this->dropForeignKey('fk_v2_comments_post_id_v2_posts_uid', '{{%v2_comments}}'); $this->addColumn('{{%v2_comments}}', 'user_id', $this->bigInteger()->null()->defaultValue(null)->after('post_id')); $this->dropColumn('{{%v2_comments}}', 'author_id'); $this->alterColumn('{{%v2_comments}}', 'message', $this->text()->notNull()); @@ -22,12 +22,12 @@ public function down() { $this->dropForeignKey('fk_v2_comments_user_id_v2_users_id', '{{%v2_comments}}'); $this->dropForeignKey('fk_v2_comments_post_id_v2_posts_id', '{{%v2_comments}}'); - $this->alterColumn('{{%v2_comments}}', 'created_at', $this->integer(11)->notNull()); + $this->alterColumn('{{%v2_comments}}', 'created_at', $this->integer()->notNull()); $this->alterColumn('{{%v2_comments}}', 'meta_data', 'json NOT NULL'); $this->alterColumn('{{%v2_comments}}', 'message', 'json NOT NULL'); - $this->addColumn('{{%v2_comments}}', 'author_id', $this->integer(11)->notNull()); + $this->addColumn('{{%v2_comments}}', 'author_id', $this->integer()->notNull()); $this->dropColumn('{{%v2_comments}}', 'user_id'); - $this->addForeignKey('fk_v2_comments_author_id_v2_users_id', '{{%v2_comments}}', 'id', 'v2_users', 'author_id'); $this->addForeignKey('fk_v2_comments_post_id_v2_posts_uid', '{{%v2_comments}}', 'uid', 'v2_posts', 'post_id'); + $this->addForeignKey('fk_v2_comments_author_id_v2_users_id', '{{%v2_comments}}', 'id', 'v2_users', 'author_id'); } } diff --git a/tests/specs/issue_fix/create_table_in_down_code/create_table_in_down_code.php b/tests/specs/issue_fix/create_table_in_down_code/create_table_in_down_code.php new file mode 100644 index 00000000..40f6e1db --- /dev/null +++ b/tests/specs/issue_fix/create_table_in_down_code/create_table_in_down_code.php @@ -0,0 +1,13 @@ + '@specs/issue_fix/create_table_in_down_code/create_table_in_down_code.yaml', + 'generateUrls' => false, + 'generateModels' => false, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => false, +]; diff --git a/tests/specs/issue_fix/create_table_in_down_code/create_table_in_down_code.yaml b/tests/specs/issue_fix/create_table_in_down_code/create_table_in_down_code.yaml new file mode 100644 index 00000000..849ec35d --- /dev/null +++ b/tests/specs/issue_fix/create_table_in_down_code/create_table_in_down_code.yaml @@ -0,0 +1,24 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Create table in down code +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Fruit: + type: object + description: Create table in down code + properties: + id: + type: integer + colourName: + type: string + maxLength: 255 diff --git a/tests/specs/x_db_default_expression/maria/edit/app/migrations_maria_db/m200000_000000_change_table_fruits.php b/tests/specs/x_db_default_expression/maria/edit/app/migrations_maria_db/m200000_000000_change_table_fruits.php new file mode 100644 index 00000000..bafd270b --- /dev/null +++ b/tests/specs/x_db_default_expression/maria/edit/app/migrations_maria_db/m200000_000000_change_table_fruits.php @@ -0,0 +1,35 @@ +alterColumn('{{%fruits}}', 'ts', $this->datetime()->null()->defaultExpression("(CURRENT_TIMESTAMP)")); + $this->alterColumn('{{%fruits}}', 'ts2', $this->datetime()->null()->defaultValue("2011-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts3', $this->datetime()->null()->defaultValue("2022-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts4', $this->timestamp()->null()->defaultValue("2022-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts5', $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)")); + $this->alterColumn('{{%fruits}}', 'ts6', $this->timestamp()->null()->defaultValue("2000-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'd', $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + $this->alterColumn('{{%fruits}}', 'd2', $this->text()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + $this->alterColumn('{{%fruits}}', 'd3', $this->text()->null()->defaultValue("text default")); + $this->alterColumn('{{%fruits}}', 'ts7', $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + } + + public function down() + { + $this->alterColumn('{{%fruits}}', 'ts7', $this->date()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'd3', $this->text()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'd2', $this->text()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'd', $this->date()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'ts6', $this->timestamp()->notNull()->defaultValue("0000-00-00 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts5', $this->timestamp()->notNull()->defaultValue("0000-00-00 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts4', $this->timestamp()->notNull()->defaultExpression("current_timestamp()")); + $this->alterColumn('{{%fruits}}', 'ts3', $this->datetime()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'ts2', $this->datetime()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'ts', $this->datetime()->null()->defaultValue(null)); + } +} diff --git a/tests/specs/x_db_default_expression/maria/edit_expression/app/migrations_maria_db/m200000_000000_change_table_fruits.php b/tests/specs/x_db_default_expression/maria/edit_expression/app/migrations_maria_db/m200000_000000_change_table_fruits.php new file mode 100644 index 00000000..de29b6a7 --- /dev/null +++ b/tests/specs/x_db_default_expression/maria/edit_expression/app/migrations_maria_db/m200000_000000_change_table_fruits.php @@ -0,0 +1,35 @@ +alterColumn('{{%fruits}}', 'ts', $this->datetime()->null()->defaultExpression("(CURRENT_TIMESTAMP)")); + $this->alterColumn('{{%fruits}}', 'ts2', $this->datetime()->null()->defaultValue("2011-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts3', $this->datetime()->null()->defaultValue("2022-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts4', $this->timestamp()->null()->defaultValue("2022-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts5', $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)")); + $this->alterColumn('{{%fruits}}', 'ts6', $this->timestamp()->null()->defaultValue("2000-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'd', $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + $this->alterColumn('{{%fruits}}', 'd2', $this->text()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + $this->alterColumn('{{%fruits}}', 'd3', $this->text()->null()->defaultValue("text default")); + $this->alterColumn('{{%fruits}}', 'ts7', $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + } + + public function down() + { + $this->alterColumn('{{%fruits}}', 'ts7', $this->date()->null()->defaultValue("2011-11-11")); + $this->alterColumn('{{%fruits}}', 'd3', $this->text()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'd2', $this->text()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'd', $this->date()->null()->defaultValue("2011-11-11")); + $this->alterColumn('{{%fruits}}', 'ts6', $this->timestamp()->notNull()->defaultExpression("current_timestamp()")); + $this->alterColumn('{{%fruits}}', 'ts5', $this->timestamp()->notNull()->defaultValue("2011-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts4', $this->timestamp()->notNull()->defaultExpression("current_timestamp()")); + $this->alterColumn('{{%fruits}}', 'ts3', $this->datetime()->null()->defaultExpression("current_timestamp()")); + $this->alterColumn('{{%fruits}}', 'ts2', $this->datetime()->null()->defaultExpression("current_timestamp()")); + $this->alterColumn('{{%fruits}}', 'ts', $this->datetime()->null()->defaultValue("2011-11-11 00:00:00")); + } +} diff --git a/tests/specs/x_db_default_expression/maria/simple/app/migrations_maria_db/m200000_000000_create_table_fruits.php b/tests/specs/x_db_default_expression/maria/simple/app/migrations_maria_db/m200000_000000_create_table_fruits.php new file mode 100644 index 00000000..3348044e --- /dev/null +++ b/tests/specs/x_db_default_expression/maria/simple/app/migrations_maria_db/m200000_000000_create_table_fruits.php @@ -0,0 +1,28 @@ +createTable('{{%fruits}}', [ + 'ts' => $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)"), + 'ts2' => $this->timestamp()->null()->defaultValue("2011-11-11 00:00:00"), + 'ts3' => $this->timestamp()->null()->defaultValue("2022-11-11 00:00:00"), + 0 => 'ts4 timestamp NULL DEFAULT \'2022-11-11 00:00:00\'', + 1 => 'ts5 timestamp NULL DEFAULT (CURRENT_TIMESTAMP)', + 2 => 'ts6 timestamp NULL DEFAULT \'2000-11-11 00:00:00\'', + 3 => 'd date NULL DEFAULT (CURRENT_DATE + INTERVAL 1 YEAR)', + 4 => 'd2 text NULL DEFAULT (CURRENT_DATE + INTERVAL 1 YEAR)', + 5 => 'd3 text NULL DEFAULT \'text default\'', + 'ts7' => $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)"), + ]); + } + + public function down() + { + $this->dropTable('{{%fruits}}'); + } +} diff --git a/tests/specs/x_db_default_expression/mysql/edit/app/migrations_mysql_db/m200000_000000_change_table_fruits.php b/tests/specs/x_db_default_expression/mysql/edit/app/migrations_mysql_db/m200000_000000_change_table_fruits.php new file mode 100644 index 00000000..35857636 --- /dev/null +++ b/tests/specs/x_db_default_expression/mysql/edit/app/migrations_mysql_db/m200000_000000_change_table_fruits.php @@ -0,0 +1,33 @@ +alterColumn('{{%fruits}}', 'ts', $this->datetime()->null()->defaultExpression("(CURRENT_TIMESTAMP)")); + $this->alterColumn('{{%fruits}}', 'ts2', $this->datetime()->null()->defaultValue("2011-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts3', $this->datetime()->null()->defaultValue("2022-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts4', $this->timestamp()->null()->defaultValue("2022-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts5', $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)")); + $this->alterColumn('{{%fruits}}', 'ts6', $this->timestamp()->null()->defaultValue("2000-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'd', $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + $this->alterColumn('{{%fruits}}', 'd2', $this->text()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + $this->alterColumn('{{%fruits}}', 'ts7', $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + } + + public function down() + { + $this->alterColumn('{{%fruits}}', 'ts7', $this->date()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'd2', $this->text()->null()); + $this->alterColumn('{{%fruits}}', 'd', $this->date()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'ts6', $this->timestamp()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'ts5', $this->timestamp()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'ts4', $this->timestamp()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'ts3', $this->datetime()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'ts2', $this->datetime()->null()->defaultValue(null)); + $this->alterColumn('{{%fruits}}', 'ts', $this->datetime()->null()->defaultValue(null)); + } +} diff --git a/tests/specs/x_db_default_expression/mysql/edit_expression/app/migrations_mysql_db/m200000_000000_change_table_fruits.php b/tests/specs/x_db_default_expression/mysql/edit_expression/app/migrations_mysql_db/m200000_000000_change_table_fruits.php new file mode 100644 index 00000000..df83564e --- /dev/null +++ b/tests/specs/x_db_default_expression/mysql/edit_expression/app/migrations_mysql_db/m200000_000000_change_table_fruits.php @@ -0,0 +1,33 @@ +alterColumn('{{%fruits}}', 'ts', $this->datetime()->null()->defaultExpression("(CURRENT_TIMESTAMP)")); + $this->alterColumn('{{%fruits}}', 'ts2', $this->datetime()->null()->defaultValue("2011-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts3', $this->datetime()->null()->defaultValue("2022-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts4', $this->timestamp()->null()->defaultValue("2022-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts5', $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)")); + $this->alterColumn('{{%fruits}}', 'ts6', $this->timestamp()->null()->defaultValue("2000-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'd', $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + $this->alterColumn('{{%fruits}}', 'd2', $this->text()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + $this->alterColumn('{{%fruits}}', 'ts7', $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)")); + } + + public function down() + { + $this->alterColumn('{{%fruits}}', 'ts7', $this->date()->null()->defaultValue("2011-11-11")); + $this->alterColumn('{{%fruits}}', 'd2', $this->text()->null()); + $this->alterColumn('{{%fruits}}', 'd', $this->date()->null()->defaultValue("2011-11-11")); + $this->alterColumn('{{%fruits}}', 'ts6', $this->timestamp()->null()->defaultExpression("CURRENT_TIMESTAMP")); + $this->alterColumn('{{%fruits}}', 'ts5', $this->timestamp()->null()->defaultValue("2011-11-11 00:00:00")); + $this->alterColumn('{{%fruits}}', 'ts4', $this->timestamp()->null()->defaultExpression("CURRENT_TIMESTAMP")); + $this->alterColumn('{{%fruits}}', 'ts3', $this->datetime()->null()->defaultExpression("CURRENT_TIMESTAMP")); + $this->alterColumn('{{%fruits}}', 'ts2', $this->datetime()->null()->defaultExpression("CURRENT_TIMESTAMP")); + $this->alterColumn('{{%fruits}}', 'ts', $this->datetime()->null()->defaultValue("2011-11-11 00:00:00")); + } +} diff --git a/tests/specs/x_db_default_expression/mysql/simple/app/migrations_mysql_db/m200000_000000_create_table_fruits.php b/tests/specs/x_db_default_expression/mysql/simple/app/migrations_mysql_db/m200000_000000_create_table_fruits.php new file mode 100644 index 00000000..e60beee3 --- /dev/null +++ b/tests/specs/x_db_default_expression/mysql/simple/app/migrations_mysql_db/m200000_000000_create_table_fruits.php @@ -0,0 +1,28 @@ +createTable('{{%fruits}}', [ + 'ts' => $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)"), + 'ts2' => $this->timestamp()->null()->defaultValue("2011-11-11 00:00:00"), + 'ts3' => $this->timestamp()->null()->defaultValue("2022-11-11 00:00:00"), + 0 => 'ts4 timestamp NULL DEFAULT \'2022-11-11 00:00:00\'', + 1 => 'ts5 timestamp NULL DEFAULT (CURRENT_TIMESTAMP)', + 2 => 'ts6 timestamp NULL DEFAULT \'2000-11-11 00:00:00\'', + 3 => 'd date NULL DEFAULT (CURRENT_DATE + INTERVAL 1 YEAR)', + 4 => 'd2 text NULL DEFAULT (CURRENT_DATE + INTERVAL 1 YEAR)', + 5 => 'd3 text NULL', + 'ts7' => $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL 1 YEAR)"), + ]); + } + + public function down() + { + $this->dropTable('{{%fruits}}'); + } +} diff --git a/tests/specs/x_db_default_expression/mysql/x_db_default_expression_mysql.php b/tests/specs/x_db_default_expression/mysql/x_db_default_expression_mysql.php new file mode 100644 index 00000000..5fd47d1b --- /dev/null +++ b/tests/specs/x_db_default_expression/mysql/x_db_default_expression_mysql.php @@ -0,0 +1,13 @@ + '@specs/x_db_default_expression/mysql/x_db_default_expression_mysql.yaml', + 'generateUrls' => false, + 'generateModels' => false, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => false, +]; diff --git a/tests/specs/x_db_default_expression/mysql/x_db_default_expression_mysql.yaml b/tests/specs/x_db_default_expression/mysql/x_db_default_expression_mysql.yaml new file mode 100644 index 00000000..67ef4f50 --- /dev/null +++ b/tests/specs/x_db_default_expression/mysql/x_db_default_expression_mysql.yaml @@ -0,0 +1,71 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: x-db-default-expression test +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Fruit: + type: object + description: x-db-default-expression test + properties: + ts: + type: string + format: datetime + # x-db-type: timestamp + x-db-default-expression: CURRENT_TIMESTAMP + ts2: + type: string + format: datetime + default: '2011-11-11 00:00:00' + # x-db-type: timestamp + # x-db-default-expression: CURRENT_TIMESTAMP + ts3: + type: string + format: datetime + default: '2022-11-11 00:00:00' + x-db-default-expression: CURRENT_TIMESTAMP + ts4: + type: string + x-db-type: timestamp + default: '2022-11-11 00:00:00' + ts5: + type: string + x-db-type: timestamp + x-db-default-expression: CURRENT_TIMESTAMP + ts6: + type: string + x-db-type: timestamp + default: '2000-11-11 00:00:00' + x-db-default-expression: CURRENT_TIMESTAMP + d: + type: string + x-db-type: date + x-db-default-expression: CURRENT_DATE + INTERVAL 1 YEAR + d2: + type: string + x-db-type: text + x-db-default-expression: CURRENT_DATE + INTERVAL 1 YEAR + d3: + type: string + x-db-type: text + default: text default # default literal constant for 'text' is not allowed in MySQL + x-db-default-expression: CURRENT_DATE + INTERVAL 1 YEAR + ts7: + type: string + format: date + x-db-default-expression: CURRENT_DATE + INTERVAL 1 YEAR + + # https://github.com/yiisoft/yii2/issues/19747 + # ts8: + # type: string + # format: date + # x-db-default-expression: CURRENT_DATE + INTERVAL 1 YEAR diff --git a/tests/specs/x_db_default_expression/pgsql/edit/app/migrations_pgsql_db/m200000_000000_change_table_fruits.php b/tests/specs/x_db_default_expression/pgsql/edit/app/migrations_pgsql_db/m200000_000000_change_table_fruits.php new file mode 100644 index 00000000..22d85a96 --- /dev/null +++ b/tests/specs/x_db_default_expression/pgsql/edit/app/migrations_pgsql_db/m200000_000000_change_table_fruits.php @@ -0,0 +1,35 @@ +alterColumn('{{%fruits}}', 'ts', "SET DEFAULT (CURRENT_TIMESTAMP)"); + $this->alterColumn('{{%fruits}}', 'ts2', "SET DEFAULT '2011-11-11 00:00:00'"); + $this->alterColumn('{{%fruits}}', 'ts3', "SET DEFAULT '2022-11-11 00:00:00'"); + $this->alterColumn('{{%fruits}}', 'ts4', "SET DEFAULT '2022-11-11 00:00:00'"); + $this->alterColumn('{{%fruits}}', 'ts5', "SET DEFAULT (CURRENT_TIMESTAMP)"); + $this->alterColumn('{{%fruits}}', 'ts6', "SET DEFAULT '2000-11-11 00:00:00'"); + $this->alterColumn('{{%fruits}}', 'd', "SET DEFAULT (CURRENT_DATE + INTERVAL '1 YEAR')"); + $this->alterColumn('{{%fruits}}', 'd2', "SET DEFAULT (CURRENT_DATE + INTERVAL '1 YEAR')"); + $this->alterColumn('{{%fruits}}', 'd3', "SET DEFAULT 'text default'"); + $this->alterColumn('{{%fruits}}', 'ts7', "SET DEFAULT (CURRENT_DATE + INTERVAL '1 YEAR')"); + } + + public function safeDown() + { + $this->alterColumn('{{%fruits}}', 'ts', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'ts2', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'ts3', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'ts4', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'ts5', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'ts6', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'd', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'd2', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'd3', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'ts7', "DROP DEFAULT"); + } +} diff --git a/tests/specs/x_db_default_expression/pgsql/edit_expression/app/migrations_pgsql_db/m200000_000000_change_table_fruits.php b/tests/specs/x_db_default_expression/pgsql/edit_expression/app/migrations_pgsql_db/m200000_000000_change_table_fruits.php new file mode 100644 index 00000000..4372308e --- /dev/null +++ b/tests/specs/x_db_default_expression/pgsql/edit_expression/app/migrations_pgsql_db/m200000_000000_change_table_fruits.php @@ -0,0 +1,35 @@ +alterColumn('{{%fruits}}', 'ts', "SET DEFAULT (CURRENT_TIMESTAMP)"); + $this->alterColumn('{{%fruits}}', 'ts2', "SET DEFAULT '2011-11-11 00:00:00'"); + $this->alterColumn('{{%fruits}}', 'ts3', "SET DEFAULT '2022-11-11 00:00:00'"); + $this->alterColumn('{{%fruits}}', 'ts4', "SET DEFAULT '2022-11-11 00:00:00'"); + $this->alterColumn('{{%fruits}}', 'ts5', "SET DEFAULT (CURRENT_TIMESTAMP)"); + $this->alterColumn('{{%fruits}}', 'ts6', "SET DEFAULT '2000-11-11 00:00:00'"); + $this->alterColumn('{{%fruits}}', 'd', "SET DEFAULT (CURRENT_DATE + INTERVAL '1 YEAR')"); + $this->alterColumn('{{%fruits}}', 'd2', "SET DEFAULT (CURRENT_DATE + INTERVAL '1 YEAR')"); + $this->alterColumn('{{%fruits}}', 'd3', "SET DEFAULT 'text default'"); + $this->alterColumn('{{%fruits}}', 'ts7', "SET DEFAULT (CURRENT_DATE + INTERVAL '1 YEAR')"); + } + + public function safeDown() + { + $this->alterColumn('{{%fruits}}', 'ts', "SET DEFAULT '2011-11-11 00:00:00'"); + $this->alterColumn('{{%fruits}}', 'ts2', "SET DEFAULT CURRENT_TIMESTAMP"); + $this->alterColumn('{{%fruits}}', 'ts3', "SET DEFAULT CURRENT_TIMESTAMP"); + $this->alterColumn('{{%fruits}}', 'ts4', "SET DEFAULT CURRENT_TIMESTAMP"); + $this->alterColumn('{{%fruits}}', 'ts5', "SET DEFAULT '2011-11-11 00:00:00'"); + $this->alterColumn('{{%fruits}}', 'ts6', "SET DEFAULT CURRENT_TIMESTAMP"); + $this->alterColumn('{{%fruits}}', 'd', "SET DEFAULT '2011-11-11'"); + $this->alterColumn('{{%fruits}}', 'd2', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'd3', "DROP DEFAULT"); + $this->alterColumn('{{%fruits}}', 'ts7', "SET DEFAULT '2011-11-11'"); + } +} diff --git a/tests/specs/x_db_default_expression/pgsql/simple/app/migrations_pgsql_db/m200000_000000_create_table_fruits.php b/tests/specs/x_db_default_expression/pgsql/simple/app/migrations_pgsql_db/m200000_000000_create_table_fruits.php new file mode 100644 index 00000000..5b1494cf --- /dev/null +++ b/tests/specs/x_db_default_expression/pgsql/simple/app/migrations_pgsql_db/m200000_000000_create_table_fruits.php @@ -0,0 +1,28 @@ +createTable('{{%fruits}}', [ + 'ts' => $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)"), + 'ts2' => $this->timestamp()->null()->defaultValue("2011-11-11 00:00:00"), + 'ts3' => $this->timestamp()->null()->defaultValue("2022-11-11 00:00:00"), + 0 => '"ts4" timestamp NULL DEFAULT \'2022-11-11 00:00:00\'', + 1 => '"ts5" timestamp NULL DEFAULT (CURRENT_TIMESTAMP)', + 2 => '"ts6" timestamp NULL DEFAULT \'2000-11-11 00:00:00\'', + 3 => '"d" date NULL DEFAULT (CURRENT_DATE + INTERVAL \'1 YEAR\')', + 4 => '"d2" text NULL DEFAULT (CURRENT_DATE + INTERVAL \'1 YEAR\')', + 5 => '"d3" text NULL DEFAULT \'text default\'', + 'ts7' => $this->date()->null()->defaultExpression("(CURRENT_DATE + INTERVAL '1 YEAR')"), + ]); + } + + public function safeDown() + { + $this->dropTable('{{%fruits}}'); + } +} diff --git a/tests/specs/x_db_default_expression/pgsql/x_db_default_expression_pgsql.php b/tests/specs/x_db_default_expression/pgsql/x_db_default_expression_pgsql.php new file mode 100644 index 00000000..b71e5511 --- /dev/null +++ b/tests/specs/x_db_default_expression/pgsql/x_db_default_expression_pgsql.php @@ -0,0 +1,13 @@ + '@specs/x_db_default_expression/pgsql/x_db_default_expression_pgsql.yaml', + 'generateUrls' => false, + 'generateModels' => false, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => false, +]; diff --git a/tests/specs/x_db_default_expression/pgsql/x_db_default_expression_pgsql.yaml b/tests/specs/x_db_default_expression/pgsql/x_db_default_expression_pgsql.yaml new file mode 100644 index 00000000..b0a37326 --- /dev/null +++ b/tests/specs/x_db_default_expression/pgsql/x_db_default_expression_pgsql.yaml @@ -0,0 +1,71 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: x-db-default-expression test +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + Fruit: + type: object + description: x-db-default-expression test + properties: + ts: + type: string + format: datetime + # x-db-type: timestamp + x-db-default-expression: CURRENT_TIMESTAMP + ts2: + type: string + format: datetime + default: '2011-11-11 00:00:00' + # x-db-type: timestamp + # x-db-default-expression: CURRENT_TIMESTAMP + ts3: + type: string + format: datetime + default: '2022-11-11 00:00:00' + x-db-default-expression: CURRENT_TIMESTAMP + ts4: + type: string + x-db-type: timestamp + default: '2022-11-11 00:00:00' + ts5: + type: string + x-db-type: timestamp + x-db-default-expression: CURRENT_TIMESTAMP + ts6: + type: string + x-db-type: timestamp + default: '2000-11-11 00:00:00' + x-db-default-expression: CURRENT_TIMESTAMP + d: + type: string + x-db-type: date + x-db-default-expression: CURRENT_DATE + INTERVAL '1 YEAR' + d2: + type: string + x-db-type: text + x-db-default-expression: CURRENT_DATE + INTERVAL '1 YEAR' + d3: + type: string + x-db-type: text + default: text default # default literal constant for 'text' is not allowed in MySQL + x-db-default-expression: CURRENT_DATE + INTERVAL '1 YEAR' + ts7: + type: string + format: date + x-db-default-expression: CURRENT_DATE + INTERVAL '1 YEAR' + + # https://github.com/yiisoft/yii2/issues/19747 + # ts8: + # type: string + # format: date + # x-db-default-expression: CURRENT_DATE + INTERVAL 1 YEAR diff --git a/tests/specs/x_db_type/edit_column/mysql/app/migrations_mysql_db/m200000_000001_change_table_editcolumns.php b/tests/specs/x_db_type/edit_column/mysql/app/migrations_mysql_db/m200000_000001_change_table_editcolumns.php index 88b873ca..29b8129b 100644 --- a/tests/specs/x_db_type/edit_column/mysql/app/migrations_mysql_db/m200000_000001_change_table_editcolumns.php +++ b/tests/specs/x_db_type/edit_column/mysql/app/migrations_mysql_db/m200000_000001_change_table_editcolumns.php @@ -21,7 +21,7 @@ public function up() public function down() { - $this->alterColumn('{{%editcolumns}}', 'numeric_col', $this->integer(11)->null()->defaultValue(null)); + $this->alterColumn('{{%editcolumns}}', 'numeric_col', $this->integer()->null()->defaultValue(null)); $this->alterColumn('{{%editcolumns}}', 'json_col_2', 'json NULL'); $this->alterColumn('{{%editcolumns}}', 'json_col', 'json NULL'); $this->alterColumn('{{%editcolumns}}', 'str_col_def', $this->string(255)->null()->defaultValue("hi there")); diff --git a/tests/unit/IssueFixTest.php b/tests/unit/IssueFixTest.php index fce08548..c3890bb6 100644 --- a/tests/unit/IssueFixTest.php +++ b/tests/unit/IssueFixTest.php @@ -127,4 +127,39 @@ private function createTableForQuoteInAlterColumn() 'colourName' => 'varchar(255)', ])->execute(); } + + // Stub -> https://github.com/cebe/yii2-openapi/issues/132 + // public function testCreateTableInDownCode() + // { + // $testFile = Yii::getAlias("@specs/issue_fix/create_table_in_down_code/create_table_in_down_code.php"); + // $this->deleteTablesForCreateTableInDownCode(); + // $this->createTableForCreateTableInDownCode(); + // $this->runGenerator($testFile, 'mysql'); + // // $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + // // 'recursive' => true, + // // ]); + // // $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/create_table_in_down_code/mysql/app"), [ + // // 'recursive' => true, + // // ]); + // // $this->checkFiles($actualFiles, $expectedFiles); + // // $this->runActualMigrations('mysql', 1); + // } + + // private function deleteTablesForCreateTableInDownCode() + // { + // Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute(); + // Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%animals}}')->execute(); + // } + + // private function createTableForCreateTableInDownCode() + // { + // Yii::$app->db->createCommand()->createTable('{{%fruits}}', [ + // 'id' => 'pk', + // 'colourName' => 'varchar(255)', + // ])->execute(); + // Yii::$app->db->createCommand()->createTable('{{%animals}}', [ + // 'id' => 'pk', + // 'colourName' => 'varchar(255)', + // ])->execute(); + // } } diff --git a/tests/unit/MigrationsGeneratorTest.php b/tests/unit/MigrationsGeneratorTest.php index 7d14479e..440502a9 100644 --- a/tests/unit/MigrationsGeneratorTest.php +++ b/tests/unit/MigrationsGeneratorTest.php @@ -98,7 +98,11 @@ public function simpleDbModelsProvider():array $expect = new MigrationModel($dbModel, true, null, [ 'dependencies' => [], 'upCodes' => [ - "\$this->createTable('{{%dummy}}', $codes);", + '$this->createTable(\'{{%dummy}}\', [ + \'id\' => $this->primaryKey(), + \'title\' => $this->string(60)->notNull(), + \'article\' => $this->text()->null(), + ]);', "\$this->createIndex('dummy_title_index', '{{%dummy}}', 'title', false);", "\$this->createIndex('dummy_article_hash_index', '{{%dummy}}', 'article', 'hash');", "\$this->createIndex('dummy_article_key', '{{%dummy}}', 'article', true);", @@ -138,17 +142,14 @@ public function simpleDbModelsProviderForNonMysqlDb():array 'dummy_article_key' => DbIndex::make('dummy', ['article'], null, true), ] ]); - $codes = str_replace(PHP_EOL, - PHP_EOL . MigrationRecordBuilder::INDENT, - VarDumper::export([ - 'id' => '$this->primaryKey()', - 'title' => '$this->string(60)->notNull()', - 'article' => '$this->text()->null()->defaultValue("")', - ])); $expect = new MigrationModel($dbModel, true, null, [ 'dependencies' => [], 'upCodes' => [ - "\$this->createTable('{{%dummy}}', $codes);", + '$this->createTable(\'{{%dummy}}\', [ + \'id\' => $this->primaryKey(), + \'title\' => $this->string(60)->notNull(), + \'article\' => $this->text()->null()->defaultValue(""), + ]);', "\$this->createIndex('dummy_title_index', '{{%dummy}}', 'title', false);", "\$this->createIndex('dummy_article_hash_index', '{{%dummy}}', 'article', 'hash');", "\$this->createIndex('dummy_article_key', '{{%dummy}}', 'article', true);", diff --git a/tests/unit/XDbDefaultExpressionTest.php b/tests/unit/XDbDefaultExpressionTest.php new file mode 100644 index 00000000..ee07bae5 --- /dev/null +++ b/tests/unit/XDbDefaultExpressionTest.php @@ -0,0 +1,208 @@ +deleteTables(); + $testFile = Yii::getAlias("@specs/x_db_default_expression/mysql/x_db_default_expression_mysql.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/x_db_default_expression/mysql/simple/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 1); + + // see https://mariadb.com/kb/en/timestamp/#examples + // Only the first timestamp is automatically inserted and updated, other will have value default '0000-00-00 00:00:00' + $this->changeDbToMariadb(); + $this->deleteTables(); + $testFile = Yii::getAlias("@specs/x_db_default_expression/mysql/x_db_default_expression_mysql.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/x_db_default_expression/maria/simple/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('maria', 1); + + $this->changeDbToPgsql(); + $this->deleteTables(); + $testFile = Yii::getAlias("@specs/x_db_default_expression/pgsql/x_db_default_expression_pgsql.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/x_db_default_expression/pgsql/simple/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 1); + } + + private function deleteTables() + { + Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute(); + } + + public function testEdit() + { + // default DB is Mysql ------------------------------------------------ + $this->deleteTables(); + $this->createTablesForEdit(); + $testFile = Yii::getAlias("@specs/x_db_default_expression/mysql/x_db_default_expression_mysql.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/x_db_default_expression/mysql/edit/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 1); + + $this->changeDbToMariadb(); + $this->deleteTables(); + $this->createTablesForEdit(); + $testFile = Yii::getAlias("@specs/x_db_default_expression/mysql/x_db_default_expression_mysql.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/x_db_default_expression/maria/edit/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('maria', 1); + + $this->changeDbToPgsql(); + $this->deleteTables(); + $this->createTablesForEdit(); + $testFile = Yii::getAlias("@specs/x_db_default_expression/pgsql/x_db_default_expression_pgsql.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/x_db_default_expression/pgsql/edit/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 1); + } + + private function createTablesForEdit() + { + Yii::$app->db->createCommand()->createTable('{{%fruits}}', [ + 'ts' => 'datetime', + 'ts2' => 'datetime', + 'ts3' => 'datetime', + 'ts4' => 'timestamp', + 'ts5' => 'timestamp', + 'ts6' => 'timestamp', + 'd' => 'date', + 'd2' => 'text', + 'd3' => 'text', + 'ts7' => 'date', + ])->execute(); + } + + public function testEditExpression() + { + // default DB is Mysql ------------------------------------------------ + $this->deleteTables(); + $this->createTablesForEditExpression(); + $testFile = Yii::getAlias("@specs/x_db_default_expression/mysql/x_db_default_expression_mysql.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/x_db_default_expression/mysql/edit_expression/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 1); + + $this->changeDbToMariadb(); + $this->deleteTables(); + $this->createTablesForEditExpression(); + $testFile = Yii::getAlias("@specs/x_db_default_expression/mysql/x_db_default_expression_mysql.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/x_db_default_expression/maria/edit_expression/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('maria', 1); + + $this->changeDbToPgsql(); + $this->deleteTables(); + $this->createTablesForEditExpression(); + $testFile = Yii::getAlias("@specs/x_db_default_expression/pgsql/x_db_default_expression_pgsql.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/x_db_default_expression/pgsql/edit_expression/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('pgsql', 1); + } + + private function createTablesForEditExpression() + { + $mysqlColumns = [ + 'ts' => 'datetime DEFAULT \'2011-11-11 00:00:00\'', + 'ts2' => 'datetime DEFAULT CURRENT_TIMESTAMP', + 'ts3' => 'datetime DEFAULT CURRENT_TIMESTAMP', + 'ts4' => 'timestamp DEFAULT CURRENT_TIMESTAMP', + 'ts5' => 'timestamp DEFAULT \'2011-11-11 00:00:00\'', + 'ts6' => 'timestamp DEFAULT CURRENT_TIMESTAMP', + 'd' => 'date DEFAULT \'2011-11-11\'', + 'd2' => 'text', // DEFAULT "2011-11-11" + 'd3' => 'text', // DEFAULT CURRENT_DATE + INTERVAL 1 YEAR + 'ts7' => 'date DEFAULT \'2011-11-11\'', + + // https://github.com/yiisoft/yii2/issues/19747 + // 'ts8' => 'date DEFAULT (CURRENT_DATE + INTERVAL 2 YEAR)', + ]; + if (ApiGenerator::isPostgres()) { + $pgsqlColumns = $mysqlColumns; + $pgsqlColumns['ts7'] = 'date DEFAULT \'2011-11-11\''; + Yii::$app->db->createCommand()->createTable('{{%fruits}}', $pgsqlColumns)->execute(); + return; + } + + Yii::$app->db->createCommand()->createTable('{{%fruits}}', $mysqlColumns)->execute(); + } +}