diff --git a/CHANGELOG.md b/CHANGELOG.md index 374328eff..933c7aad2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,7 @@ - New #408, #410: Implement `DMLQueryBuilder::upsertReturning()` method (@Tigrov) - Enh #412: Reduce binding parameters (@Tigrov) - Chg #414: Rename `DMLQueryBuilder::insertWithReturningPks()` to `DMLQueryBuilder::insertReturningPks()` (@Tigrov) -- Enh #415: Implement `CaseExpressionBuilder` class (@Tigrov) +- Enh #415, #448: Implement `CaseExpressionBuilder` class (@Tigrov) - Enh #420: Provide `yiisoft/db-implementation` virtual package (@vjik) - Enh #424, #425, #428: Adapt to conditions refactoring in `yiisoft/db` package (@vjik) - Enh #431: Remove `TableSchema` class and refactor `Schema` class (@Tigrov) diff --git a/src/Builder/CaseExpressionBuilder.php b/src/Builder/CaseXBuilder.php similarity index 59% rename from src/Builder/CaseExpressionBuilder.php rename to src/Builder/CaseXBuilder.php index 9d86b93d4..c99a89248 100644 --- a/src/Builder/CaseExpressionBuilder.php +++ b/src/Builder/CaseXBuilder.php @@ -4,44 +4,35 @@ namespace Yiisoft\Db\Pgsql\Builder; -use InvalidArgumentException; -use Yiisoft\Db\Expression\Statement\CaseExpression; +use Yiisoft\Db\Expression\Statement\CaseX; use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Schema\Column\ColumnInterface; use function is_string; /** - * Builds expressions for {@see CaseExpression}. + * Builds expressions for {@see CaseX}. */ -final class CaseExpressionBuilder extends \Yiisoft\Db\Expression\Statement\Builder\CaseExpressionBuilder +final class CaseXBuilder extends \Yiisoft\Db\Expression\Statement\Builder\CaseXBuilder { public function build(ExpressionInterface $expression, array &$params = []): string { - $whenClauses = $expression->getWhen(); - - if (empty($whenClauses)) { - throw new InvalidArgumentException('The CASE expression must have at least one WHEN clause.'); - } - $sql = 'CASE'; - $case = $expression->getCase(); - - if ($case !== null) { - $caseTypeHint = $this->buildTypeHint($expression->getCaseType()); - $sql .= ' ' . $this->buildConditionWithTypeHint($case, $caseTypeHint, $params); + if ($expression->value !== null) { + $caseTypeHint = $this->buildTypeHint($expression->valueType); + $sql .= ' ' . $this->buildConditionWithTypeHint($expression->value, $caseTypeHint, $params); } else { $caseTypeHint = ''; } - foreach ($whenClauses as $when) { + foreach ($expression->when as $when) { $sql .= ' WHEN ' . $this->buildConditionWithTypeHint($when->condition, $caseTypeHint, $params); $sql .= ' THEN ' . $this->buildResult($when->result, $params); } if ($expression->hasElse()) { - $sql .= ' ELSE ' . $this->buildResult($expression->getElse(), $params); + $sql .= ' ELSE ' . $this->buildResult($expression->else, $params); } return $sql . ' END'; diff --git a/src/DQLQueryBuilder.php b/src/DQLQueryBuilder.php index a403e682a..cf646eef5 100644 --- a/src/DQLQueryBuilder.php +++ b/src/DQLQueryBuilder.php @@ -5,14 +5,14 @@ namespace Yiisoft\Db\Pgsql; use Yiisoft\Db\Expression\Value\ArrayExpression; -use Yiisoft\Db\Expression\Statement\CaseExpression; +use Yiisoft\Db\Expression\Statement\CaseX; use Yiisoft\Db\Expression\Function\ArrayMerge; use Yiisoft\Db\Expression\Value\JsonExpression; use Yiisoft\Db\Expression\Value\StructuredExpression; use Yiisoft\Db\Pgsql\Builder\ArrayExpressionBuilder; use Yiisoft\Db\Pgsql\Builder\ArrayMergeBuilder; use Yiisoft\Db\Pgsql\Builder\ArrayOverlapsBuilder; -use Yiisoft\Db\Pgsql\Builder\CaseExpressionBuilder; +use Yiisoft\Db\Pgsql\Builder\CaseXBuilder; use Yiisoft\Db\Pgsql\Builder\JsonOverlapsBuilder; use Yiisoft\Db\Pgsql\Builder\LikeBuilder; use Yiisoft\Db\Pgsql\Builder\StructuredExpressionBuilder; @@ -39,7 +39,7 @@ protected function defaultExpressionBuilders(): array StructuredExpression::class => StructuredExpressionBuilder::class, Like::class => LikeBuilder::class, NotLike::class => LikeBuilder::class, - CaseExpression::class => CaseExpressionBuilder::class, + CaseX::class => CaseXBuilder::class, ArrayMerge::class => ArrayMergeBuilder::class, ]; } diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index f4e4e1763..8e507c434 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -6,11 +6,13 @@ use Yiisoft\Db\Constant\DataType; use Yiisoft\Db\Constant\PseudoType; +use Yiisoft\Db\Expression\Statement\When; use Yiisoft\Db\Expression\Value\ArrayExpression; -use Yiisoft\Db\Expression\Statement\CaseExpression; +use Yiisoft\Db\Expression\Statement\CaseX; use Yiisoft\Db\Expression\Expression; use Yiisoft\Db\Expression\Function\ArrayMerge; use Yiisoft\Db\Expression\Value\Param; +use Yiisoft\Db\Expression\Value\Value; use Yiisoft\Db\Pgsql\Column\ColumnBuilder; use Yiisoft\Db\Pgsql\Column\IntegerColumn; use Yiisoft\Db\Pgsql\Tests\Support\TestTrait; @@ -519,9 +521,9 @@ public static function prepareValue(): array return $values; } - public static function caseExpressionBuilder(): array + public static function caseXBuilder(): array { - $data = parent::caseExpressionBuilder(); + $data = parent::caseXBuilder(); $db = self::getDb(); $serverVersion = $db->getServerInfo()->getVersion(); @@ -529,17 +531,21 @@ public static function caseExpressionBuilder(): array if (version_compare($serverVersion, '10', '<')) { $data['without case expression'] = [ - (new CaseExpression()) - ->addWhen(['=', 'column_name', 1], $paramA = new Param('a', DataType::STRING)) - ->addWhen( + new CaseX( + when1: new When(['=', 'column_name', 1], new Value('a')), + when2: new When( '"column_name" = 2', $db->select(new Expression( ':pv2::text', - [':pv2' => $paramB = new Param('b', DataType::STRING)], + [':pv2' => $param = new Param('b', DataType::STRING)], )), ), + ), 'CASE WHEN "column_name" = 1 THEN :qp0 WHEN "column_name" = 2 THEN (SELECT :pv2::text) END', - [':qp0' => $paramA, ':pv2' => $paramB], + [ + ':qp0' => new Param('a', DataType::STRING), + ':pv2' => $param, + ], 'b', ]; } @@ -547,28 +553,36 @@ public static function caseExpressionBuilder(): array return [ ...$data, 'without case and type hint' => [ - (new CaseExpression())->caseType('int') - ->addWhen(true, "'a'"), + new CaseX( + valueType: 'int', + when: new When(true, "'a'"), + ), "CASE WHEN TRUE THEN 'a' END", [], 'a', ], 'with case and type hint' => [ - (new CaseExpression('1 + 1', 'int')) - ->addWhen(1, "'a'") - ->else("'b'"), + new CaseX( + '1 + 1', + 'int', + new When(1, "'a'"), + "'b'", + ), "CASE (1 + 1)::int WHEN (1)::int THEN 'a' ELSE 'b' END", [], 'b', ], 'with case and type hint with column' => [ - (new CaseExpression('1 + 1', new IntegerColumn())) - ->addWhen(1, $paramA = new Param('a', DataType::STRING)) - ->else($paramB = new Param('b', DataType::STRING)), + new CaseX( + '1 + 1', + new IntegerColumn(), + new When(1, new Value('a')), + $param = new Param('b', DataType::STRING), + ), 'CASE (1 + 1)::integer WHEN (1)::integer THEN :qp0 ELSE :qp1 END', [ - ':qp0' => $paramA, - ':qp1' => $paramB, + ':qp0' => new Param('a', DataType::STRING), + ':qp1' => $param, ], 'b', ], diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index 078f241b9..8b303c53e 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -11,7 +11,7 @@ use Yiisoft\Db\Exception\IntegrityException; use Yiisoft\Db\Exception\NotSupportedException; use Yiisoft\Db\Expression\Value\ArrayExpression; -use Yiisoft\Db\Expression\Statement\CaseExpression; +use Yiisoft\Db\Expression\Statement\CaseX; use Yiisoft\Db\Expression\Expression; use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Expression\Function\ArrayMerge; @@ -585,14 +585,14 @@ public function testPrepareValue(string $expected, mixed $value): void parent::testPrepareValue($expected, $value); } - #[DataProviderExternal(QueryBuilderProvider::class, 'caseExpressionBuilder')] - public function testCaseExpressionBuilder( - CaseExpression $case, + #[DataProviderExternal(QueryBuilderProvider::class, 'caseXBuilder')] + public function testCaseXBuilder( + CaseX $case, string $expectedSql, array $expectedParams, string|int $expectedResult, ): void { - parent::testCaseExpressionBuilder($case, $expectedSql, $expectedParams, $expectedResult); + parent::testCaseXBuilder($case, $expectedSql, $expectedParams, $expectedResult); } #[DataProviderExternal(QueryBuilderProvider::class, 'lengthBuilder')]