Skip to content

Commit

Permalink
Add ColumnDefinitionBuilder (#322)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov authored Oct 15, 2024
1 parent b0213bf commit 5171ad7
Show file tree
Hide file tree
Showing 14 changed files with 237 additions and 32 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@

## 2.0.0 under development

- Enh #277: Implement `ColumnSchemaInterface` classes according to the data type of database table columns
- New #277: Implement `ColumnSchemaInterface` classes according to the data type of database table columns
for type casting performance. Related with yiisoft/db#752 (@Tigrov)
- Enh #293: Implement `SqlParser` and `ExpressionBuilder` driver classes (@Tigrov)
- Chg #306: Remove parameter `$withColumn` from `Quoter::getTableNameParts()` method (@Tigrov)
- Chg #308: Replace call of `SchemaInterface::getRawTableName()` to `QuoterInterface::getRawTableName()` (@Tigrov)
- Enh #312: Refactor `bit` type (@Tigrov)
- Enh #315: Refactor PHP type of `ColumnSchemaInterface` instances (@Tigrov)
- Enh #317: Raise minimum PHP version to `^8.1` with minor refactoring (@Tigrov)
- Enh #316: Implement `ColumnFactory` class (@Tigrov)
- New #316: Implement `ColumnFactory` class (@Tigrov)
- Enh #319: Separate column type constants (@Tigrov)
- Enh #320: Realize `ColumnBuilder` class (@Tigrov)
- New #320: Realize `ColumnBuilder` class (@Tigrov)
- Enh #321: Update according changes in `ColumnSchemaInterface` (@Tigrov)
- New #322: Add `ColumnDefinitionBuilder` class (@Tigrov)

## 1.2.0 March 21, 2024

Expand Down
89 changes: 89 additions & 0 deletions src/Column/ColumnDefinitionBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Mssql\Column;

use Yiisoft\Db\Constant\ColumnType;
use Yiisoft\Db\QueryBuilder\AbstractColumnDefinitionBuilder;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;

use function ceil;

final class ColumnDefinitionBuilder extends AbstractColumnDefinitionBuilder
{
protected const AUTO_INCREMENT_KEYWORD = 'IDENTITY';

protected const GENERATE_UUID_EXPRESSION = 'newid()';

protected const TYPES_WITH_SIZE = [
'decimal',
'numeric',
'float',
'time',
'datetime2',
'datetimeoffset',
'char',
'varchar',
'nchar',
'nvarchar',
'binary',
'varbinary',
];

protected const TYPES_WITH_SCALE = [
'decimal',
'numeric',
];

public function build(ColumnSchemaInterface $column): string
{
return $this->buildType($column)
. $this->buildAutoIncrement($column)
. $this->buildPrimaryKey($column)
. $this->buildUnique($column)
. $this->buildNotNull($column)
. $this->buildDefault($column)
. $this->buildCheck($column)
. $this->buildReferences($column)
. $this->buildExtra($column);
}

protected function getDbType(ColumnSchemaInterface $column): string
{
/** @psalm-suppress DocblockTypeContradiction */
return match ($column->getType()) {
ColumnType::BOOLEAN => 'bit',
ColumnType::BIT => match (true) {
($size = $column->getSize()) === null => 'bigint',
$size === 1 => 'bit',
$size <= 8 => 'tinyint',
$size <= 16 => 'smallint',
$size <= 32 => 'int',
$size <= 64 => 'bigint',
default => 'varbinary(' . ceil($size / 8) . ')',
},
ColumnType::TINYINT => 'tinyint',
ColumnType::SMALLINT => 'smallint',
ColumnType::INTEGER => 'int',
ColumnType::BIGINT => 'bigint',
ColumnType::FLOAT => 'real',
ColumnType::DOUBLE => 'float(53)',
ColumnType::DECIMAL => 'decimal',
ColumnType::MONEY => 'money',
ColumnType::CHAR => 'nchar',
ColumnType::STRING => 'nvarchar',
ColumnType::TEXT => 'nvarchar(max)',
ColumnType::BINARY => 'varbinary(max)',
ColumnType::UUID => 'uniqueidentifier',
ColumnType::DATETIME => 'datetime2',
ColumnType::TIMESTAMP => 'datetime2',
ColumnType::DATE => 'date',
ColumnType::TIME => 'time',
ColumnType::ARRAY => 'json',
ColumnType::STRUCTURED => 'json',
ColumnType::JSON => 'json',
default => 'varchar',
};
}
}
17 changes: 15 additions & 2 deletions src/Column/ColumnFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
namespace Yiisoft\Db\Mssql\Column;

use Yiisoft\Db\Constant\ColumnType;
use Yiisoft\Db\Constant\PseudoType;
use Yiisoft\Db\Expression\Expression;
use Yiisoft\Db\Schema\Column\AbstractColumnFactory;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;

Expand Down Expand Up @@ -58,9 +60,9 @@ final class ColumnFactory extends AbstractColumnFactory
/**
* Other data types 'cursor' type can't be used with tables
*/
'timestamp' => ColumnType::TIMESTAMP,
'timestamp' => ColumnType::BINARY,
'hierarchyid' => ColumnType::STRING,
'uniqueidentifier' => ColumnType::STRING,
'uniqueidentifier' => ColumnType::UUID,
'sql_variant' => ColumnType::STRING,
'xml' => ColumnType::STRING,
'table' => ColumnType::STRING,
Expand All @@ -71,6 +73,17 @@ protected function getType(string $dbType, array $info = []): string
return self::TYPE_MAP[$dbType] ?? ColumnType::STRING;
}

