Skip to content

Commit

Permalink
Add ColumnDefinitionBuilder (#364)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov authored Oct 15, 2024
1 parent 384c326 commit 14b4bd8
Show file tree
Hide file tree
Showing 12 changed files with 185 additions and 23 deletions.
9 changes: 5 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@
## 2.0.0 under development

- Enh #336: Implement `SqlParser` and `ExpressionBuilder` driver classes (@Tigrov)
- Enh #315: Implement `ColumnSchemaInterface` classes according to the data type of database table columns
- New #315: Implement `ColumnSchemaInterface` classes according to the data type of database table columns
for type casting performance. Related with yiisoft/db#752 (@Tigrov)
- Chg #348: Replace call of `SchemaInterface::getRawTableName()` to `QuoterInterface::getRawTableName()` (@Tigrov)
- Enh #349: Add method chaining for column classes (@Tigrov)
- Enh #350: Add array overlaps and JSON overlaps condition builders (@Tigrov)
- New #350: Add array overlaps and JSON overlaps condition builders (@Tigrov)
- Enh #353: Update `bit` type according to main PR yiisoft/db#860 (@Tigrov)
- Enh #354: Refactor PHP type of `ColumnSchemaInterface` instances (@Tigrov)
- Enh #356: Raise minimum PHP version to `^8.1` with minor refactoring (@Tigrov)
- Enh #355: Implement `ColumnFactory` class (@Tigrov)
- New #355: Implement `ColumnFactory` class (@Tigrov)
- Enh #359: Separate column type constants (@Tigrov)
- Enh #359: Remove `Schema::TYPE_ARRAY` and `Schema::TYPE_STRUCTURED` constants (@Tigrov)
- Enh #360: Realize `ColumnBuilder` class (@Tigrov)
- New #360: Realize `ColumnBuilder` class (@Tigrov)
- Enh #362: Update according changes in `ColumnSchemaInterface` (@Tigrov)
- New #364: Add `ColumnDefinitionBuilder` class (@Tigrov)

## 1.3.0 March 21, 2024

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

declare(strict_types=1);

namespace Yiisoft\Db\Pgsql\Column;

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

final class ColumnDefinitionBuilder extends AbstractColumnDefinitionBuilder
{
protected const GENERATE_UUID_EXPRESSION = 'gen_random_uuid()';

protected const TYPES_WITH_SIZE = [
'bit',
'bit varying',
'varbit',
'decimal',
'numeric',
'char',
'character',
'bpchar',
'character varying',
'varchar',
'time',
'timetz',
'timestamp',
'timestamptz',
'interval',
];

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

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

protected function buildType(ColumnSchemaInterface $column): string
{
if ($column instanceof \Yiisoft\Db\Schema\Column\ArrayColumnSchema) {
return $this->buildType($column->getColumn()) . str_repeat('[]', $column->getDimension());
}

return parent::buildType($column);
}

protected function getDbType(ColumnSchemaInterface $column): string
{
/** @psalm-suppress DocblockTypeContradiction */
return match ($column->getType()) {
ColumnType::BOOLEAN => 'boolean',
ColumnType::BIT => 'varbit',
ColumnType::TINYINT => $column->isAutoIncrement() ? 'smallserial' : 'smallint',
ColumnType::SMALLINT => $column->isAutoIncrement() ? 'smallserial' : 'smallint',
ColumnType::INTEGER => $column->isAutoIncrement() ? 'serial' : 'integer',
ColumnType::BIGINT => $column->isAutoIncrement() ? 'bigserial' : 'bigint',
ColumnType::FLOAT => 'real',
ColumnType::DOUBLE => 'double precision',
ColumnType::DECIMAL => 'numeric',
ColumnType::MONEY => 'money',
ColumnType::CHAR => 'char',
ColumnType::STRING => 'varchar',
ColumnType::TEXT => 'text',
ColumnType::BINARY => 'bytea',
ColumnType::UUID => 'uuid',
ColumnType::DATETIME => 'timestamp',
ColumnType::TIMESTAMP => 'timestamp',
ColumnType::DATE => 'date',
ColumnType::TIME => 'time',
ColumnType::STRUCTURED => 'jsonb',
ColumnType::JSON => 'jsonb',
default => 'varchar',
};
}
}
1 change: 1 addition & 0 deletions src/Column/ColumnFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ final class ColumnFactory extends AbstractColumnFactory
'cidr' => ColumnType::STRING,
'inet' => ColumnType::STRING,
'macaddr' => ColumnType::STRING,
'macaddr8' => ColumnType::STRING,
'tsquery' => ColumnType::STRING,
'tsvector' => ColumnType::STRING,
'txid_snapshot' => ColumnType::STRING,
Expand Down
7 changes: 0 additions & 7 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
use Yiisoft\Db\Driver\Pdo\AbstractPdoConnection;
use Yiisoft\Db\Driver\Pdo\PdoCommandInterface;
use Yiisoft\Db\Exception\InvalidArgumentException;
use Yiisoft\Db\Pgsql\Column\ColumnFactory;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
use Yiisoft\Db\Schema\Column\ColumnFactoryInterface;
use Yiisoft\Db\Schema\Quoter;
use Yiisoft\Db\Schema\QuoterInterface;
use Yiisoft\Db\Schema\SchemaInterface;
Expand Down Expand Up @@ -46,11 +44,6 @@ public function createTransaction(): TransactionInterface
return new Transaction($this);
}

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

