diff --git a/CHANGELOG.md b/CHANGELOG.md index 850972ef9..6f84beb42 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, #448: Implement `CaseExpressionBuilder` class (@Tigrov) +- Enh #415, #448, #451: Implement `CaseXBuilder` 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/CaseXBuilder.php b/src/Builder/CaseXBuilder.php index c99a89248..6b807684f 100644 --- a/src/Builder/CaseXBuilder.php +++ b/src/Builder/CaseXBuilder.php @@ -15,29 +15,39 @@ */ final class CaseXBuilder extends \Yiisoft\Db\Expression\Statement\Builder\CaseXBuilder { + /** + * @param CaseX $expression The `CASE` expression to build. + */ public function build(ExpressionInterface $expression, array &$params = []): string { $sql = 'CASE'; if ($expression->value !== null) { $caseTypeHint = $this->buildTypeHint($expression->valueType); - $sql .= ' ' . $this->buildConditionWithTypeHint($expression->value, $caseTypeHint, $params); + $sql .= ' ' . $this->buildCaseValueWithTypeHint($expression->value, $caseTypeHint, $params); } else { $caseTypeHint = ''; } - foreach ($expression->when as $when) { - $sql .= ' WHEN ' . $this->buildConditionWithTypeHint($when->condition, $caseTypeHint, $params); - $sql .= ' THEN ' . $this->buildResult($when->result, $params); + foreach ($expression->whenThen as $whenThen) { + $sql .= ' WHEN ' . $this->buildConditionWithTypeHint($whenThen->when, $caseTypeHint, $params); + $sql .= ' THEN ' . $this->queryBuilder->buildValue($whenThen->then, $params); } if ($expression->hasElse()) { - $sql .= ' ELSE ' . $this->buildResult($expression->else, $params); + $sql .= ' ELSE ' . $this->queryBuilder->buildValue($expression->else, $params); } return $sql . ' END'; } + private function buildCaseValueWithTypeHint(mixed $value, string $typeHint, array &$params): string + { + $builtValue = $this->buildCaseValue($value, $params); + + return $typeHint !== '' ? "($builtValue)$typeHint" : $builtValue; + } + private function buildConditionWithTypeHint(mixed $condition, string $typeHint, array &$params): string { $builtCondition = $this->buildCondition($condition, $params); diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index ce9a43f50..4b79bf1b0 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -6,17 +6,17 @@ use Yiisoft\Db\Constant\DataType; use Yiisoft\Db\Constant\PseudoType; -use Yiisoft\Db\Expression\Statement\When; +use Yiisoft\Db\Expression\Statement\WhenThen; use Yiisoft\Db\Expression\Value\ArrayValue; 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; use Yiisoft\Db\Query\Query; +use Yiisoft\Db\QueryBuilder\Condition\Equals; use Yiisoft\Db\QueryBuilder\Condition\LikeConjunction; use function array_replace; @@ -532,9 +532,9 @@ public static function caseXBuilder(): array if (version_compare($serverVersion, '10', '<')) { $data['without case expression'] = [ new CaseX( - when1: new When(['=', 'column_name', 1], new Value('a')), - when2: new When( - '"column_name" = 2', + when1: new WhenThen(['column_name' => 1], 'a'), + when2: new WhenThen( + new Equals('column_name', 2), $db->select(new Expression( ':pv2::text', [':pv2' => $param = new Param('b', DataType::STRING)], @@ -555,31 +555,36 @@ public static function caseXBuilder(): array 'without case and type hint' => [ new CaseX( valueType: 'int', - when: new When(true, "'a'"), + when: new WhenThen(true, 'a'), ), - "CASE WHEN TRUE THEN 'a' END", - [], + 'CASE WHEN TRUE THEN :qp0 END', + [ + ':qp0' => new Param('a', DataType::STRING), + ], 'a', ], 'with case and type hint' => [ new CaseX( - '1 + 1', + 'column_name', 'int', - new When(1, "'a'"), - "'b'", + new WhenThen(1, 'a'), + 'b', ), - "CASE (1 + 1)::int WHEN (1)::int THEN 'a' ELSE 'b' END", - [], + 'CASE ("column_name")::int WHEN (1)::int THEN :qp0 ELSE :qp1 END', + [ + ':qp0' => new Param('a', DataType::STRING), + ':qp1' => new Param('b', DataType::STRING), + ], 'b', ], 'with case and type hint with column' => [ new CaseX( - '1 + 1', + 'column_name', new IntegerColumn(), - new When(1, new Value('a')), + new WhenThen(1, 'a'), $param = new Param('b', DataType::STRING), ), - 'CASE (1 + 1)::integer WHEN (1)::integer THEN :qp0 ELSE :qp1 END', + 'CASE ("column_name")::integer WHEN (1)::integer THEN :qp0 ELSE :qp1 END', [ ':qp0' => new Param('a', DataType::STRING), ':qp1' => $param,