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

Realize ColumnBuilder #360

Merged
merged 13 commits into from
Sep 16, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Enh #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)

## 1.3.0 March 21, 2024

Expand Down
5 changes: 2 additions & 3 deletions src/Column/ArrayColumnSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ public function column(ColumnSchemaInterface|null $column): static
public function getColumn(): ColumnSchemaInterface
{
if ($this->column === null) {
$this->column = (new ColumnFactory())->fromType($this->getType());
$this->column->dbType($this->getDbType());
$this->column = (new ColumnFactory())->fromDbType($this->getDbType() ?? '');
$this->column->enumValues($this->getEnumValues());
$this->column->precision($this->getPrecision());
$this->column->scale($this->getScale());
Expand Down Expand Up @@ -101,7 +100,7 @@ public function dbTypecast(mixed $value): ExpressionInterface|null
$value = $this->dbTypecastArray($value, $this->dimension);
}

return new ArrayExpression($value, $this->getDbType(), $this->dimension);
return new ArrayExpression($value, $this->getDbType() ?? $this->getColumn()->getDbType(), $this->dimension);
}

public function phpTypecast(mixed $value): array|null
Expand Down
71 changes: 71 additions & 0 deletions src/Column/ColumnBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Pgsql\Column;

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

final class ColumnBuilder extends \Yiisoft\Db\Schema\Column\ColumnBuilder
{
public static function boolean(): ColumnSchemaInterface
{
return new BooleanColumnSchema(ColumnType::BOOLEAN);
}

public static function bit(int|null $size = null): ColumnSchemaInterface
{
return (new BitColumnSchema(ColumnType::BIT))
->size($size);
}

public static function tinyint(int|null $size = null): ColumnSchemaInterface
{
return (new IntegerColumnSchema(ColumnType::TINYINT))
->size($size);
}

public static function smallint(int|null $size = null): ColumnSchemaInterface
{
return (new IntegerColumnSchema(ColumnType::SMALLINT))
->size($size);
}

public static function integer(int|null $size = null): ColumnSchemaInterface
{
return (new IntegerColumnSchema(ColumnType::INTEGER))
->size($size);
}

public static function bigint(int|null $size = null): ColumnSchemaInterface
{
return (new IntegerColumnSchema(ColumnType::BIGINT))
->size($size);
}

public static function binary(int|null $size = null): ColumnSchemaInterface
{
return (new BinaryColumnSchema(ColumnType::BINARY))
->size($size);
}

public static function array(ColumnSchemaInterface|null $column = null): ColumnSchemaInterface
{
return (new ArrayColumnSchema(ColumnType::ARRAY))
->column($column);
}

/**
* @param string|null $dbType The DB type of the column.
* @param ColumnSchemaInterface[] $columns The columns (name -> instance) that the structured column should contain.
*
* @psalm-param array<string, ColumnSchemaInterface> $columns
*/
public static function structured(string|null $dbType = null, array $columns = []): ColumnSchemaInterface
{
return (new StructuredColumnSchema(ColumnType::STRUCTURED))
->dbType($dbType)
->columns($columns);
}
}
9 changes: 7 additions & 2 deletions src/Column/ColumnFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ final class ColumnFactory extends AbstractColumnFactory
* @psalm-param ColumnType::* $type
* @psalm-param ColumnInfo $info
* @psalm-suppress MoreSpecificImplementedParamType
* @psalm-suppress ArgumentTypeCoercion
*/
public function fromType(string $type, array $info = []): ColumnSchemaInterface
{
Expand All @@ -125,7 +126,6 @@ public function fromType(string $type, array $info = []): ColumnSchemaInterface
->dimension($dimension)
->column($this->fromType($type, $info));
} else {
/** @psalm-suppress ArgumentTypeCoercion */
$column = match ($type) {
ColumnType::BOOLEAN => new BooleanColumnSchema($type),
ColumnType::BIT => new BitColumnSchema($type),
Expand All @@ -141,11 +141,16 @@ public function fromType(string $type, array $info = []): ColumnSchemaInterface
};
}

return $column;
return $column->load($info);
}

protected function getType(string $dbType, array $info = []): string
{
return self::TYPE_MAP[$dbType] ?? ColumnType::STRING;
}

protected function isDbType(string $dbType): bool
{
return isset(self::TYPE_MAP[$dbType]);
}
}
7 changes: 7 additions & 0 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
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 @@ -44,6 +46,11 @@ 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
12 changes: 3 additions & 9 deletions src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
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\Pgsql\Column\StructuredColumnSchemaInterface;
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 @@ -111,11 +109,6 @@ public function createColumn(string $type, array|int|string $length = null): Col
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 @@ -722,6 +715,7 @@ protected function findColumns(TableSchemaInterface $table): bool
*/
private function loadColumnSchema(array $info): ColumnSchemaInterface
{
$columnFactory = $this->db->getColumnFactory();
$dbType = $info['data_type'];

if (!in_array($info['type_scheme'], [$this->defaultSchema, 'pg_catalog'], true)) {
Expand All @@ -737,10 +731,10 @@ private function loadColumnSchema(array $info): ColumnSchemaInterface
$columns = $structured->getColumns();
}

$column = $this->getColumnFactory()
$column = $columnFactory
->fromType(ColumnType::STRUCTURED, ['dimension' => $info['dimension'], 'columns' => $columns]);
} else {
$column = $this->getColumnFactory()
$column = $columnFactory
->fromDbType($dbType, ['dimension' => $info['dimension']]);
}

