Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new column definition builder #367

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
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 @@

return $dbType;
}

protected function getDefaultUuidExpression(): string
{
$serverVersion = $this->queryBuilder->getServerInfo()->getVersion();

if (!str_contains($serverVersion, 'MariaDB')
&& version_compare($serverVersion, '8', '<')
) {
return '';

Check warning on line 114 in src/Column/ColumnDefinitionBuilder.php

View check run for this annotation

Codecov / codecov/patch

src/Column/ColumnDefinitionBuilder.php#L114

Added line #L114 was not covered by tests
}

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
Loading