Skip to content

Commit

Permalink
Use new column definition builder (#367)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov authored Dec 23, 2024
1 parent 1b9dc80 commit 0b031ba
Show file tree
Hide file tree
Showing 13 changed files with 93 additions and 72 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- Enh #363: Refactor `Schema::normalizeDefaultValue()` method and move it to `ColumnFactory` class (@Tigrov)
- Enh #366: Refactor `Quoter::quoteValue()` method (@Tigrov)
- Chg #368: Update `QueryBuilder` constructor (@Tigrov)
- Enh #367: Use `ColumnDefinitionBuilder` to generate table column SQL representation (@Tigrov)

## 1.2.0 March 21, 2024

Expand Down
4 changes: 4 additions & 0 deletions src/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
18 changes: 16 additions & 2 deletions src/Column/ColumnDefinitionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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(),'-','')))";
}
}
5 changes: 4 additions & 1 deletion src/Column/ColumnFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
1 change: 1 addition & 0 deletions src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
8 changes: 0 additions & 8 deletions tests/ColumnSchemaBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
2 changes: 1 addition & 1 deletion tests/ColumnSchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public function testPhpTypeCast(): void
$db->close();
}

public function testColumnSchemaInstance()
public function testColumnSchemaInstance(): void
{
$db = $this->getConnection(true);
$schema = $db->getSchema();
Expand Down
1 change: 1 addition & 0 deletions tests/Provider/ColumnFactoryProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)')],
];
}
}
20 changes: 0 additions & 20 deletions tests/Provider/ColumnSchemaBuilderProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
29 changes: 26 additions & 3 deletions tests/Provider/QueryBuilderProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 [
Expand Down Expand Up @@ -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)';
Expand Down Expand Up @@ -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;
}
}
18 changes: 7 additions & 11 deletions tests/QueryBuilderJsonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -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(
<<<SQL
Expand All @@ -36,8 +35,8 @@ public function testAlterColumn()
public function testAddColumn()
{
$qb = $this->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(
<<<SQL
Expand All @@ -50,8 +49,8 @@ public function testAddColumn()
public function testCreateTable()
{
$qb = $this->getConnection()->getQueryBuilder();
$columnSchemaBuilder = new Column(ColumnType::JSON);
$sql = $qb->createTable('storage', ['abc' => $columnSchemaBuilder]);
$column = ColumnBuilder::json();
$sql = $qb->createTable('storage', ['abc' => $column]);

$this->assertSame(
<<<SQL
Expand All @@ -66,7 +65,6 @@ public function testCreateTable()
public function testInsertAndSelect()
{
$db = $this->getConnection(true);

$qb = $db->getQueryBuilder();

$this->assertSame(
Expand All @@ -80,10 +78,8 @@ public function testInsertAndSelect()
public function testInsertJsonExpresionAndSelect()
{
$db = $this->getConnection(true);

$qb = $db->getQueryBuilder();


$this->assertSame(
<<<SQL
INSERT INTO `storage` (`data`) VALUES (:qp0)
Expand Down
19 changes: 16 additions & 3 deletions tests/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

namespace Yiisoft\Db\Mysql\Tests;

use PHPUnit\Framework\Attributes\DataProviderExternal;
use Throwable;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidArgumentException;
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Expression\Expression;
use Yiisoft\Db\Expression\ExpressionInterface;
use Yiisoft\Db\Mysql\Tests\Provider\QueryBuilderProvider;
use Yiisoft\Db\Mysql\Tests\Support\TestTrait;
use Yiisoft\Db\Query\Query;
use Yiisoft\Db\Query\QueryInterface;
Expand All @@ -30,6 +32,11 @@ final class QueryBuilderTest extends CommonQueryBuilderTest
{
use TestTrait;

public function getBuildColumnDefinitionProvider(): array
{
return QueryBuilderProvider::buildColumnDefinition();
}

public function testAddcheck(): void
{
$db = $this->getConnection();
Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -266,11 +279,11 @@ public function testCreateTable(): void
$this->assertSame(
<<<SQL
CREATE TABLE `test` (
\t`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
\t`id` int PRIMARY KEY AUTO_INCREMENT,
\t`name` varchar(255) NOT NULL,
\t`email` varchar(255) NOT NULL,
\t`status` int(11) NOT NULL,
\t`created_at` datetime(0) NOT NULL
\t`status` integer NOT NULL,
\t`created_at` datetime NOT NULL
)
SQL,
$qb->createTable(
Expand Down
39 changes: 16 additions & 23 deletions tests/SchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 = [];
Expand All @@ -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());
}
}

Expand Down Expand Up @@ -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();

Expand Down

0 comments on commit 0b031ba

Please sign in to comment.