diff --git a/CHANGELOG.md b/CHANGELOG.md index 8012aa30d..094958f1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## 1.1.1 under development -- no changes in this release. +- Enh #301: Refactor `JsonExpressionBuilder` (@Tigrov) +- Enh #300: Refactor `ArrayExpressionBuilder` (@Tigrov) +- Enh #302: Refactor `ColumnSchema` (@Tigrov) +- Bug #302: Fix incorrect convert string value for BIT type (@Tigrov) ## 1.1.0 July 24, 2023 diff --git a/src/Builder/ArrayExpressionBuilder.php b/src/Builder/ArrayExpressionBuilder.php index 21a35092e..66b5f634a 100644 --- a/src/Builder/ArrayExpressionBuilder.php +++ b/src/Builder/ArrayExpressionBuilder.php @@ -4,7 +4,6 @@ namespace Yiisoft\Db\Pgsql\Builder; -use Traversable; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidConfigException; @@ -19,7 +18,7 @@ use function implode; use function in_array; -use function is_array; +use function is_iterable; use function str_repeat; /** @@ -34,7 +33,7 @@ public function __construct(private QueryBuilderInterface $queryBuilder) /** * The Method builds the raw SQL from the expression that won't be additionally escaped or quoted. * - * @param ExpressionInterface $expression The expression build. + * @param ArrayExpression $expression The expression build. * @param array $params The binding parameters. * * @throws Exception @@ -43,8 +42,6 @@ public function __construct(private QueryBuilderInterface $queryBuilder) * @throws NotSupportedException * * @return string The raw SQL that won't be additionally escaped or quoted. - * - * @psalm-param ArrayExpression $expression */ public function build(ExpressionInterface $expression, array &$params = []): string { @@ -63,7 +60,7 @@ public function build(ExpressionInterface $expression, array &$params = []): str /** @psalm-var string[] $placeholders */ $placeholders = $this->buildPlaceholders($expression, $params); - return 'ARRAY[' . implode(', ', $placeholders) . ']' . $this->getTypehint($expression); + return 'ARRAY[' . implode(', ', $placeholders) . ']' . $this->getTypeHint($expression); } /** @@ -75,22 +72,20 @@ public function build(ExpressionInterface $expression, array &$params = []): str * @throws InvalidArgumentException * @throws InvalidConfigException * @throws NotSupportedException - * - * @psalm-param ArrayExpression $expression */ - protected function buildPlaceholders(ExpressionInterface $expression, array &$params): array + private function buildPlaceholders(ArrayExpression $expression, array &$params): array { $placeholders = []; /** @psalm-var mixed $value */ $value = $expression->getValue(); - if (!is_array($value) && !$value instanceof Traversable) { + if (!is_iterable($value)) { return $placeholders; } if ($expression->getDimension() > 1) { - /** @psalm-var ExpressionInterface|int $item */ + /** @psalm-var mixed $item */ foreach ($value as $item) { $placeholders[] = $this->build($this->unnestArrayExpression($expression, $item), $params); } @@ -109,10 +104,9 @@ protected function buildPlaceholders(ExpressionInterface $expression, array &$pa if ($item instanceof ExpressionInterface) { $placeholders[] = $this->queryBuilder->buildExpression($item, $params); - continue; + } else { + $placeholders[] = $this->queryBuilder->bindParam($item, $params); } - - $placeholders[] = $this->queryBuilder->bindParam($item, $params); } return $placeholders; @@ -126,7 +120,7 @@ private function unnestArrayExpression(ArrayExpression $expression, mixed $value /** * @return string The typecast expression based on {@see type}. */ - protected function getTypeHint(ArrayExpression $expression): string + private function getTypeHint(ArrayExpression $expression): string { $type = $expression->getType(); @@ -135,10 +129,8 @@ protected function getTypeHint(ArrayExpression $expression): string } $dimension = $expression->getDimension(); - $result = '::' . $type; - $result .= str_repeat('[]', $dimension); - return $result; + return '::' . $type . str_repeat('[]', $dimension); } /** @@ -149,7 +141,7 @@ protected function getTypeHint(ArrayExpression $expression): string * * @return string The sub-query array expression. */ - protected function buildSubqueryArray(string $sql, ArrayExpression $expression): string + private function buildSubqueryArray(string $sql, ArrayExpression $expression): string { return 'ARRAY(' . $sql . ')' . $this->getTypeHint($expression); } @@ -157,7 +149,7 @@ protected function buildSubqueryArray(string $sql, ArrayExpression $expression): /** * @return array|bool|ExpressionInterface|float|int|JsonExpression|string|null The cast value or expression. */ - protected function typecastValue( + private function typecastValue( ArrayExpression $expression, array|bool|float|int|string|ExpressionInterface|null $value ): array|bool|float|int|string|JsonExpression|ExpressionInterface|null { diff --git a/src/Builder/JsonExpressionBuilder.php b/src/Builder/JsonExpressionBuilder.php index f8562eebb..e86fda354 100644 --- a/src/Builder/JsonExpressionBuilder.php +++ b/src/Builder/JsonExpressionBuilder.php @@ -29,7 +29,7 @@ public function __construct(private QueryBuilderInterface $queryBuilder) /** * The Method builds the raw SQL from the $expression that won't be additionally escaped or quoted. * - * @param ExpressionInterface $expression The expression to build. + * @param JsonExpression $expression The expression to build. * @param array $params The binding parameters. * * @throws Exception @@ -39,19 +39,15 @@ public function __construct(private QueryBuilderInterface $queryBuilder) * @throws NotSupportedException * * @return string The raw SQL that won't be additionally escaped or quoted. - * - * @psalm-param JsonExpression $expression */ public function build(ExpressionInterface $expression, array &$params = []): string { - /** - * @psalm-var array|mixed|QueryInterface $value - */ + /** @psalm-var mixed $value */ $value = $expression->getValue(); if ($value instanceof QueryInterface) { [$sql, $params] = $this->queryBuilder->build($value, $params); - return "($sql)" . $this->getTypecast($expression); + return "($sql)" . $this->getTypeHint($expression); } if ($value instanceof ArrayExpression) { @@ -60,13 +56,13 @@ public function build(ExpressionInterface $expression, array &$params = []): str $placeholder = $this->queryBuilder->bindParam(Json::encode($value), $params); } - return $placeholder . $this->getTypecast($expression); + return $placeholder . $this->getTypeHint($expression); } /** * @return string The typecast expression based on {@see JsonExpression::getType()}. */ - protected function getTypecast(JsonExpression $expression): string + private function getTypeHint(JsonExpression $expression): string { $type = $expression->getType(); diff --git a/src/ColumnSchema.php b/src/ColumnSchema.php index a40a6ab78..db39d788b 100644 --- a/src/ColumnSchema.php +++ b/src/ColumnSchema.php @@ -65,8 +65,7 @@ final class ColumnSchema extends AbstractColumnSchema * * @param mixed $value input value * - * @return mixed Converted value. This may also be an array containing the value as the first element and the PDO - * type as the second element. + * @return mixed Converted value. */ public function dbTypecast(mixed $value): mixed { @@ -87,7 +86,7 @@ public function dbTypecast(mixed $value): mixed Schema::TYPE_BIT => is_int($value) ? str_pad(decbin($value), (int) $this->getSize(), '0', STR_PAD_LEFT) - : $this->typecast($value), + : (string) $value, default => $this->typecast($value), }; @@ -111,15 +110,15 @@ public function phpTypecast(mixed $value): mixed $value = $this->getArrayParser()->parse($value); } - if (is_array($value)) { - array_walk_recursive($value, function (string|null &$val) { - /** @psalm-var mixed $val */ - $val = $this->phpTypecastValue($val); - }); - } else { + if (!is_array($value)) { return null; } + array_walk_recursive($value, function (mixed &$val) { + /** @psalm-var mixed $val */ + $val = $this->phpTypecastValue($val); + }); + return $value; } @@ -131,7 +130,7 @@ public function phpTypecast(mixed $value): mixed * * @throws JsonException */ - protected function phpTypecastValue(mixed $value): mixed + private function phpTypecastValue(mixed $value): mixed { if ($value === null) { return null; @@ -152,7 +151,7 @@ protected function phpTypecastValue(mixed $value): mixed /** * Creates instance of ArrayParser. */ - protected function getArrayParser(): ArrayParser + private function getArrayParser(): ArrayParser { return new ArrayParser(); } diff --git a/tests/ColumnSchemaTest.php b/tests/ColumnSchemaTest.php index 01b8ed031..2c8195acb 100644 --- a/tests/ColumnSchemaTest.php +++ b/tests/ColumnSchemaTest.php @@ -188,4 +188,13 @@ public function testNegativeDefaultValues() $this->assertSame(-12345.6789, $tableSchema->getColumn('float_col')->getDefaultValue()); $this->assertSame(-33.22, $tableSchema->getColumn('numeric_col')->getDefaultValue()); } + + public function testDbTypeCastBit() + { + $db = $this->getConnection(true); + $schema = $db->getSchema(); + $tableSchema = $schema->getTableSchema('type'); + + $this->assertSame('01100100', $tableSchema->getColumn('bit_col')->dbTypecast('01100100')); + } } diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index b57378150..39e6ba959 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -204,6 +204,17 @@ public function testAlterColumn(): void ), ); + $this->assertSame( + <<alterColumn( + 'foo1', + 'bar', + (new Column(SchemaInterface::TYPE_STRING, 30))->unique() + ), + ); + $db->close(); }