From 3aff3c958702d4ce2a4d2bd8978b9d47672b0d82 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Mon, 7 Oct 2024 14:40:48 +0700 Subject: [PATCH 1/5] Add `ColumnDefinitionBuilder` --- src/ArrayParser.php | 10 +- src/Builder/StructuredExpressionBuilder.php | 2 +- src/Column/ArrayColumnSchema.php | 159 +--------------- src/Column/ColumnBuilder.php | 6 - src/Column/ColumnDefinitionBuilder.php | 87 +++++++++ src/Column/ColumnFactory.php | 1 + src/Column/StructuredColumnSchema.php | 88 +-------- .../StructuredColumnSchemaInterface.php | 25 --- src/Connection.php | 7 - src/DDLQueryBuilder.php | 1 + src/DQLQueryBuilder.php | 1 + src/QueryBuilder.php | 5 +- src/Schema.php | 12 +- src/StructuredExpression.php | 104 ----------- src/StructuredParser.php | 6 +- tests/ArrayParserTest.php | 1 - tests/ColumnSchemaTest.php | 72 ++------ tests/ConnectionTest.php | 8 - tests/PdoCommandTest.php | 2 + tests/Provider/ColumnBuilderProvider.php | 89 +++++---- tests/Provider/ColumnSchemaProvider.php | 169 ++---------------- tests/Provider/QueryBuilderProvider.php | 65 ++++++- tests/Provider/StructuredTypeProvider.php | 58 +----- tests/QueryBuilderTest.php | 9 + tests/SchemaTest.php | 14 ++ tests/StructuredExpressionTest.php | 24 --- tests/Support/ColumnSchemaBuilder.php | 36 ---- 27 files changed, 276 insertions(+), 785 deletions(-) create mode 100644 src/Column/ColumnDefinitionBuilder.php delete mode 100644 src/Column/StructuredColumnSchemaInterface.php delete mode 100644 src/StructuredExpression.php delete mode 100644 tests/StructuredExpressionTest.php delete mode 100644 tests/Support/ColumnSchemaBuilder.php diff --git a/src/ArrayParser.php b/src/ArrayParser.php index 2a4578b6a..6648396ce 100644 --- a/src/ArrayParser.php +++ b/src/ArrayParser.php @@ -4,21 +4,21 @@ namespace Yiisoft\Db\Pgsql; +use Yiisoft\Db\Syntax\ParserToArrayInterface; + use function in_array; /** * Array representation to PHP array parser for PostgreSQL Server. */ -final class ArrayParser +final class ArrayParser implements ParserToArrayInterface { /** * Convert an array from PostgresSQL to PHP. - * - * @param string|null $value String to convert. */ - public function parse(string|null $value): array|null + public function parse(string $value): array|null { - return $value !== null && $value[0] === '{' + return $value[0] === '{' ? $this->parseArray($value) : null; } diff --git a/src/Builder/StructuredExpressionBuilder.php b/src/Builder/StructuredExpressionBuilder.php index ddc0ff342..e81232152 100644 --- a/src/Builder/StructuredExpressionBuilder.php +++ b/src/Builder/StructuredExpressionBuilder.php @@ -10,7 +10,7 @@ use Yiisoft\Db\Exception\NotSupportedException; use Yiisoft\Db\Expression\ExpressionBuilderInterface; use Yiisoft\Db\Expression\ExpressionInterface; -use Yiisoft\Db\Pgsql\StructuredExpression; +use Yiisoft\Db\Expression\StructuredExpression; use Yiisoft\Db\Query\QueryInterface; use Yiisoft\Db\QueryBuilder\QueryBuilderInterface; diff --git a/src/Column/ArrayColumnSchema.php b/src/Column/ArrayColumnSchema.php index d80d7c1e2..8f5a2ac97 100644 --- a/src/Column/ArrayColumnSchema.php +++ b/src/Column/ArrayColumnSchema.php @@ -4,164 +4,21 @@ namespace Yiisoft\Db\Pgsql\Column; -use Traversable; -use Yiisoft\Db\Constant\ColumnType; -use Yiisoft\Db\Constant\PhpType; -use Yiisoft\Db\Expression\ArrayExpression; -use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Pgsql\ArrayParser; -use Yiisoft\Db\Schema\Column\AbstractColumnSchema; -use Yiisoft\Db\Schema\Column\ColumnSchemaInterface; +use Yiisoft\Db\Schema\Column\ArrayColumnSchema as BaseArrayColumnSchema; +use Yiisoft\Db\Schema\Column\ColumnFactoryInterface; +use Yiisoft\Db\Syntax\ParserToArrayInterface; -use function array_map; -use function array_walk_recursive; -use function is_array; -use function is_iterable; -use function is_string; -use function iterator_to_array; - -final class ArrayColumnSchema extends AbstractColumnSchema +final class ArrayColumnSchema extends BaseArrayColumnSchema { - /** - * @var ColumnSchemaInterface|null The column of an array item. - */ - private ColumnSchemaInterface|null $column = null; - - /** - * @var int The dimension of array, must be greater than 0. - */ - private int $dimension = 1; - - /** - * @psalm-param ColumnType::* $type - */ - public function __construct( - string $type = ColumnType::ARRAY, - ) { - parent::__construct($type); - } - - /** - * Set column of an array item. - */ - public function column(ColumnSchemaInterface|null $column): static - { - $this->column = $column; - return $this; - } - - /** - * @return ColumnSchemaInterface the column of an array item. - */ - public function getColumn(): ColumnSchemaInterface - { - if ($this->column === null) { - $this->column = (new ColumnFactory())->fromDbType($this->getDbType() ?? ''); - $this->column->enumValues($this->getEnumValues()); - $this->column->scale($this->getScale()); - $this->column->size($this->getSize()); - } - - return $this->column; - } - - /** - * Set dimension of an array, must be greater than 0. - */ - public function dimension(int $dimension): static - { - $this->dimension = $dimension; - return $this; - } - - /** - * @return int the dimension of the array. - */ - public function getDimension(): int - { - return $this->dimension; - } - - public function getPhpType(): string + protected function getColumnFactory(): ColumnFactoryInterface { - return PhpType::ARRAY; + return new ColumnFactory(); } - public function dbTypecast(mixed $value): ExpressionInterface|null + protected function getParser(): ParserToArrayInterface { - if ($value === null || $value instanceof ExpressionInterface) { - return $value; - } - - if ($this->dimension === 1 && is_array($value)) { - $value = array_map($this->getColumn()->dbTypecast(...), $value); - } else { - $value = $this->dbTypecastArray($value, $this->dimension); - } - - return new ArrayExpression($value, $this->getDbType() ?? $this->getColumn()->getDbType(), $this->dimension); - } - - public function phpTypecast(mixed $value): array|null - { - if (is_string($value)) { - $value = (new ArrayParser())->parse($value); - } - - if (!is_array($value)) { - return null; - } - - if ($this->getType() === ColumnType::STRING) { - return $value; - } - - $column = $this->getColumn(); - - if ($this->dimension === 1 && $column->getType() !== ColumnType::JSON) { - return array_map($column->phpTypecast(...), $value); - } - - array_walk_recursive($value, function (string|null &$val) use ($column): void { - $val = $column->phpTypecast($val); - }); - - return $value; + return new ArrayParser(); } - /** - * Recursively converts array values for use in a db query. - * - * @param mixed $value The array or iterable object. - * @param int $dimension The array dimension. Should be more than 0. - * - * @return array|null Converted values. - */ - private function dbTypecastArray(mixed $value, int $dimension): array|null - { - if ($value === null) { - return null; - } - - if (!is_iterable($value)) { - return []; - } - - if ($dimension <= 1) { - return array_map( - $this->getColumn()->dbTypecast(...), - $value instanceof Traversable - ? iterator_to_array($value, false) - : $value - ); - } - - $items = []; - - foreach ($value as $val) { - $items[] = $this->dbTypecastArray($val, $dimension - 1); - } - - return $items; - } } diff --git a/src/Column/ColumnBuilder.php b/src/Column/ColumnBuilder.php index 4c66a3b42..8778a3b32 100644 --- a/src/Column/ColumnBuilder.php +++ b/src/Column/ColumnBuilder.php @@ -56,12 +56,6 @@ public static function array(ColumnSchemaInterface|null $column = null): ColumnS ->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 $columns - */ public static function structured(string|null $dbType = null, array $columns = []): ColumnSchemaInterface { return (new StructuredColumnSchema(ColumnType::STRUCTURED)) diff --git a/src/Column/ColumnDefinitionBuilder.php b/src/Column/ColumnDefinitionBuilder.php new file mode 100644 index 000000000..e5e3b883f --- /dev/null +++ b/src/Column/ColumnDefinitionBuilder.php @@ -0,0 +1,87 @@ +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::ARRAY => 'jsonb', + ColumnType::STRUCTURED => 'jsonb', + ColumnType::JSON => 'jsonb', + default => 'varchar', + }; + } +} diff --git a/src/Column/ColumnFactory.php b/src/Column/ColumnFactory.php index 8a2c05e81..c36e259fc 100644 --- a/src/Column/ColumnFactory.php +++ b/src/Column/ColumnFactory.php @@ -103,6 +103,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, diff --git a/src/Column/StructuredColumnSchema.php b/src/Column/StructuredColumnSchema.php index 51cee569a..edacb7847 100644 --- a/src/Column/StructuredColumnSchema.php +++ b/src/Column/StructuredColumnSchema.php @@ -4,92 +4,14 @@ namespace Yiisoft\Db\Pgsql\Column; -use Traversable; -use Yiisoft\Db\Constant\ColumnType; -use Yiisoft\Db\Constant\PhpType; -use Yiisoft\Db\Expression\ExpressionInterface; -use Yiisoft\Db\Pgsql\StructuredExpression; use Yiisoft\Db\Pgsql\StructuredParser; -use Yiisoft\Db\Schema\Column\AbstractColumnSchema; -use Yiisoft\Db\Schema\Column\ColumnSchemaInterface; +use Yiisoft\Db\Schema\Column\StructuredColumnSchema as BaseStructuredColumnSchema; +use Yiisoft\Db\Syntax\ParserToArrayInterface; -use function array_keys; -use function is_iterable; -use function is_string; -use function iterator_to_array; - -final class StructuredColumnSchema extends AbstractColumnSchema implements StructuredColumnSchemaInterface +final class StructuredColumnSchema extends BaseStructuredColumnSchema { - /** - * @var ColumnSchemaInterface[] Columns metadata of the composite type. - * @psalm-var array - */ - private array $columns = []; - - /** - * @psalm-param ColumnType::* $type - */ - public function __construct( - string $type = ColumnType::STRUCTURED, - ) { - parent::__construct($type); - } - - public function columns(array $columns): static - { - $this->columns = $columns; - return $this; - } - - public function getColumns(): array - { - return $this->columns; - } - - public function getPhpType(): string + protected function getParser(): ParserToArrayInterface { - return PhpType::ARRAY; - } - - public function dbTypecast(mixed $value): mixed - { - if ($value === null || $value instanceof ExpressionInterface) { - return $value; - } - - return new StructuredExpression($value, $this->getDbType(), $this->columns); - } - - public function phpTypecast(mixed $value): array|null - { - if (is_string($value)) { - $value = (new StructuredParser())->parse($value); - } - - if (!is_iterable($value)) { - return null; - } - - if (empty($this->columns)) { - return $value instanceof Traversable - ? iterator_to_array($value) - : $value; - } - - $fields = []; - $columnNames = array_keys($this->columns); - - /** @psalm-var int|string $columnName */ - foreach ($value as $columnName => $item) { - $columnName = $columnNames[$columnName] ?? $columnName; - - if (isset($this->columns[$columnName])) { - $fields[$columnName] = $this->columns[$columnName]->phpTypecast($item); - } else { - $fields[$columnName] = $item; - } - } - - return $fields; + return new StructuredParser(); } } diff --git a/src/Column/StructuredColumnSchemaInterface.php b/src/Column/StructuredColumnSchemaInterface.php deleted file mode 100644 index 35db4ce2a..000000000 --- a/src/Column/StructuredColumnSchemaInterface.php +++ /dev/null @@ -1,25 +0,0 @@ - $columns - */ - public function columns(array $columns): static; - - /** - * Get the metadata of the composite type columns. - * - * @return ColumnSchemaInterface[] - */ - public function getColumns(): array; -} diff --git a/src/Connection.php b/src/Connection.php index 99929eda7..46b57fc43 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -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; @@ -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) { diff --git a/src/DDLQueryBuilder.php b/src/DDLQueryBuilder.php index ad96a5627..de4442fc9 100644 --- a/src/DDLQueryBuilder.php +++ b/src/DDLQueryBuilder.php @@ -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); diff --git a/src/DQLQueryBuilder.php b/src/DQLQueryBuilder.php index 5ad9578a9..a41acd8a7 100644 --- a/src/DQLQueryBuilder.php +++ b/src/DQLQueryBuilder.php @@ -8,6 +8,7 @@ use Yiisoft\Db\Expression\Expression; use Yiisoft\Db\Expression\ExpressionBuilderInterface; use Yiisoft\Db\Expression\JsonExpression; +use Yiisoft\Db\Expression\StructuredExpression; use Yiisoft\Db\Pgsql\Builder\ArrayExpressionBuilder; use Yiisoft\Db\Pgsql\Builder\ArrayOverlapsConditionBuilder; use Yiisoft\Db\Pgsql\Builder\JsonOverlapsConditionBuilder; diff --git a/src/QueryBuilder.php b/src/QueryBuilder.php index 7766181a8..e667c9527 100644 --- a/src/QueryBuilder.php +++ b/src/QueryBuilder.php @@ -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; @@ -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); } } diff --git a/src/Schema.php b/src/Schema.php index 341d73050..cbf61bfab 100644 --- a/src/Schema.php +++ b/src/Schema.php @@ -19,10 +19,12 @@ 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\Column\StructuredColumnSchemaInterface; use Yiisoft\Db\Schema\TableSchemaInterface; use function array_change_key_case; @@ -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). * @@ -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)) { diff --git a/src/StructuredExpression.php b/src/StructuredExpression.php deleted file mode 100644 index 74ea76b6e..000000000 --- a/src/StructuredExpression.php +++ /dev/null @@ -1,104 +0,0 @@ - 10, 'currency_code' => 'USD']); - * ``` - * - * Will be encoded to `ROW(10, USD)` - */ -class StructuredExpression implements ExpressionInterface -{ - /** - * @param ColumnSchemaInterface[] $columns - * @psalm-param array $columns - */ - public function __construct( - private mixed $value, - private string|null $type = null, - private array $columns = [], - ) { - } - - /** - * The structured type name. - * - * Defaults to `null` which means the type is not explicitly specified. - * - * Note that in the case where a type is not specified explicitly and DBMS cannot guess it from the context, - * SQL error will be raised. - */ - public function getType(): string|null - { - return $this->type; - } - - /** - * The structured type columns that are used for value normalization and type casting. - * - * @return ColumnSchemaInterface[] - */ - public function getColumns(): array - { - return $this->columns; - } - - /** - * The content of the structured type. It can be represented as an associative array of structured type column names - * and values. - */ - public function getValue(): mixed - { - return $this->value; - } - - /** - * Sorted values according to the order of structured type columns, - * indexed keys are replaced with column names, - * missing elements are filled in with default values, - * excessive elements are removed. - */ - public function getNormalizedValue(): mixed - { - if (empty($this->columns) || !is_iterable($this->value)) { - return $this->value; - } - - $normalized = []; - $value = $this->value; - $columnsNames = array_keys($this->columns); - - if ($value instanceof Traversable) { - $value = iterator_to_array($value); - } - - foreach ($columnsNames as $i => $columnsName) { - $normalized[$columnsName] = match (true) { - array_key_exists($columnsName, $value) => $value[$columnsName], - array_key_exists($i, $value) => $value[$i], - default => $this->columns[$columnsName]->getDefaultValue(), - }; - } - - return $normalized; - } -} diff --git a/src/StructuredParser.php b/src/StructuredParser.php index 0327904d3..ab765cdff 100644 --- a/src/StructuredParser.php +++ b/src/StructuredParser.php @@ -4,17 +4,17 @@ namespace Yiisoft\Db\Pgsql; +use Yiisoft\Db\Syntax\ParserToArrayInterface; + use function in_array; /** * Structured type representation to PHP array parser for PostgreSQL Server. */ -final class StructuredParser +final class StructuredParser implements ParserToArrayInterface { /** * Converts structured (composite) type value from PostgreSQL to PHP array - * - * @param string $value String to convert. */ public function parse(string $value): array|null { diff --git a/tests/ArrayParserTest.php b/tests/ArrayParserTest.php index 829576684..57bbefdea 100644 --- a/tests/ArrayParserTest.php +++ b/tests/ArrayParserTest.php @@ -18,7 +18,6 @@ public function testParser(): void { $arrayParse = new ArrayParser(); - $this->assertNull($arrayParse->parse(null)); $this->assertSame([0 => null, 1 => null], $arrayParse->parse('{NULL,NULL}')); $this->assertSame([], $arrayParse->parse('{}')); $this->assertSame([0 => null, 1 => null], $arrayParse->parse('{,}')); diff --git a/tests/ColumnSchemaTest.php b/tests/ColumnSchemaTest.php index 7d2ad8491..745acf1bc 100644 --- a/tests/ColumnSchemaTest.php +++ b/tests/ColumnSchemaTest.php @@ -16,9 +16,11 @@ 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\Tests\Support\TestTrait; use Yiisoft\Db\Query\Query; +use Yiisoft\Db\Schema\Column\ColumnSchemaInterface; use Yiisoft\Db\Schema\Column\DoubleColumnSchema; use Yiisoft\Db\Schema\Column\JsonColumnSchema; use Yiisoft\Db\Schema\Column\StringColumnSchema; @@ -116,6 +118,8 @@ public function testDbTypeCastJson(): void $this->assertEquals(new JsonExpression('', 'json'), $tableSchema->getColumn('json_col')->dbTypecast('')); $this->assertEquals(new JsonExpression('', 'jsonb'), $tableSchema->getColumn('jsonb_col')->dbTypecast('')); + + $db->close(); } public function testBoolDefault(): void @@ -195,6 +199,8 @@ public function testPrimaryKeyOfView() $this->assertFalse($tableSchema->getColumn('C_index_1')->isPrimaryKey()); $this->assertFalse($tableSchema->getColumn('C_index_2_1')->isPrimaryKey()); $this->assertFalse($tableSchema->getColumn('C_index_2_2')->isPrimaryKey()); + + $db->close(); } public function testStructuredType(): void @@ -290,6 +296,8 @@ public function testColumnSchemaInstance() $this->assertInstanceOf(ArrayColumnSchema::class, $tableSchema->getColumn('intarray_col')); $this->assertInstanceOf(IntegerColumnSchema::class, $tableSchema->getColumn('intarray_col')->getColumn()); $this->assertInstanceOf(JsonColumnSchema::class, $tableSchema->getColumn('json_col')); + + $db->close(); } /** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnSchemaProvider::predefinedTypes */ @@ -304,41 +312,10 @@ public function testDbTypecastColumns(string $className, array $values) parent::testDbTypecastColumns($className, $values); } - /** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnSchemaProvider::phpTypecastColumns */ - public function testPhpTypecastColumns(string $className, array $values) - { - parent::testPhpTypecastColumns($className, $values); - } - - /** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnSchemaProvider::dbTypecastArrayColumns */ - public function testDbTypecastArrayColumnSchema(string $dbType, string $type, array $values): void - { - $db = $this->getConnection(); - $columnFactory = $db->getColumnFactory(); - - $arrayCol = (new ArrayColumnSchema())->column($columnFactory->fromType($type)->dbType($dbType)); - - foreach ($values as [$dimension, $expected, $value]) { - $arrayCol->dimension($dimension); - $dbValue = $arrayCol->dbTypecast($value); - - $this->assertInstanceOf(ArrayExpression::class, $dbValue); - $this->assertSame($dbType, $dbValue->getType()); - $this->assertSame($dimension, $dbValue->getDimension()); - - if (is_object($expected)) { - $this->assertEquals($expected, $dbValue->getValue()); - } - } - } - /** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnSchemaProvider::phpTypecastArrayColumns */ - public function testPhpTypecastArrayColumnSchema(string $dbType, string $type, array $values): void + public function testPhpTypecastArrayColumnSchema(ColumnSchemaInterface $column, array $values): void { - $db = $this->getConnection(); - $columnFactory = $db->getColumnFactory(); - - $arrayCol = (new ArrayColumnSchema())->column($columnFactory->fromType($type)->dbType($dbType)); + $arrayCol = ColumnBuilder::array($column); foreach ($values as [$dimension, $expected, $value]) { $arrayCol->dimension($dimension); @@ -371,33 +348,4 @@ public function testBigIntColumnSchema() $this->assertNull($bigintCol->getSequenceName()); } - - public function testArrayColumnSchema() - { - $arrayCol = new ArrayColumnSchema(); - - $this->assertSame(1, $arrayCol->getDimension()); - - $this->assertNull($arrayCol->dbTypecast(null)); - $this->assertEquals(new ArrayExpression([]), $arrayCol->dbTypecast('')); - $this->assertSame($expression = new Expression('expression'), $arrayCol->dbTypecast($expression)); - $this->assertNull($arrayCol->phpTypecast(null)); - - $arrayCol->dimension(2); - $this->assertSame(2, $arrayCol->getDimension()); - } - - public function testArrayColumnSchemaColumn(): void - { - $arrayCol = new ArrayColumnSchema(); - $intCol = new IntegerColumnSchema(); - - $this->assertInstanceOf(StringColumnSchema::class, $arrayCol->getColumn()); - $this->assertSame($arrayCol, $arrayCol->column($intCol)); - $this->assertSame($intCol, $arrayCol->getColumn()); - - $arrayCol->column(null); - - $this->assertInstanceOf(StringColumnSchema::class, $arrayCol->getColumn()); - } } diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php index 1f181e5b0..cb8290a3e 100644 --- a/tests/ConnectionTest.php +++ b/tests/ConnectionTest.php @@ -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; @@ -134,11 +133,4 @@ static function (ConnectionInterface $db) { $db->close(); } - - public function testGetColumnFactory(): void - { - $db = $this->getConnection(); - - $this->assertInstanceOf(ColumnFactory::class, $db->getColumnFactory()); - } } diff --git a/tests/PdoCommandTest.php b/tests/PdoCommandTest.php index af9a86ef9..85a44bd4d 100644 --- a/tests/PdoCommandTest.php +++ b/tests/PdoCommandTest.php @@ -53,6 +53,8 @@ public function testInsertAndReadToArrayColumn(): void $columnSchema = $db->getTableSchema('{{%table_with_array_col}}')->getColumn('array_col'); $this->assertSame($arrValue, $columnSchema->phpTypecast($selectData['array_col'])); + + $db->close(); } public function testCommandLogging(): void diff --git a/tests/Provider/ColumnBuilderProvider.php b/tests/Provider/ColumnBuilderProvider.php index 078af75ef..248e629d0 100644 --- a/tests/Provider/ColumnBuilderProvider.php +++ b/tests/Provider/ColumnBuilderProvider.php @@ -19,54 +19,45 @@ class ColumnBuilderProvider extends \Yiisoft\Db\Tests\Provider\ColumnBuilderProv { 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], - ], - ]; + $values = parent::buildingMethods(); + + $values['primaryKey()'][2] = IntegerColumnSchema::class; + $values['primaryKey(false)'][2] = IntegerColumnSchema::class; + $values['smallPrimaryKey()'][2] = IntegerColumnSchema::class; + $values['smallPrimaryKey(false)'][2] = IntegerColumnSchema::class; + $values['bigPrimaryKey()'][2] = IntegerColumnSchema::class; + $values['bigPrimaryKey(false)'][2] = IntegerColumnSchema::class; + $values['boolean()'][2] = BooleanColumnSchema::class; + $values['bit()'][2] = BitColumnSchema::class; + $values['bit(1)'][2] = BitColumnSchema::class; + $values['tinyint()'][2] = IntegerColumnSchema::class; + $values['tinyint(1)'][2] = IntegerColumnSchema::class; + $values['smallint()'][2] = IntegerColumnSchema::class; + $values['smallint(1)'][2] = IntegerColumnSchema::class; + $values['integer()'][2] = IntegerColumnSchema::class; + $values['integer(1)'][2] = IntegerColumnSchema::class; + $values['bigint()'][2] = IntegerColumnSchema::class; + $values['bigint(1)'][2] = IntegerColumnSchema::class; + $values['float()'][2] = DoubleColumnSchema::class; + $values['float(8)'][2] = DoubleColumnSchema::class; + $values['float(8,2)'][2] = DoubleColumnSchema::class; + $values['double()'][2] = DoubleColumnSchema::class; + $values['double(8)'][2] = DoubleColumnSchema::class; + $values['double(8,2)'][2] = DoubleColumnSchema::class; + $values['decimal()'][2] = DoubleColumnSchema::class; + $values['decimal(8)'][2] = DoubleColumnSchema::class; + $values['decimal(8,2)'][2] = DoubleColumnSchema::class; + $values['money()'][2] = DoubleColumnSchema::class; + $values['money(8)'][2] = DoubleColumnSchema::class; + $values['money(8,2)'][2] = DoubleColumnSchema::class; + $values['binary()'][2] = BinaryColumnSchema::class; + $values['binary(8)'][2] = BinaryColumnSchema::class; + $values['array()'][2] = ArrayColumnSchema::class; + $values['array($column)'][2] = ArrayColumnSchema::class; + $values['structured()'][2] = StructuredColumnSchema::class; + $values["structured('money_currency')"][2] = StructuredColumnSchema::class; + $values["structured('money_currency',\$columns)"][2] = StructuredColumnSchema::class; + + return $values; } } diff --git a/tests/Provider/ColumnSchemaProvider.php b/tests/Provider/ColumnSchemaProvider.php index 063a5885d..3bc02ace7 100644 --- a/tests/Provider/ColumnSchemaProvider.php +++ b/tests/Provider/ColumnSchemaProvider.php @@ -4,19 +4,13 @@ namespace Yiisoft\Db\Pgsql\Tests\Provider; -use PDO; -use Yiisoft\Db\Command\Param; -use Yiisoft\Db\Constant\ColumnType; use Yiisoft\Db\Expression\Expression; -use Yiisoft\Db\Expression\JsonExpression; use Yiisoft\Db\Pgsql\Column\BigIntColumnSchema; 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\StructuredExpression; - -use function fopen; class ColumnSchemaProvider extends \Yiisoft\Db\Tests\Provider\ColumnSchemaProvider { @@ -87,141 +81,12 @@ public static function phpTypecastColumns(): array return $values; } - public static function dbTypecastArrayColumns() - { - $bigInt = PHP_INT_SIZE === 8 ? 9223372036854775807 : '9223372036854775807'; - - return [ - // [dbType, type, values] - [ - 'int4', - ColumnType::INTEGER, - [ - // [dimension, expected, typecast value] - [1, [1, 2, 3, null], [1, 2.0, '3', null]], - [2, [[1, 2], [3], null], [[1, 2.0], ['3'], null]], - [2, [null, null], [null, null]], - ], - ], - [ - 'int8', - ColumnType::BIGINT, - [ - [1, [1, 2, 3, $bigInt], [1, 2.0, '3', '9223372036854775807']], - [2, [[1, 2], [3], [$bigInt]], [[1, 2.0], ['3'], ['9223372036854775807']]], - ], - ], - [ - 'float8', - ColumnType::DOUBLE, - [ - [1, [1.0, 2.2, 3.3, null], [1, 2.2, '3.3', null]], - [2, [[1.0, 2.2], [3.3, null]], [[1, 2.2], ['3.3', null]]], - ], - ], - [ - 'bool', - ColumnType::BOOLEAN, - [ - [1, [true, true, true, false, false, false, null], [true, 1, '1', false, 0, '0', null]], - [2, [[true, true, true, false, false, false, null]], [[true, 1, '1', false, 0, '0', null]]], - ], - ], - [ - 'varchar', - ColumnType::STRING, - [ - [1, ['1', '2', '1', '0', '', null], [1, '2', true, false, '', null]], - [2, [['1', '2', '1', '0'], [''], [null]], [[1, '2', true, false], [''], [null]]], - ], - ], - [ - 'bytea', - ColumnType::BINARY, - [ - [1, [ - '1', - new Param("\x10", PDO::PARAM_LOB), - $resource = fopen('php://memory', 'rb'), - null, - ], [1, "\x10", $resource, null]], - [2, [[ - '1', - new Param("\x10", PDO::PARAM_LOB), - $resource = fopen('php://memory', 'rb'), - null, - ]], [[1, "\x10", $resource, null]]], - ], - ], - [ - 'jsonb', - ColumnType::JSON, - [ - [1, [ - new JsonExpression([1, 2, 3], 'jsonb'), - new JsonExpression(['key' => 'value'], 'jsonb'), - new JsonExpression(['key' => 'value']), - null, - ], [[1, 2, 3], ['key' => 'value'], new JsonExpression(['key' => 'value']), null]], - [2, [ - [ - new JsonExpression([1, 2, 3], 'jsonb'), - new JsonExpression(['key' => 'value'], 'jsonb'), - new JsonExpression(['key' => 'value']), - null, - ], - null, - ], [[[1, 2, 3], ['key' => 'value'], new JsonExpression(['key' => 'value']), null], null]], - ], - ], - [ - 'varbit', - ColumnType::BIT, - [ - [1, ['1011', '1001', null], [0b1011, '1001', null]], - [2, [['1011', '1001', null]], [[0b1011, '1001', null]]], - ], - ], - [ - 'price_composite', - ColumnType::STRUCTURED, - [ - [ - 1, - [ - new StructuredExpression(['value' => 10, 'currency' => 'USD'], 'price_composite'), - null, - ], - [ - ['value' => 10, 'currency' => 'USD'], - null, - ], - ], - [ - 2, - [[ - new StructuredExpression(['value' => 10, 'currency' => 'USD'], 'price_composite'), - null, - ]], - [[ - ['value' => 10, 'currency' => 'USD'], - null, - ]], - ], - ], - ], - ]; - } - public static function phpTypecastArrayColumns() { - $bigInt = PHP_INT_SIZE === 8 ? 9223372036854775807 : '9223372036854775807'; - return [ - // [dbtype, type, values] + // [column, values] [ - 'int4', - ColumnType::INTEGER, + ColumnBuilder::integer(), [ // [dimension, expected, typecast value] [1, [1, 2, 3, null], '{1,2,3,}'], @@ -229,48 +94,42 @@ public static function phpTypecastArrayColumns() ], ], [ - 'int8', - ColumnType::BIGINT, + new BigIntColumnSchema(), [ - [1, [1, 2, $bigInt], '{1,2,9223372036854775807}'], - [2, [[1, 2], [$bigInt]], '{{1,2},{9223372036854775807}}'], + [1, ['1', '2', '9223372036854775807'], '{1,2,9223372036854775807}'], + [2, [['1', '2'], ['9223372036854775807']], '{{1,2},{9223372036854775807}}'], ], ], [ - 'float8', - ColumnType::DOUBLE, + ColumnBuilder::double(), [ [1, [1.0, 2.2, null], '{1,2.2,}'], [2, [[1.0], [2.2, null]], '{{1},{2.2,}}'], ], ], [ - 'bool', - ColumnType::BOOLEAN, + ColumnBuilder::boolean(), [ [1, [true, false, null], '{t,f,}'], [2, [[true, false, null]], '{{t,f,}}'], ], ], [ - 'varchar', - ColumnType::STRING, + ColumnBuilder::string(), [ [1, ['1', '2', '', null], '{1,2,"",}'], [2, [['1', '2'], [''], [null]], '{{1,2},{""},{NULL}}'], ], ], [ - 'bytea', - ColumnType::BINARY, + ColumnBuilder::binary(), [ [1, ["\x10\x11", '', null], '{\x1011,"",}'], [2, [["\x10\x11"], ['', null]], '{{\x1011},{"",}}'], ], ], [ - 'jsonb', - ColumnType::JSON, + ColumnBuilder::json(), [ [1, [[1, 2, 3], null], '{"[1,2,3]",}'], [1, [[1, 2, 3]], '{{1,2,3}}'], @@ -278,16 +137,14 @@ public static function phpTypecastArrayColumns() ], ], [ - 'varbit', - ColumnType::BIT, + ColumnBuilder::bit(), [ [1, [0b1011, 0b1001, null], '{1011,1001,}'], [2, [[0b1011, 0b1001, null]], '{{1011,1001,}}'], ], ], [ - 'price_structured', - ColumnType::STRUCTURED, + ColumnBuilder::structured(), [ [1, [['10', 'USD'], null], '{"(10,USD)",}'], [2, [[['10', 'USD'], null]], '{{"(10,USD)",}}'], diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index d13c9e51f..2171b25c1 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -5,11 +5,12 @@ 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; -use Yiisoft\Db\Pgsql\StructuredExpression; -use Yiisoft\Db\Pgsql\Tests\Support\ColumnSchemaBuilder; +use Yiisoft\Db\Expression\StructuredExpression; +use Yiisoft\Db\Pgsql\Column\ColumnBuilder; use Yiisoft\Db\Pgsql\Tests\Support\TestTrait; use Yiisoft\Db\Query\Query; use Yiisoft\Db\Tests\Support\TraversableObject; @@ -27,8 +28,8 @@ public static function buildCondition(): array $buildCondition = parent::buildCondition(); $priceColumns = [ - 'value' => ColumnSchemaBuilder::numeric(name: 'value', size: 10, scale: 2), - 'currency_code' => ColumnSchemaBuilder::char(name: 'currency_code', size: 3), + 'value' => ColumnBuilder::money(10, 2), + 'currency_code' => ColumnBuilder::char(3), ]; return array_merge( @@ -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; + } } diff --git a/tests/Provider/StructuredTypeProvider.php b/tests/Provider/StructuredTypeProvider.php index 121ae80f7..77dc30b16 100644 --- a/tests/Provider/StructuredTypeProvider.php +++ b/tests/Provider/StructuredTypeProvider.php @@ -8,7 +8,7 @@ use Yiisoft\Db\Pgsql\Tests\Support\ColumnSchemaBuilder; use Yiisoft\Db\Tests\Support\TraversableObject; -final class StructuredTypeProvider extends \Yiisoft\Db\Tests\Provider\SchemaProvider +final class StructuredTypeProvider { public static function columns(): array { @@ -283,60 +283,4 @@ public static function columns(): array ], ]; } - - public static function normolizedValues() - { - $price5UsdColumns = [ - 'value' => ColumnSchemaBuilder::numeric(name: 'value', size: 10, scale: 2, defaultValue: 5.0), - 'currency_code' => ColumnSchemaBuilder::char(name: 'currency_code', size: 3, defaultValue: 'USD'), - ]; - - return [ - 'Sort according to `$columns` order' => [ - ['currency_code' => 'USD', 'value' => 10.0], - ['value' => 10.0, 'currency_code' => 'USD'], - $price5UsdColumns, - ], - 'Remove excessive elements' => [ - ['value' => 10.0, 'currency_code' => 'USD', 'excessive' => 'element'], - ['value' => 10.0, 'currency_code' => 'USD'], - $price5UsdColumns, - ], - 'Fill default values for skipped fields' => [ - ['currency_code' => 'CNY'], - ['value' => 5.0, 'currency_code' => 'CNY'], - $price5UsdColumns, - ], - 'Fill default values and column names for skipped indexed fields' => [ - [10.0], - ['value' => 10.0, 'currency_code' => 'USD'], - $price5UsdColumns, - ], - 'Fill default values and column names for iterable object' => [ - new TraversableObject([10.0]), - ['value' => 10.0, 'currency_code' => 'USD'], - $price5UsdColumns, - ], - 'Fill default values for iterable object' => [ - new ArrayIterator(['currency_code' => 'CNY']), - ['value' => 5.0, 'currency_code' => 'CNY'], - $price5UsdColumns, - ], - 'Fill default values for empty array' => [ - [], - ['value' => 5.0, 'currency_code' => 'USD'], - $price5UsdColumns, - ], - 'Do not normalize scalar values' => [ - 1, - 1, - $price5UsdColumns, - ], - 'Do not normalize with empty columns' => [ - [10.0], - [10.0], - [], - ], - ]; - } } diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index 316ea1f2e..4566c2069 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -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; @@ -433,6 +434,8 @@ public function testDropDefaultValue(): void ); $qb->dropDefaultValue('T_constraints_1', 'CN_pk'); + + $db->close(); } /** @@ -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); + } } diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index fb3243dcb..3735187c9 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -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; @@ -516,6 +517,8 @@ public function testCustomTypeInNonDefaultSchema() $schema = $db->getSchema()->getTableSchema('schema2.custom_type_test_table'); $this->assertEquals('my_type', $schema->getColumn('test_type')->getDbType()); $this->assertEquals('schema2.my_type2', $schema->getColumn('test_type2')->getDbType()); + + $db->close(); } public function testNotConnectionPDO(): void @@ -643,5 +646,16 @@ public function testTableIndexes(): void $this->assertSame(['non_unique_index'], $tableIndexes[4]->getColumnNames()); $this->assertFalse($tableIndexes[4]->isPrimary()); $this->assertFalse($tableIndexes[4]->isUnique()); + + $db->close(); + } + + public function testGetColumnFactory(): void + { + $db = $this->getConnection(); + + $this->assertInstanceOf(ColumnFactory::class, $db->getSchema()->getColumnFactory()); + + $db->close(); } } diff --git a/tests/StructuredExpressionTest.php b/tests/StructuredExpressionTest.php deleted file mode 100644 index 5949f67bd..000000000 --- a/tests/StructuredExpressionTest.php +++ /dev/null @@ -1,24 +0,0 @@ -assertSame($expected, $structuredExpression->getNormalizedValue()); - } -} diff --git a/tests/Support/ColumnSchemaBuilder.php b/tests/Support/ColumnSchemaBuilder.php deleted file mode 100644 index 695e10db2..000000000 --- a/tests/Support/ColumnSchemaBuilder.php +++ /dev/null @@ -1,36 +0,0 @@ -name($name); - $column->dbType('numeric'); - $column->size($size); - $column->scale($scale); - $column->defaultValue($defaultValue); - - return $column; - } - - public static function char(string $name, int|null $size, mixed $defaultValue = null): ColumnSchemaInterface - { - $column = new StringColumnSchema(ColumnType::CHAR); - $column->name($name); - $column->dbType('bpchar'); - $column->size($size); - $column->defaultValue($defaultValue); - - return $column; - } -} From 0bc6495baaf471276404b69ad0e84401ca5ad2f5 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Wed, 9 Oct 2024 09:27:40 +0700 Subject: [PATCH 2/5] Fix after merge --- tests/ColumnFactoryTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ColumnFactoryTest.php b/tests/ColumnFactoryTest.php index dc014ad56..8df2d5319 100644 --- a/tests/ColumnFactoryTest.php +++ b/tests/ColumnFactoryTest.php @@ -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]); @@ -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]); From 1938df150dfeeae1e5319405b6f1d6ba257b8501 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Wed, 9 Oct 2024 10:31:54 +0700 Subject: [PATCH 3/5] Remove unused `type -> dbType` conversion --- src/Column/ColumnDefinitionBuilder.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Column/ColumnDefinitionBuilder.php b/src/Column/ColumnDefinitionBuilder.php index e5e3b883f..a86d7f17c 100644 --- a/src/Column/ColumnDefinitionBuilder.php +++ b/src/Column/ColumnDefinitionBuilder.php @@ -78,7 +78,6 @@ protected function getDbType(ColumnSchemaInterface $column): string ColumnType::TIMESTAMP => 'timestamp', ColumnType::DATE => 'date', ColumnType::TIME => 'time', - ColumnType::ARRAY => 'jsonb', ColumnType::STRUCTURED => 'jsonb', ColumnType::JSON => 'jsonb', default => 'varchar', From e087c6b6d2de92cc5f34b61c111ef4f13e64d719 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Wed, 9 Oct 2024 12:06:01 +0700 Subject: [PATCH 4/5] Remove `CLAUSES` constant --- src/Column/ColumnDefinitionBuilder.php | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Column/ColumnDefinitionBuilder.php b/src/Column/ColumnDefinitionBuilder.php index a86d7f17c..0bf498b6f 100644 --- a/src/Column/ColumnDefinitionBuilder.php +++ b/src/Column/ColumnDefinitionBuilder.php @@ -10,17 +10,6 @@ final class ColumnDefinitionBuilder extends AbstractColumnDefinitionBuilder { - protected const CLAUSES = [ - 'type', - 'not_null', - 'primary_key', - 'unique', - 'default', - 'check', - 'references', - 'extra', - ]; - protected const GENERATE_UUID_EXPRESSION = 'gen_random_uuid()'; protected const TYPES_WITH_SIZE = [ @@ -46,6 +35,18 @@ final class ColumnDefinitionBuilder extends AbstractColumnDefinitionBuilder '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) { From 4ad0473c6dfd8a34417b9b1fe6b7728ce2ffcdc9 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Fri, 11 Oct 2024 09:50:16 +0700 Subject: [PATCH 5/5] Add line to CHANGELOG.md [skip ci] --- CHANGELOG.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44680c41e..7eac161d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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