From 580a7a07c8da5151380efb59cf683c56cd4183fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Lundb=C3=B8l?= Date: Thu, 30 Nov 2023 09:40:31 +0100 Subject: [PATCH] Add case when syntax (#19) Co-authored-by: tpetry --- src/Language/CaseGroup.php | 39 +++++++++++++++++++++ src/Language/CaseRule.php | 29 +++++++++++++++ tests/ConditionExpression.php | 12 +++++++ tests/Language/CaseTest.php | 66 +++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 src/Language/CaseGroup.php create mode 100644 src/Language/CaseRule.php create mode 100644 tests/ConditionExpression.php create mode 100644 tests/Language/CaseTest.php diff --git a/src/Language/CaseGroup.php b/src/Language/CaseGroup.php new file mode 100644 index 0000000..0f98590 --- /dev/null +++ b/src/Language/CaseGroup.php @@ -0,0 +1,39 @@ + $when + */ + public function __construct( + private readonly array $when, + private readonly string|Expression|null $else = null, + ) { + } + + public function getValue(Grammar $grammar): string + { + $conditions = array_map( + callback: fn ($expression) => $this->stringize($grammar, $expression), + array: $this->when, + ); + $conditions = implode(' ', $conditions); + + return match ($this->else) { + null => "(case {$conditions} end)", + default => "(case {$conditions} else {$this->stringize($grammar, $this->else)} end)", + }; + } +} diff --git a/src/Language/CaseRule.php b/src/Language/CaseRule.php new file mode 100644 index 0000000..9125698 --- /dev/null +++ b/src/Language/CaseRule.php @@ -0,0 +1,29 @@ +stringize($grammar, $this->condition); + $result = $this->stringize($grammar, $this->result); + + return "when {$condition} then {$result}"; + } +} 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 CaseGroup([ + new CaseRule(new Expression(2), new ConditionExpression('1 = 1')), + ]) + ) + ->toBeExecutable() + ->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('can create create a case-expression with multiple branches') + ->expect(new CaseGroup([ + new CaseRule(new Expression(2), new ConditionExpression('1 = 1')), + new CaseRule('val', new ConditionExpression('2 = 2')), + ])) + ->toBeExecutable(function (Blueprint $table) { + $table->integer('val'); + }) + ->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('can create create a case-expression with multiple branches and expression default') + ->expect(new CaseGroup( + [ + new CaseRule(new Expression(2), new ConditionExpression('1 = 1')), + new CaseRule('val', new ConditionExpression('2 = 2')), + ], + new Expression('4'), + )) + ->toBeExecutable(function (Blueprint $table) { + $table->integer('val'); + }) + ->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('can create create a case-expression with multiple branches and column default') + ->expect(new CaseGroup( + [ + new CaseRule(new Expression(2), new ConditionExpression('1 = 1')), + new CaseRule('val', new ConditionExpression('2 = 2')), + ], + 'val', + )) + ->toBeExecutable(function (Blueprint $table) { + $table->integer('val'); + }) + ->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)');