public function fromPseudoType(string $pseudoType, array $info = []): ColumnSchemaInterface
{
if ($pseudoType === PseudoType::UUID_PK_SEQ) {
return ColumnBuilder::uuidPrimaryKey()
->defaultValue(new Expression('newsequentialid()'))
->load($info);
}

return parent::fromPseudoType($pseudoType, $info);
}

public function fromType(string $type, array $info = []): ColumnSchemaInterface
{
if ($type === ColumnType::BINARY) {
Expand Down
7 changes: 0 additions & 7 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@

use Yiisoft\Db\Driver\Pdo\AbstractPdoConnection;
use Yiisoft\Db\Driver\Pdo\PdoCommandInterface;
use Yiisoft\Db\Mssql\Column\ColumnFactory;
use Yiisoft\Db\Query\BatchQueryResultInterface;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
use Yiisoft\Db\Schema\Column\ColumnFactoryInterface;
use Yiisoft\Db\Schema\QuoterInterface;
use Yiisoft\Db\Schema\SchemaInterface;
use Yiisoft\Db\Transaction\TransactionInterface;
Expand Down Expand Up @@ -51,11 +49,6 @@ public function createTransaction(): TransactionInterface
return new Transaction($this);
}

public function getColumnFactory(): ColumnFactoryInterface
{
return new ColumnFactory();
}

public function getQueryBuilder(): QueryBuilderInterface
{
if ($this->queryBuilder === null) {
Expand Down
1 change: 1 addition & 0 deletions src/DDLQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin
}
}

/** @psalm-suppress DeprecatedMethod */
return implode("\n", [
$this->dropConstraintsForColumn($table, $column, 'D'),
"ALTER TABLE $tableName ALTER COLUMN $columnName {$this->queryBuilder->getColumnType($type)}",
Expand Down
6 changes: 5 additions & 1 deletion src/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Yiisoft\Db\Constant\ColumnType;
use Yiisoft\Db\Constant\PseudoType;
use Yiisoft\Db\Mssql\Column\ColumnDefinitionBuilder;
use Yiisoft\Db\QueryBuilder\AbstractQueryBuilder;
use Yiisoft\Db\Schema\Builder\ColumnInterface;
use Yiisoft\Db\Schema\QuoterInterface;
Expand Down Expand Up @@ -52,12 +53,15 @@ public function __construct(QuoterInterface $quoter, SchemaInterface $schema)
$ddlBuilder = new DDLQueryBuilder($this, $quoter, $schema);
$dmlBuilder = new DMLQueryBuilder($this, $quoter, $schema);
$dqlBuilder = new DQLQueryBuilder($this, $quoter);
$columnDefinitionBuilder = new ColumnDefinitionBuilder($this);

parent::__construct($quoter, $schema, $ddlBuilder, $dmlBuilder, $dqlBuilder);
parent::__construct($quoter, $schema, $ddlBuilder, $dmlBuilder, $dqlBuilder, $columnDefinitionBuilder);
}

/** @deprecated Use {@see buildColumnDefinition()}. Will be removed in version 2.0. */
public function getColumnType(ColumnInterface|string $type): string
{
/** @psalm-suppress DeprecatedMethod */
$columnType = parent::getColumnType($type);

/** remove unsupported keywords*/
Expand Down
10 changes: 9 additions & 1 deletion src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Helper\DbArrayHelper;
use Yiisoft\Db\Mssql\Column\ColumnFactory;
use Yiisoft\Db\Schema\Builder\ColumnInterface;
use Yiisoft\Db\Schema\Column\ColumnFactoryInterface;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
use Yiisoft\Db\Schema\TableSchemaInterface;

Expand Down Expand Up @@ -64,11 +66,17 @@ final class Schema extends AbstractPdoSchema
*/
protected string|null $defaultSchema = 'dbo';

/** @deprecated Use {@see ColumnBuilder} instead. Will be removed in 2.0. */
public function createColumn(string $type, array|int|string|null $length = null): ColumnInterface
{
return new Column($type, $length);
}

public function getColumnFactory(): ColumnFactoryInterface
{
return new ColumnFactory();
}

/**
* Resolves the table name and schema name (if any).
*
Expand Down Expand Up @@ -358,7 +366,7 @@ protected function loadTableDefaultValues(string $tableName): array
*/
private function loadColumnSchema(array $info): ColumnSchemaInterface
{
$columnFactory = $this->db->getColumnFactory();
$columnFactory = $this->getColumnFactory();

$dbType = $info['data_type'];
/** @psalm-var ColumnArray $info */
Expand Down
8 changes: 0 additions & 8 deletions tests/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Mssql\Column\ColumnFactory;
use Yiisoft\Db\Mssql\Tests\Support\TestTrait;
use Yiisoft\Db\Tests\Common\CommonConnectionTest;
use Yiisoft\Db\Transaction\TransactionInterface;
Expand Down Expand Up @@ -88,11 +87,4 @@ public function testSettingDefaultAttributes(): void

$this->assertSame(PDO::ERRMODE_EXCEPTION, $db->getActivePDO()?->getAttribute(PDO::ATTR_ERRMODE));
}

public function testGetColumnFactory(): void
{
$db = $this->getConnection();

$this->assertInstanceOf(ColumnFactory::class, $db->getColumnFactory());
}
}
13 changes: 6 additions & 7 deletions tests/Provider/ColumnBuilderProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@

namespace Yiisoft\Db\Mssql\Tests\Provider;

use Yiisoft\Db\Constant\ColumnType;
use Yiisoft\Db\Mssql\Column\BinaryColumnSchema;

class ColumnBuilderProvider extends \Yiisoft\Db\Tests\Provider\ColumnBuilderProvider
{
public static function buildingMethods(): array
{
return [
// building method, args, expected instance of, expected type, expected column method results
...parent::buildingMethods(),
['binary', [], BinaryColumnSchema::class, ColumnType::BINARY],
['binary', [8], BinaryColumnSchema::class, ColumnType::BINARY, ['getSize' => 8]],
];
$values = parent::buildingMethods();

$values['binary()'][2] = BinaryColumnSchema::class;
$values['binary(8)'][2] = BinaryColumnSchema::class;

return $values;
}
}
14 changes: 12 additions & 2 deletions tests/Provider/ColumnFactoryProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Yiisoft\Db\Mssql\Tests\Provider;

use Yiisoft\Db\Constant\ColumnType;
use Yiisoft\Db\Expression\Expression;
use Yiisoft\Db\Mssql\Column\BinaryColumnSchema;
use Yiisoft\Db\Schema\Column\BooleanColumnSchema;
use Yiisoft\Db\Schema\Column\DoubleColumnSchema;
Expand All @@ -13,6 +14,15 @@

final class ColumnFactoryProvider extends \Yiisoft\Db\Tests\Provider\ColumnFactoryProvider
{
public static function pseudoTypes(): array
{
$values = parent::pseudoTypes();

$values['uuid_pk_seq'][3]['getDefaultValue'] = new Expression('newsequentialid()');

return $values;
}

public static function dbTypes(): array
{
return [
Expand Down Expand Up @@ -44,9 +54,9 @@ public static function dbTypes(): array
['binary', ColumnType::BINARY, BinaryColumnSchema::class],
['varbinary', ColumnType::BINARY, BinaryColumnSchema::class],
['image', ColumnType::BINARY, BinaryColumnSchema::class],
['timestamp', ColumnType::TIMESTAMP, StringColumnSchema::class],
['timestamp', ColumnType::BINARY, BinaryColumnSchema::class],
['hierarchyid', ColumnType::STRING, StringColumnSchema::class],
['uniqueidentifier', ColumnType::STRING, StringColumnSchema::class],
['uniqueidentifier', ColumnType::UUID, StringColumnSchema::class],
['sql_variant', ColumnType::STRING, StringColumnSchema::class],
['xml', ColumnType::STRING, StringColumnSchema::class],
['table', ColumnType::STRING, StringColumnSchema::class],
Expand Down
Loading

0 comments on commit 5171ad7

Please sign in to comment.