From f6582be8d7c28d7ba24f1f56449d2b389242d2d5 Mon Sep 17 00:00:00 2001 From: tpetry Date: Thu, 25 May 2023 10:49:23 +0200 Subject: [PATCH 1/3] expressions that form a complete condition --- .../Database/Query/ConditionExpression.php | 8 +++++ src/Illuminate/Database/Query/Builder.php | 21 +++++++++++++ .../Database/Query/Grammars/Grammar.php | 25 +++++++++++++++ tests/Database/DatabaseQueryBuilderTest.php | 31 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 src/Illuminate/Contracts/Database/Query/ConditionExpression.php diff --git a/src/Illuminate/Contracts/Database/Query/ConditionExpression.php b/src/Illuminate/Contracts/Database/Query/ConditionExpression.php new file mode 100644 index 000000000000..edfb6e03ac32 --- /dev/null +++ b/src/Illuminate/Contracts/Database/Query/ConditionExpression.php @@ -0,0 +1,8 @@ +wheres[] = compact('type', 'column', 'boolean'); + + return $this; + } + // If the column is an array, we will assume it is an array of key-value pairs // and can add them each as a where clause. We will maintain the boolean we // received when the method was called and pass it into the nested where. @@ -2083,6 +2094,16 @@ public function having($column, $operator = null, $value = null, $boolean = 'and { $type = 'Basic'; + // If the column is a condition expression, we can skip the normal handling + // of parameters. Such a value indicates that the column contains a having + // condition that can be directly embedded into the query. + if ($column instanceof ConditionExpression) { + $type = 'Expression'; + $this->havings[] = compact('type', 'column', 'boolean'); + + return $this; + } + // Here we will make some assumptions about the operator. If only 2 values are // passed to the method, we will assume that the operator is an equals sign // and keep going. Otherwise, we'll require the operator to be passed in. diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index fc384662de03..7118fa51878f 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -706,6 +706,18 @@ public function whereFullText(Builder $query, $where) throw new RuntimeException('This database engine does not support fulltext search operations.'); } + /** + * Compile a clause based on an expression. + * + * @param \Illuminate\Database\Query\Builder $query + * @param array $where + * @return string + */ + public function whereExpression(Builder $query, $where) + { + return $where['column']->getValue($this); + } + /** * Compile the "group by" portions of the query. * @@ -752,6 +764,8 @@ protected function compileHaving(array $having) return $this->compileHavingNotNull($having); } elseif ($having['type'] === 'bit') { return $this->compileHavingBit($having); + } elseif ($having['type'] === 'Expression') { + return $this->compileHavingExpression($having); } elseif ($having['type'] === 'Nested') { return $this->compileNestedHavings($having); } @@ -834,6 +848,17 @@ protected function compileHavingBit($having) return '('.$column.' '.$having['operator'].' '.$parameter.') != 0'; } + /** + * Compile a having clause involving an expression. + * + * @param array $having + * @return string + */ + protected function compileHavingExpression($having) + { + return $having['column']->getValue($this); + } + /** * Compile a nested having clause. * diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index b09287792cec..47f1cd450781 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -5,6 +5,7 @@ use BadMethodCallException; use Closure; use DateTime; +use Illuminate\Contracts\Database\Query\ConditionExpression; use Illuminate\Database\ConnectionInterface; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Query\Builder; @@ -1833,6 +1834,21 @@ public function testHavingNotNull() $this->assertSame('select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" is not null', $builder->toSql()); } + public function testHavingExpression() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->having( + new class() implements ConditionExpression { + public function getValue(\Illuminate\Database\Grammar $grammar) + { + return '1 = 1'; + } + } + ); + $this->assertSame('select * from "users" having 1 = 1', $builder->toSql()); + $this->assertSame([], $builder->getBindings()); + } + public function testHavingShortcut() { $builder = $this->getBuilder(); @@ -5076,6 +5092,21 @@ public function testCursorPaginateWithUnionWheresMultipleOrders() ]), $result); } + public function testWhereExpression() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('orders')->where( + new class() implements ConditionExpression { + public function getValue(\Illuminate\Database\Grammar $grammar) + { + return '1 = 1'; + } + } + ); + $this->assertSame('select * from "orders" where 1 = 1', $builder->toSql()); + $this->assertSame([], $builder->getBindings()); + } + public function testWhereRowValues() { $builder = $this->getBuilder(); From 4c0eaf6f39e76b736e972f621f2f5ebd33d4cb17 Mon Sep 17 00:00:00 2001 From: tpetry Date: Thu, 25 May 2023 11:46:20 +0200 Subject: [PATCH 2/3] style-ci --- .../Database/Query/ConditionExpression.php | 1 - src/Illuminate/Database/Query/Builder.php | 32 +++++++++---------- tests/Database/DatabaseQueryBuilderTest.php | 8 +++-- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/Illuminate/Contracts/Database/Query/ConditionExpression.php b/src/Illuminate/Contracts/Database/Query/ConditionExpression.php index edfb6e03ac32..b2e97a6e83c8 100644 --- a/src/Illuminate/Contracts/Database/Query/ConditionExpression.php +++ b/src/Illuminate/Contracts/Database/Query/ConditionExpression.php @@ -4,5 +4,4 @@ interface ConditionExpression extends Expression { - } diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index dcf714ed52ab..054e8ee86449 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -754,15 +754,15 @@ public function mergeWheres($wheres, $bindings) */ public function where($column, $operator = null, $value = null, $boolean = 'and') { - // If the column is a condition expression, we can skip the normal handling - // of parameters. Such a value indicates that the column contains a where - // condition that can be directly embedded into the query. - if ($column instanceof ConditionExpression) { - $type = 'Expression'; - $this->wheres[] = compact('type', 'column', 'boolean'); + // If the column is a condition expression, we can skip the normal handling + // of parameters. Such a value indicates that the column contains a where + // condition that can be directly embedded into the query. + if ($column instanceof ConditionExpression) { + $type = 'Expression'; + $this->wheres[] = compact('type', 'column', 'boolean'); - return $this; - } + return $this; + } // If the column is an array, we will assume it is an array of key-value pairs // and can add them each as a where clause. We will maintain the boolean we @@ -2094,15 +2094,15 @@ public function having($column, $operator = null, $value = null, $boolean = 'and { $type = 'Basic'; - // If the column is a condition expression, we can skip the normal handling - // of parameters. Such a value indicates that the column contains a having - // condition that can be directly embedded into the query. - if ($column instanceof ConditionExpression) { - $type = 'Expression'; - $this->havings[] = compact('type', 'column', 'boolean'); + // If the column is a condition expression, we can skip the normal handling + // of parameters. Such a value indicates that the column contains a having + // condition that can be directly embedded into the query. + if ($column instanceof ConditionExpression) { + $type = 'Expression'; + $this->havings[] = compact('type', 'column', 'boolean'); - return $this; - } + return $this; + } // Here we will make some assumptions about the operator. If only 2 values are // passed to the method, we will assume that the operator is an equals sign diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 47f1cd450781..1a785439c044 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -1838,7 +1838,8 @@ public function testHavingExpression() { $builder = $this->getBuilder(); $builder->select('*')->from('users')->having( - new class() implements ConditionExpression { + new class() implements ConditionExpression + { public function getValue(\Illuminate\Database\Grammar $grammar) { return '1 = 1'; @@ -1847,7 +1848,7 @@ public function getValue(\Illuminate\Database\Grammar $grammar) ); $this->assertSame('select * from "users" having 1 = 1', $builder->toSql()); $this->assertSame([], $builder->getBindings()); - } + } public function testHavingShortcut() { @@ -5096,7 +5097,8 @@ public function testWhereExpression() { $builder = $this->getBuilder(); $builder->select('*')->from('orders')->where( - new class() implements ConditionExpression { + new class() implements ConditionExpression + { public function getValue(\Illuminate\Database\Grammar $grammar) { return '1 = 1'; From 0faf741f937c23ce4c5bcefc9452891752a28641 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 30 May 2023 16:26:14 -0500 Subject: [PATCH 3/3] formatting --- src/Illuminate/Database/Query/Builder.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 054e8ee86449..c00c1cb84ed2 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -754,11 +754,9 @@ public function mergeWheres($wheres, $bindings) */ public function where($column, $operator = null, $value = null, $boolean = 'and') { - // If the column is a condition expression, we can skip the normal handling - // of parameters. Such a value indicates that the column contains a where - // condition that can be directly embedded into the query. if ($column instanceof ConditionExpression) { $type = 'Expression'; + $this->wheres[] = compact('type', 'column', 'boolean'); return $this; @@ -2094,11 +2092,9 @@ public function having($column, $operator = null, $value = null, $boolean = 'and { $type = 'Basic'; - // If the column is a condition expression, we can skip the normal handling - // of parameters. Such a value indicates that the column contains a having - // condition that can be directly embedded into the query. if ($column instanceof ConditionExpression) { $type = 'Expression'; + $this->havings[] = compact('type', 'column', 'boolean'); return $this;