public function getLastInsertID(string $sequenceName = null): string
{
if ($sequenceName === null) {
Expand Down
1 change: 1 addition & 0 deletions src/DDLQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin
return "ALTER TABLE $tableName ALTER COLUMN $columnName $type";
}

/** @psalm-suppress DeprecatedMethod */
$type = 'TYPE ' . $this->queryBuilder->getColumnType($type);
$multiAlterStatement = [];
$constraintPrefix = preg_replace('/[^a-z0-9_]/i', '', $table . '_' . $column);
Expand Down
5 changes: 4 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\Pgsql\Column\ColumnDefinitionBuilder;
use Yiisoft\Db\QueryBuilder\AbstractQueryBuilder;
use Yiisoft\Db\Schema\QuoterInterface;
use Yiisoft\Db\Schema\SchemaInterface;
Expand Down Expand Up @@ -52,6 +53,8 @@ public function __construct(QuoterInterface $quoter, SchemaInterface $schema)
$ddlBuilder = new DDLQueryBuilder($this, $quoter, $schema);
$dmlBuilder = new DMLQueryBuilder($this, $quoter, $schema);
$dqlBuilder = new DQLQueryBuilder($this, $quoter);
parent::__construct($quoter, $schema, $ddlBuilder, $dmlBuilder, $dqlBuilder);
$columnDefinitionBuilder = new ColumnDefinitionBuilder($this);

parent::__construct($quoter, $schema, $ddlBuilder, $dmlBuilder, $dqlBuilder, $columnDefinitionBuilder);
}
}
10 changes: 9 additions & 1 deletion src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
use Yiisoft\Db\Expression\Expression;
use Yiisoft\Db\Helper\DbArrayHelper;
use Yiisoft\Db\Pgsql\Column\ArrayColumnSchema;
use Yiisoft\Db\Pgsql\Column\ColumnFactory;
use Yiisoft\Db\Pgsql\Column\SequenceColumnSchemaInterface;
use Yiisoft\Db\Schema\Builder\ColumnInterface;
use Yiisoft\Db\Schema\Column\ColumnFactoryInterface;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
use Yiisoft\Db\Schema\Column\StructuredColumnSchema;
use Yiisoft\Db\Schema\TableSchemaInterface;
Expand Down Expand Up @@ -102,11 +104,17 @@ final class Schema extends AbstractPdoSchema
*/
protected string|array $tableQuoteCharacter = '"';

