diff --git a/src/Column.php b/src/Column.php index 90861113..f722420d 100644 --- a/src/Column.php +++ b/src/Column.php @@ -22,6 +22,10 @@ * * Provides a fluent interface, which means that the methods can be chained together to create a column schema with * many properties in a single line of code. + * + * @psalm-suppress DeprecatedClass + * + * @deprecated Use {@see StringColumnSchema} or other column classes instead. Will be removed in 2.0.0. */ final class Column extends AbstractColumn { diff --git a/src/Column/ColumnDefinitionBuilder.php b/src/Column/ColumnDefinitionBuilder.php index 3d859471..fcb7c4f6 100644 --- a/src/Column/ColumnDefinitionBuilder.php +++ b/src/Column/ColumnDefinitionBuilder.php @@ -8,12 +8,13 @@ use Yiisoft\Db\QueryBuilder\AbstractColumnDefinitionBuilder; use Yiisoft\Db\Schema\Column\ColumnSchemaInterface; +use function str_contains; +use function version_compare; + final class ColumnDefinitionBuilder extends AbstractColumnDefinitionBuilder { protected const AUTO_INCREMENT_KEYWORD = 'AUTO_INCREMENT'; - protected const GENERATE_UUID_EXPRESSION = "unhex(replace(uuid(),'-',''))"; - protected const TYPES_WITH_SIZE = [ 'bit', 'tinyint', @@ -102,4 +103,17 @@ protected function getDbType(ColumnSchemaInterface $column): string return $dbType; } + + protected function getDefaultUuidExpression(): string + { + $serverVersion = $this->queryBuilder->getServerInfo()->getVersion(); + + if (!str_contains($serverVersion, 'MariaDB') + && version_compare($serverVersion, '8', '<') + ) { + return ''; + } + + return "(unhex(replace(uuid(),'-','')))"; + } } diff --git a/src/Column/ColumnFactory.php b/src/Column/ColumnFactory.php index 455a6a55..bd36e60a 100644 --- a/src/Column/ColumnFactory.php +++ b/src/Column/ColumnFactory.php @@ -90,7 +90,10 @@ protected function normalizeNotNullDefaultValue(string $defaultValue, ColumnSche return new Expression('CURRENT_TIMESTAMP' . (!empty($matches[1]) ? '(' . $matches[1] . ')' : '')); } - if (!empty($column->getExtra())) { + if (!empty($column->getExtra()) + || $defaultValue[0] === '(' + && !in_array($column->getType(), [ColumnType::CHAR, ColumnType::STRING, ColumnType::TEXT, ColumnType::BINARY], true) + ) { return new Expression($defaultValue); } diff --git a/src/Schema.php b/src/Schema.php index ee89ac59..f0c4eba1 100644 --- a/src/Schema.php +++ b/src/Schema.php @@ -76,6 +76,7 @@ final class Schema extends AbstractPdoSchema /** @deprecated Use {@see ColumnBuilder} instead. Will be removed in 2.0. */ public function createColumn(string $type, array|int|string $length = null): ColumnInterface { + /** @psalm-suppress DeprecatedClass */ return new Column($type, $length); } diff --git a/tests/ColumnSchemaBuilderTest.php b/tests/ColumnSchemaBuilderTest.php index 2d86c5d4..490b613a 100644 --- a/tests/ColumnSchemaBuilderTest.php +++ b/tests/ColumnSchemaBuilderTest.php @@ -23,12 +23,4 @@ public function testCustomTypes(string $expected, string $type, int|null $length { $this->checkBuildString($expected, $type, $length, $calls); } - - /** - * @dataProvider \Yiisoft\Db\Mysql\Tests\Provider\ColumnSchemaBuilderProvider::createColumnTypes - */ - public function testCreateColumnTypes(string $expected, string $type, ?int $length, array $calls): void - { - parent::testCreateColumnTypes($expected, $type, $length, $calls); - } } diff --git a/tests/ColumnSchemaTest.php b/tests/ColumnSchemaTest.php index 1f026d0e..3abbf128 100644 --- a/tests/ColumnSchemaTest.php +++ b/tests/ColumnSchemaTest.php @@ -6,6 +6,7 @@ use Throwable; use Yiisoft\Db\Exception\Exception; +use Yiisoft\Db\Mysql\Column\ColumnBuilder; use Yiisoft\Db\Mysql\Tests\Support\TestTrait; use Yiisoft\Db\Query\Query; use Yiisoft\Db\Schema\Column\BinaryColumnSchema; @@ -98,7 +99,7 @@ public function testPhpTypeCast(): void $db->close(); } - public function testColumnSchemaInstance() + public function testColumnSchemaInstance(): void { $db = $this->getConnection(true); $schema = $db->getSchema(); @@ -111,4 +112,32 @@ public function testColumnSchemaInstance() $this->assertInstanceOf(BooleanColumnSchema::class, $tableSchema->getColumn('bool_col')); $this->assertInstanceOf(JsonColumnSchema::class, $tableSchema->getColumn('json_col')); } + + public function testLongtextType(): void + { + $db = $this->getConnection(); + $command = $db->createCommand(); + + try { + $command->dropTable('text_type')->execute(); + } catch (Exception) { + } + + $command->createTable( + 'text_type', + [ + 'tinytext' => ColumnBuilder::text(1), + 'text' => ColumnBuilder::text(1_000), + 'mediumtext' => ColumnBuilder::text(1_000_000), + 'longtext' => ColumnBuilder::text(1_000_000_000), + ] + )->execute(); + + $table = $db->getSchema()->getTableSchema('text_type'); + + $this->assertSame('tinytext', $table->getColumn('tinytext')->getDbType()); + $this->assertSame('text', $table->getColumn('text')->getDbType()); + $this->assertSame('mediumtext', $table->getColumn('mediumtext')->getDbType()); + $this->assertSame('longtext', $table->getColumn('longtext')->getDbType()); + } } diff --git a/tests/Provider/ColumnFactoryProvider.php b/tests/Provider/ColumnFactoryProvider.php index 597644fc..17fd9439 100644 --- a/tests/Provider/ColumnFactoryProvider.php +++ b/tests/Provider/ColumnFactoryProvider.php @@ -76,6 +76,7 @@ public static function defaultValueRaw(): array [ColumnType::STRING, "'str''ing'", "str'ing"], [ColumnType::TIMESTAMP, 'CURRENT_TIMESTAMP', new Expression('CURRENT_TIMESTAMP')], [ColumnType::TIMESTAMP, 'current_timestamp(3)', new Expression('CURRENT_TIMESTAMP(3)')], + [ColumnType::INTEGER, '(1 + 2)', new Expression('(1 + 2)')], ]; } } diff --git a/tests/Provider/ColumnSchemaBuilderProvider.php b/tests/Provider/ColumnSchemaBuilderProvider.php index c85e3469..a6771a31 100644 --- a/tests/Provider/ColumnSchemaBuilderProvider.php +++ b/tests/Provider/ColumnSchemaBuilderProvider.php @@ -36,24 +36,4 @@ public static function types(): array ], ]; } - - public static function createColumnTypes(): array - { - $types = parent::createColumnTypes(); - $types['integer'][0] = '`column` int(11)'; - - $types['uuid'][0] = '`column` binary(16)'; - $types['uuid not null'][0] = '`column` binary(16) NOT NULL'; - - $types['uuid with default'][0] = '`column` binary(16) DEFAULT (UUID_TO_BIN(\'875343b3-6bd0-4bec-81bb-aa68bb52d945\'))'; - $types['uuid with default'][3] = [['defaultExpression', '(UUID_TO_BIN(\'875343b3-6bd0-4bec-81bb-aa68bb52d945\'))']]; - - $types['uuid pk'][0] = '`column` binary(16) PRIMARY KEY'; - $types['uuid pk not null'][0] = '`column` binary(16) PRIMARY KEY NOT NULL'; - - $types['uuid pk not null with default'][0] = '`column` binary(16) PRIMARY KEY NOT NULL DEFAULT (UUID_TO_BIN(UUID()))'; - $types['uuid pk not null with default'][3] = [['notNull'], ['defaultExpression', '(UUID_TO_BIN(UUID()))']]; - - return $types; - } } diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index bfd8516a..987e24fc 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -4,6 +4,7 @@ namespace Yiisoft\Db\Mysql\Tests\Provider; +use Yiisoft\Db\Constant\ColumnType; use Yiisoft\Db\Constant\PseudoType; use Yiisoft\Db\Expression\Expression; use Yiisoft\Db\Expression\JsonExpression; @@ -19,6 +20,13 @@ final class QueryBuilderProvider extends \Yiisoft\Db\Tests\Provider\QueryBuilder protected static string $driverName = 'mysql'; + public static function alterColumn(): array + { + return [ + [ColumnType::STRING, 'ALTER TABLE `foo1` CHANGE `bar` `bar` varchar(255)'], + ]; + } + public static function buildCondition(): array { return [ @@ -185,13 +193,13 @@ public static function buildColumnDefinition(): array $values[PseudoType::UPK][0] = 'int UNSIGNED PRIMARY KEY AUTO_INCREMENT'; $values[PseudoType::BIGPK][0] = 'bigint PRIMARY KEY AUTO_INCREMENT'; $values[PseudoType::UBIGPK][0] = 'bigint UNSIGNED PRIMARY KEY AUTO_INCREMENT'; - $values[PseudoType::UUID_PK][0] = "binary(16) PRIMARY KEY DEFAULT unhex(replace(uuid(),'-',''))"; - $values[PseudoType::UUID_PK_SEQ][0] = "binary(16) PRIMARY KEY DEFAULT unhex(replace(uuid(),'-',''))"; + $values[PseudoType::UUID_PK][0] = "binary(16) PRIMARY KEY DEFAULT (unhex(replace(uuid(),'-','')))"; + $values[PseudoType::UUID_PK_SEQ][0] = "binary(16) PRIMARY KEY DEFAULT (unhex(replace(uuid(),'-','')))"; $values['primaryKey()'][0] = 'int PRIMARY KEY AUTO_INCREMENT'; $values['primaryKey(false)'][0] = 'int PRIMARY KEY'; $values['smallPrimaryKey()'][0] = 'smallint PRIMARY KEY AUTO_INCREMENT'; $values['bigPrimaryKey()'][0] = 'bigint PRIMARY KEY AUTO_INCREMENT'; - $values['uuidPrimaryKey()'][0] = "binary(16) PRIMARY KEY DEFAULT unhex(replace(uuid(),'-',''))"; + $values['uuidPrimaryKey()'][0] = "binary(16) PRIMARY KEY DEFAULT (unhex(replace(uuid(),'-','')))"; $values['uuidPrimaryKey(false)'][0] = 'binary(16) PRIMARY KEY'; $values['boolean()'][0] = 'bit(1)'; $values['boolean(100)'][0] = 'bit(1)'; @@ -221,6 +229,21 @@ public static function buildColumnDefinition(): array $values[] = ["enum('a','b','c')", ColumnBuilder::string()->dbType("enum('a','b','c')")]; + $db = self::getDb(); + $serverVersion = $db->getServerInfo()->getVersion(); + $db->close(); + + if (!str_contains($serverVersion, 'MariaDB') + && version_compare($serverVersion, '8', '<') + ) { + $values[PseudoType::UUID_PK][0] = 'binary(16) PRIMARY KEY'; + $values[PseudoType::UUID_PK_SEQ][0] = 'binary(16) PRIMARY KEY'; + $values['uuidPrimaryKey()'][0] = 'binary(16) PRIMARY KEY'; + $values['defaultValue($expression)'] = ['int DEFAULT 3', ColumnBuilder::integer()->defaultValue(3)]; + $values['timestamp(6)'] = ['timestamp(6) DEFAULT CURRENT_TIMESTAMP(6)', ColumnBuilder::timestamp(6)->defaultValue(new Expression('CURRENT_TIMESTAMP(6)'))]; + $values['timestamp(null)'] = ['timestamp DEFAULT CURRENT_TIMESTAMP', ColumnBuilder::timestamp(null)->defaultValue(new Expression('CURRENT_TIMESTAMP'))]; + } + return $values; } } diff --git a/tests/QueryBuilderJsonTest.php b/tests/QueryBuilderJsonTest.php index 93ac2cd4..d15e58e7 100644 --- a/tests/QueryBuilderJsonTest.php +++ b/tests/QueryBuilderJsonTest.php @@ -5,9 +5,8 @@ namespace Yiisoft\Db\Mysql\Tests; use PHPUnit\Framework\TestCase; -use Yiisoft\Db\Constant\ColumnType; use Yiisoft\Db\Expression\JsonExpression; -use Yiisoft\Db\Mysql\Column; +use Yiisoft\Db\Mysql\Column\ColumnBuilder; use Yiisoft\Db\Mysql\Tests\Support\TestTrait; /** @@ -22,8 +21,8 @@ final class QueryBuilderJsonTest extends TestCase public function testAlterColumn() { $qb = $this->getConnection()->getQueryBuilder(); - $columnSchemaBuilder = new Column(ColumnType::JSON); - $sql = $qb->alterColumn('storage', 'id', $columnSchemaBuilder); + $column = ColumnBuilder::json(); + $sql = $qb->alterColumn('storage', 'id', $column); $this->assertStringEndsWith( <<getConnection()->getQueryBuilder(); - $columnSchemaBuilder = new Column(ColumnType::JSON); - $sql = $qb->addColumn('storage', 'abc', $columnSchemaBuilder->asString()); + $column = ColumnBuilder::json(); + $sql = $qb->addColumn('storage', 'abc', $column); $this->assertSame( <<getConnection()->getQueryBuilder(); - $columnSchemaBuilder = new Column(ColumnType::JSON); - $sql = $qb->createTable('storage', ['abc' => $columnSchemaBuilder]); + $column = ColumnBuilder::json(); + $sql = $qb->createTable('storage', ['abc' => $column]); $this->assertSame( <<getConnection(true); - $qb = $db->getQueryBuilder(); $this->assertSame( @@ -80,10 +78,8 @@ public function testInsertAndSelect() public function testInsertJsonExpresionAndSelect() { $db = $this->getConnection(true); - $qb = $db->getQueryBuilder(); - $this->assertSame( <<getConnection(); @@ -138,6 +145,12 @@ public function testAddUnique(string $name, string $table, array|string $columns parent::testAddUnique($name, $table, $columns, $expected); } + #[DataProviderExternal(QueryBuilderProvider::class, 'alterColumn')] + public function testAlterColumn(string|ColumnSchemaInterface $type, string $expected): void + { + parent::testAlterColumn($type, $expected); + } + /** * @dataProvider \Yiisoft\Db\Mysql\Tests\Provider\QueryBuilderProvider::batchInsert * @@ -266,11 +279,11 @@ public function testCreateTable(): void $this->assertSame( <<createTable( diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index 0799626f..33215c3e 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -7,15 +7,13 @@ use Throwable; use Yiisoft\Db\Command\CommandInterface; use Yiisoft\Db\Connection\ConnectionInterface; -use Yiisoft\Db\Constant\ColumnType; -use Yiisoft\Db\Constant\PseudoType; use Yiisoft\Db\Constraint\Constraint; use Yiisoft\Db\Driver\Pdo\PdoConnectionInterface; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; use Yiisoft\Db\Expression\Expression; -use Yiisoft\Db\Mysql\Column; +use Yiisoft\Db\Mysql\Column\ColumnBuilder; use Yiisoft\Db\Mysql\Column\ColumnFactory; use Yiisoft\Db\Mysql\Schema; use Yiisoft\Db\Mysql\Tests\Support\TestTrait; @@ -104,19 +102,19 @@ public function testDefaultValueDatetimeColumn(): void ); $columnsData = [ - 'id' => ['int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY', '', false], - 'd' => ['date DEFAULT \'2011-11-11\'', '2011-11-11', false], - 'dt' => ['datetime NOT NULL DEFAULT CURRENT_TIMESTAMP', 'CURRENT_TIMESTAMP', true], - 'dt1' => ['datetime DEFAULT \'2011-11-11 00:00:00\'', '2011-11-11 00:00:00', false], - 'dt2' => ['datetime DEFAULT CURRENT_TIMESTAMP', 'CURRENT_TIMESTAMP', true], - 'ts' => ['timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP', 'CURRENT_TIMESTAMP', true], - 'ts1' => ['timestamp DEFAULT \'2011-11-11 00:00:00\'', '2011-11-11 00:00:00', false], - 'ts2' => ['timestamp DEFAULT CURRENT_TIMESTAMP', 'CURRENT_TIMESTAMP', true], - 'simple_col' => ['varchar(40) DEFAULT \'uuid()\'', 'uuid()', false], + 'id' => ['int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY', ''], + 'd' => ['date DEFAULT \'2011-11-11\'', '2011-11-11'], + 'dt' => ['datetime NOT NULL DEFAULT CURRENT_TIMESTAMP', new Expression('CURRENT_TIMESTAMP')], + 'dt1' => ['datetime DEFAULT \'2011-11-11 00:00:00\'', '2011-11-11 00:00:00'], + 'dt2' => ['datetime DEFAULT CURRENT_TIMESTAMP', new Expression('CURRENT_TIMESTAMP')], + 'ts' => ['timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP', new Expression('CURRENT_TIMESTAMP')], + 'ts1' => ['timestamp DEFAULT \'2011-11-11 00:00:00\'', '2011-11-11 00:00:00'], + 'ts2' => ['timestamp DEFAULT CURRENT_TIMESTAMP', new Expression('CURRENT_TIMESTAMP')], + 'simple_col' => ['varchar(40) DEFAULT \'uuid()\'', 'uuid()'], ]; if (!$oldMySQL) { - $columnsData['ts4'] = ['date DEFAULT (CURRENT_DATE + INTERVAL 2 YEAR)', '(curdate() + interval 2 year)', true]; - $columnsData['uuid_col'] = ['varchar(40) DEFAULT (uuid())', 'uuid()', true]; + $columnsData['ts4'] = ['date DEFAULT (CURRENT_DATE + INTERVAL 2 YEAR)', new Expression('(curdate() + interval 2 year)')]; + $columnsData['uuid_col'] = ['varchar(40) DEFAULT (uuid())', new Expression('(uuid())')]; } $columns = []; @@ -135,12 +133,7 @@ public function testDefaultValueDatetimeColumn(): void foreach ($tableSchema->getColumns() as $column) { $columnName = $column->getName(); - if ($columnsData[$columnName][2]) { - $this->assertInstanceOf(Expression::class, $column->getDefaultValue()); - } else { - $this->assertNotInstanceOf(Expression::class, $column->getDefaultValue()); - } - $this->assertEquals($columnsData[$columnName][1], (string) $column->getDefaultValue()); + $this->assertEquals($columnsData[$columnName][1], $column->getDefaultValue()); } } @@ -438,9 +431,9 @@ public function testTinyInt1() $db->createCommand()->createTable( $tableName, [ - 'id' => new Column(PseudoType::PK), - 'bool_col' => new Column(ColumnType::BOOLEAN), - 'status' => new Column(ColumnType::TINYINT, 1), + 'id' => ColumnBuilder::primaryKey(), + 'bool_col' => ColumnBuilder::boolean(), + 'status' => ColumnBuilder::tinyint(), ] )->execute();