diff --git a/src/Language/CaseBlock.php b/src/Language/CaseBlock.php index af6c202..505b343 100644 --- a/src/Language/CaseBlock.php +++ b/src/Language/CaseBlock.php @@ -19,16 +19,20 @@ class CaseBlock extends ManyArgumentsExpression implements ConditionExpression /** * @param non-empty-array $when */ - public function __construct(readonly array $when, private readonly string|Expression $else) - { + public function __construct( + array $when, + private readonly string|Expression|null $else = null, + ) { parent::__construct($when); } public function getValue(Grammar $grammar) { $conditions = implode(' ', $this->getExpressions($grammar)); - $else = $this->stringize($grammar, $this->else); - return "(case {$conditions} else {$else} end)"; + return match ($this->else) { + null => "(case {$conditions} end)", + default => "(case {$conditions} else {$this->stringize($grammar, $this->else)} end)", + }; } } diff --git a/src/Language/CaseCondition.php b/src/Language/CaseCondition.php index fa3b352..bc5afa8 100644 --- a/src/Language/CaseCondition.php +++ b/src/Language/CaseCondition.php @@ -4,6 +4,7 @@ namespace Tpetry\QueryExpressions\Language; +use Illuminate\Contracts\Database\Query\ConditionExpression; use Illuminate\Contracts\Database\Query\Expression; use Illuminate\Database\Grammar; use Tpetry\QueryExpressions\Concerns\StringizeExpression; @@ -12,9 +13,10 @@ class CaseCondition implements Expression { use StringizeExpression; - public function __construct(private readonly string|Expression $result, private readonly string|Expression $condition) - { - + public function __construct( + private readonly string|Expression $result, + private readonly ConditionExpression $condition, + ) { } public function getValue(Grammar $grammar) diff --git a/tests/ConditionExpression.php b/tests/ConditionExpression.php new file mode 100644 index 0000000..f56d90f --- /dev/null +++ b/tests/ConditionExpression.php @@ -0,0 +1,12 @@ +expect( - new CaseBlock(when: [ - new CaseCondition(result: new Number(5), condition: new Equal(new Number(1), new Number(2))), - ], - else: new Number(2) - ) + new CaseBlock([ + new CaseCondition(new Expression(2), new ConditionExpression('1 = 1')), + ]) ) ->toBeExecutable() - ->toBeMysql('(case when (1 = 2) then 5 else 2 end)') - ->toBePgsql('(case when (1 = 2) then 5 else 2 end)') - ->toBeSqlite('(case when (1 = 2) then 5 else 2 end)') - ->toBeSqlsrv('(case when (1 = 2) then 5 else 2 end)'); + ->toBeMysql('(case when 1 = 1 then 2 end)') + ->toBePgsql('(case when 1 = 1 then 2 end)') + ->toBeSqlite('(case when 1 = 1 then 2 end)') + ->toBeSqlsrv('(case when 1 = 1 then 2 end)'); -it('uses a caseBlock with multiple condition blocks') - ->expect( - new CaseBlock(when: [ - new CaseCondition(result: new Number(5), condition: new Equal(new Number(1), new Number(2))), - new CaseCondition(result: new Number(6), condition: new Equal(new Number(2), new Number(2))), - ], - else: new Number(2) - ) - ) - ->toBeExecutable() - ->toBeMysql('(case when (1 = 2) then 5 when (2 = 2) then 6 else 2 end)') - ->toBePgsql('(case when (1 = 2) then 5 when (2 = 2) then 6 else 2 end)') - ->toBeSqlite('(case when (1 = 2) then 5 when (2 = 2) then 6 else 2 end)') - ->toBeSqlsrv('(case when (1 = 2) then 5 when (2 = 2) then 6 else 2 end)'); +it('can create create a case-expression with multiple branches') + ->expect(new CaseBlock([ + new CaseCondition(new Expression(2), new ConditionExpression('1 = 1')), + new CaseCondition('val', new ConditionExpression('2 = 2')), + ])) + ->toBeExecutable(['val int']) + ->toBeMysql('(case when 1 = 1 then 2 when 2 = 2 then `val` end)') + ->toBePgsql('(case when 1 = 1 then 2 when 2 = 2 then "val" end)') + ->toBeSqlite('(case when 1 = 1 then 2 when 2 = 2 then "val" end)') + ->toBeSqlsrv('(case when 1 = 1 then 2 when 2 = 2 then [val] end)'); -it('uses a caseBlock with multiple condition and value') - ->expect( - new CaseBlock(when: [ - new CaseCondition(result: new Number(5), condition: new Equal(new Number(1), new Number(2))), - new CaseCondition(result: new Number(6), condition: new Equal(new Number(2), new Number(2))), +it('can create create a case-expression with multiple branches and expression default') + ->expect(new CaseBlock( + [ + new CaseCondition(new Expression(2), new ConditionExpression('1 = 1')), + new CaseCondition('val', new ConditionExpression('2 = 2')), ], - else: 'val' - ) - ) + new Expression('4'), + )) ->toBeExecutable(['val int']) - ->toBeMysql('(case when (1 = 2) then 5 when (2 = 2) then 6 else `val` end)') - ->toBePgsql('(case when (1 = 2) then 5 when (2 = 2) then 6 else "val" end)') - ->toBeSqlite('(case when (1 = 2) then 5 when (2 = 2) then 6 else "val" end)') - ->toBeSqlsrv('(case when (1 = 2) then 5 when (2 = 2) then 6 else [val] end)'); + ->toBeMysql('(case when 1 = 1 then 2 when 2 = 2 then `val` else 4 end)') + ->toBePgsql('(case when 1 = 1 then 2 when 2 = 2 then "val" else 4 end)') + ->toBeSqlite('(case when 1 = 1 then 2 when 2 = 2 then "val" else 4 end)') + ->toBeSqlsrv('(case when 1 = 1 then 2 when 2 = 2 then [val] else 4 end)'); -it('uses a caseBlock with multiple condition and value aliased') - ->expect( - new \Tpetry\QueryExpressions\Language\Alias(new CaseBlock(when: [ - new CaseCondition(result: new Number(5), condition: new Equal(new Number(1), new Number(2))), - new CaseCondition(result: new Number(6), condition: new Equal(new Number(2), new Number(2))), +it('can create create a case-expression with multiple branches and column default') + ->expect(new CaseBlock( + [ + new CaseCondition(new Expression(2), new ConditionExpression('1 = 1')), + new CaseCondition('val', new ConditionExpression('2 = 2')), ], - else: 'val' - ), 'name') - ) + 'val', + )) ->toBeExecutable(['val int']) - ->toBeMysql('(case when (1 = 2) then 5 when (2 = 2) then 6 else `val` end) as `name`') - ->toBePgsql('(case when (1 = 2) then 5 when (2 = 2) then 6 else "val" end) as "name"') - ->toBeSqlite('(case when (1 = 2) then 5 when (2 = 2) then 6 else "val" end) as "name"') - ->toBeSqlsrv('(case when (1 = 2) then 5 when (2 = 2) then 6 else [val] end) as [name]'); + ->toBeMysql('(case when 1 = 1 then 2 when 2 = 2 then `val` else `val` end)') + ->toBePgsql('(case when 1 = 1 then 2 when 2 = 2 then "val" else "val" end)') + ->toBeSqlite('(case when 1 = 1 then 2 when 2 = 2 then "val" else "val" end)') + ->toBeSqlsrv('(case when 1 = 1 then 2 when 2 = 2 then [val] else [val] end)');