/** @deprecated Use {@see ColumnBuilder} instead. Will be removed in 2.0. */
public function createColumn(string $type, array|int|string $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 @@ -718,7 +726,7 @@ protected function findColumns(TableSchemaInterface $table): bool
*/
private function loadColumnSchema(array $info): ColumnSchemaInterface
{
$columnFactory = $this->db->getColumnFactory();
$columnFactory = $this->getColumnFactory();
$dbType = $info['data_type'];

if (!in_array($info['type_scheme'], [$this->defaultSchema, 'pg_catalog'], true)) {
Expand Down
4 changes: 2 additions & 2 deletions tests/ColumnFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function testFromDbType(string $dbType, string $expectedType, string $exp
parent::testFromDbType($dbType, $expectedType, $expectedInstanceOf);

$db = $this->getConnection();
$columnFactory = $db->getColumnFactory();
$columnFactory = $db->getSchema()->getColumnFactory();

// With dimension
$column = $columnFactory->fromDbType($dbType, ['dimension' => 1]);
Expand Down Expand Up @@ -60,7 +60,7 @@ public function testFromType(string $type, string $expectedType, string $expecte
parent::testFromType($type, $expectedType, $expectedInstanceOf);

$db = $this->getConnection();
$columnFactory = $db->getColumnFactory();
$columnFactory = $db->getSchema()->getColumnFactory();

// With dimension
$column = $columnFactory->fromType($type, ['dimension' => 1]);
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\Pgsql\Column\ColumnFactory;
use Yiisoft\Db\Pgsql\Tests\Support\TestTrait;
use Yiisoft\Db\Tests\Common\CommonConnectionTest;
use Yiisoft\Db\Transaction\TransactionInterface;
Expand Down Expand Up @@ -134,11 +133,4 @@ static function (ConnectionInterface $db) {

$db->close();
}

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

$this->assertInstanceOf(ColumnFactory::class, $db->getColumnFactory());
}
}
57 changes: 57 additions & 0 deletions tests/Provider/QueryBuilderProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Yiisoft\Db\Pgsql\Tests\Provider;

use Yiisoft\Db\Constant\ColumnType;
use Yiisoft\Db\Constant\PseudoType;
use Yiisoft\Db\Expression\ArrayExpression;
use Yiisoft\Db\Expression\Expression;
use Yiisoft\Db\Expression\JsonExpression;
Expand Down Expand Up @@ -536,4 +537,60 @@ public static function overlapsCondition(): array

return $data;
}

public static function buildColumnDefinition(): array
{
$values = parent::buildColumnDefinition();

$values[PseudoType::PK][0] = 'serial PRIMARY KEY';
$values[PseudoType::UPK][0] = 'serial PRIMARY KEY';
$values[PseudoType::BIGPK][0] = 'bigserial PRIMARY KEY';
$values[PseudoType::UBIGPK][0] = 'bigserial PRIMARY KEY';
$values[PseudoType::UUID_PK][0] = 'uuid PRIMARY KEY DEFAULT gen_random_uuid()';
$values[PseudoType::UUID_PK_SEQ][0] = 'uuid PRIMARY KEY DEFAULT gen_random_uuid()';
$values['primaryKey()'][0] = 'serial PRIMARY KEY';
$values['smallPrimaryKey()'][0] = 'smallserial PRIMARY KEY';
$values['bigPrimaryKey()'][0] = 'bigserial PRIMARY KEY';
$values['uuidPrimaryKey()'][0] = 'uuid PRIMARY KEY DEFAULT gen_random_uuid()';
$values['bit()'][0] = 'varbit';
$values['bit(1)'][0] = 'varbit(1)';
$values['bit(8)'][0] = 'varbit(8)';
$values['bit(1000)'][0] = 'varbit(1000)';
$values['tinyint()'][0] = 'smallint';
$values['tinyint(2)'][0] = 'smallint';
$values['smallint(4)'][0] = 'smallint';
$values['integer(8)'][0] = 'integer';
$values['bigint(15)'][0] = 'bigint';
$values['float()'][0] = 'real';
$values['float(10)'][0] = 'real';
$values['float(10,2)'][0] = 'real';
$values['double()'][0] = 'double precision';
$values['double(10)'][0] = 'double precision';
$values['double(10,2)'][0] = 'double precision';
$values['decimal()'][0] = 'numeric(10,0)';
$values['decimal(5)'][0] = 'numeric(5,0)';
$values['decimal(5,2)'][0] = 'numeric(5,2)';
$values['decimal(null)'][0] = 'numeric';
$values['money()'][0] = 'money';
$values['money(10)'][0] = 'money';
$values['money(10,2)'][0] = 'money';
$values['money(null)'][0] = 'money';
$values['text(1000)'][0] = 'text';
$values['binary()'][0] = 'bytea';
$values['binary(1000)'][0] = 'bytea';
$values['uuid()'][0] = 'uuid';
$values['datetime()'][0] = 'timestamp(0)';
$values['datetime(6)'][0] = 'timestamp(6)';
$values['datetime(null)'][0] = 'timestamp';
$values['array()'][0] = 'varchar[]';
$values['structured()'][0] = 'jsonb';
$values["structured('structured_type')"][0] = 'structured_type';
$values['json()'][0] = 'jsonb';
$values['json(100)'][0] = 'jsonb';
$values['unsigned()'][0] = 'integer';
$values['scale(2)'][0] = 'numeric(10,2)';
$values['integer(8)->scale(2)'][0] = 'integer';

return $values;
}
}
9 changes: 9 additions & 0 deletions tests/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\QueryBuilder\Condition\ArrayOverlapsCondition;
use Yiisoft\Db\QueryBuilder\Condition\JsonOverlapsCondition;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
use Yiisoft\Db\Tests\Common\CommonQueryBuilderTest;

use function version_compare;
Expand Down Expand Up @@ -433,6 +434,8 @@ public function testDropDefaultValue(): void
);
$qb->dropDefaultValue('T_constraints_1', 'CN_pk');
$db->close();
}
/**
Expand Down Expand Up @@ -783,4 +786,10 @@ public function testOverlapsConditionOperator(iterable|ExpressionInterface $valu

$db->close();
}

/** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\QueryBuilderProvider::buildColumnDefinition() */
public function testBuildColumnDefinition(string $expected, ColumnSchemaInterface|string $column): void
{
parent::testBuildColumnDefinition($expected, $column);
}
}
10 changes: 10 additions & 0 deletions tests/SchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Expression\Expression;
use Yiisoft\Db\Pgsql\Column\ColumnFactory;
use Yiisoft\Db\Pgsql\Schema;
use Yiisoft\Db\Pgsql\Tests\Support\TestTrait;
use Yiisoft\Db\Schema\SchemaInterface;
Expand Down Expand Up @@ -648,4 +649,13 @@ public function testTableIndexes(): void

$db->close();
}

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

$this->assertInstanceOf(ColumnFactory::class, $db->getSchema()->getColumnFactory());

$db->close();
}
}

0 comments on commit 14b4bd8

Please sign in to comment.