Expand Down
35 changes: 35 additions & 0 deletions tests/ColumnBuilderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Pgsql\Tests;

use Yiisoft\Db\Pgsql\Column\ColumnBuilder;
use Yiisoft\Db\Pgsql\Tests\Support\TestTrait;
use Yiisoft\Db\Tests\AbstractColumnBuilderTest;

/**
* @group pgsql
*/
final class ColumnBuilderTest extends AbstractColumnBuilderTest
{
use TestTrait;

public function getColumnBuilderClass(): string
{
return ColumnBuilder::class;
}

/**
* @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnBuilderProvider::buildingMethods
*/
public function testBuildingMethods(
string $buildingMethod,
array $args,
string $expectedInstanceOf,
string $expectedType,
array $expectedMethodResults = [],
): void {
parent::testBuildingMethods($buildingMethod, $args, $expectedInstanceOf, $expectedType, $expectedMethodResults);
}
}
20 changes: 17 additions & 3 deletions tests/ColumnFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,23 @@ public function testFromDbType(string $dbType, string $expectedType, string $exp
}

/** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnFactoryProvider::definitions */
public function testFromDefinition(string $definition, string $expectedType, string $expectedInstanceOf, array $expectedInfo = []): void
{
parent::testFromDefinition($definition, $expectedType, $expectedInstanceOf, $expectedInfo);
public function testFromDefinition(
string $definition,
string $expectedType,
string $expectedInstanceOf,
array $expectedMethodResults = []
): void {
parent::testFromDefinition($definition, $expectedType, $expectedInstanceOf, $expectedMethodResults);
}

/** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnFactoryProvider::pseudoTypes */
public function testFromPseudoType(
string $pseudoType,
string $expectedType,
string $expectedInstanceOf,
array $expectedMethodResults = []
): void {
parent::testFromPseudoType($pseudoType, $expectedType, $expectedInstanceOf, $expectedMethodResults);
}

/** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnFactoryProvider::types */
Expand Down
16 changes: 10 additions & 6 deletions tests/ColumnSchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,12 @@ public function testPhpTypecastColumns(string $className, array $values)
}

/** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnSchemaProvider::dbTypecastArrayColumns */
public function testDbTypecastArrayColumnSchema(string $dbType, string $type, string $phpType, array $values): void
public function testDbTypecastArrayColumnSchema(string $dbType, string $type, array $values): void
{
$arrayCol = new ArrayColumnSchema($type, $phpType);
$arrayCol->dbType($dbType);
$db = $this->getConnection();
$columnFactory = $db->getColumnFactory();

$arrayCol = (new ArrayColumnSchema())->column($columnFactory->fromType($type)->dbType($dbType));

foreach ($values as [$dimension, $expected, $value]) {
$arrayCol->dimension($dimension);
Expand All @@ -331,10 +333,12 @@ public function testDbTypecastArrayColumnSchema(string $dbType, string $type, st
}

/** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnSchemaProvider::phpTypecastArrayColumns */
public function testPhpTypecastArrayColumnSchema(string $dbType, string $type, string $phpType, array $values): void
public function testPhpTypecastArrayColumnSchema(string $dbType, string $type, array $values): void
{
$arrayCol = new ArrayColumnSchema($type, $phpType);
$arrayCol->dbType($dbType);
$db = $this->getConnection();
$columnFactory = $db->getColumnFactory();

$arrayCol = (new ArrayColumnSchema())->column($columnFactory->fromType($type)->dbType($dbType));

foreach ($values as [$dimension, $expected, $value]) {
$arrayCol->dimension($dimension);
Expand Down
8 changes: 8 additions & 0 deletions tests/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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 @@ -133,4 +134,11 @@ static function (ConnectionInterface $db) {

$db->close();
}

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

$this->assertInstanceOf(ColumnFactory::class, $db->getColumnFactory());
}
}
72 changes: 72 additions & 0 deletions tests/Provider/ColumnBuilderProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Pgsql\Tests\Provider;

use Yiisoft\Db\Constant\ColumnType;
use Yiisoft\Db\Pgsql\Column\ArrayColumnSchema;
use Yiisoft\Db\Pgsql\Column\BinaryColumnSchema;
use Yiisoft\Db\Pgsql\Column\BitColumnSchema;
use Yiisoft\Db\Pgsql\Column\BooleanColumnSchema;
use Yiisoft\Db\Pgsql\Column\ColumnBuilder;
use Yiisoft\Db\Pgsql\Column\IntegerColumnSchema;
use Yiisoft\Db\Pgsql\Column\StructuredColumnSchema;
use Yiisoft\Db\Schema\Column\DoubleColumnSchema;
use Yiisoft\Db\Schema\Column\StringColumnSchema;

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(),
['primaryKey', [], IntegerColumnSchema::class, ColumnType::INTEGER, ['isPrimaryKey' => true, 'isAutoIncrement' => true]],
['primaryKey', [false], IntegerColumnSchema::class, ColumnType::INTEGER, ['isPrimaryKey' => true, 'isAutoIncrement' => false]],
['smallPrimaryKey', [], IntegerColumnSchema::class, ColumnType::SMALLINT, ['isPrimaryKey' => true, 'isAutoIncrement' => true]],
['smallPrimaryKey', [false], IntegerColumnSchema::class, ColumnType::SMALLINT, ['isPrimaryKey' => true, 'isAutoIncrement' => false]],
['bigPrimaryKey', [], IntegerColumnSchema::class, ColumnType::BIGINT, ['isPrimaryKey' => true, 'isAutoIncrement' => true]],
['bigPrimaryKey', [false], IntegerColumnSchema::class, ColumnType::BIGINT, ['isPrimaryKey' => true, 'isAutoIncrement' => false]],
['boolean', [], BooleanColumnSchema::class, ColumnType::BOOLEAN],
['bit', [], BitColumnSchema::class, ColumnType::BIT],
['bit', [1], BitColumnSchema::class, ColumnType::BIT, ['getSize' => 1]],
['tinyint', [], IntegerColumnSchema::class, ColumnType::TINYINT],
['tinyint', [1], IntegerColumnSchema::class, ColumnType::TINYINT, ['getSize' => 1]],
['smallint', [], IntegerColumnSchema::class, ColumnType::SMALLINT],
['smallint', [1], IntegerColumnSchema::class, ColumnType::SMALLINT, ['getSize' => 1]],
['integer', [], IntegerColumnSchema::class, ColumnType::INTEGER],
['integer', [1], IntegerColumnSchema::class, ColumnType::INTEGER, ['getSize' => 1]],
['bigint', [], IntegerColumnSchema::class, ColumnType::BIGINT],
['bigint', [1], IntegerColumnSchema::class, ColumnType::BIGINT, ['getSize' => 1]],
['float', [], DoubleColumnSchema::class, ColumnType::FLOAT],
['float', [8], DoubleColumnSchema::class, ColumnType::FLOAT, ['getSize' => 8]],
['float', [8, 2], DoubleColumnSchema::class, ColumnType::FLOAT, ['getSize' => 8, 'getScale' => 2]],
['double', [], DoubleColumnSchema::class, ColumnType::DOUBLE],
['double', [8], DoubleColumnSchema::class, ColumnType::DOUBLE, ['getSize' => 8]],
['double', [8, 2], DoubleColumnSchema::class, ColumnType::DOUBLE, ['getSize' => 8, 'getScale' => 2]],
['decimal', [], DoubleColumnSchema::class, ColumnType::DECIMAL, ['getSize' => 10, 'getScale' => 0]],
['decimal', [8], DoubleColumnSchema::class, ColumnType::DECIMAL, ['getSize' => 8, 'getScale' => 0]],
['decimal', [8, 2], DoubleColumnSchema::class, ColumnType::DECIMAL, ['getSize' => 8, 'getScale' => 2]],
['money', [], DoubleColumnSchema::class, ColumnType::MONEY, ['getSize' => 19, 'getScale' => 4]],
['money', [8], DoubleColumnSchema::class, ColumnType::MONEY, ['getSize' => 8, 'getScale' => 4]],
['money', [8, 2], DoubleColumnSchema::class, ColumnType::MONEY, ['getSize' => 8, 'getScale' => 2]],
['binary', [], BinaryColumnSchema::class, ColumnType::BINARY],
['binary', [8], BinaryColumnSchema::class, ColumnType::BINARY, ['getSize' => 8]],
['array', [], ArrayColumnSchema::class, ColumnType::ARRAY],
['array', [$column = new StringColumnSchema()], ArrayColumnSchema::class, ColumnType::ARRAY, ['getColumn' => $column]],
['structured', [], StructuredColumnSchema::class, ColumnType::STRUCTURED],
['structured', ['money_currency'], StructuredColumnSchema::class, ColumnType::STRUCTURED, ['getDbType' => 'money_currency']],
[
'structured',
[
'money_currency',
$columns = ['value' => ColumnBuilder::money(), 'currency' => ColumnBuilder::string(3)],
],
StructuredColumnSchema::class,
ColumnType::STRUCTURED,
['getDbType' => 'money_currency', 'getColumns' => $columns],
],
];
}
}
Loading
Loading