Skip to content

Commit

Permalink
[10.x] Database Expressions that are conditions (#47210)
Browse files Browse the repository at this point in the history
* expressions that form a complete condition

* style-ci

* formatting

---------

Co-authored-by: Taylor Otwell <taylor@laravel.com>
  • Loading branch information
tpetry and taylorotwell authored May 30, 2023
1 parent c2c20ba commit e0788c9
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Illuminate\Contracts\Database\Query;

interface ConditionExpression extends Expression
{
}
17 changes: 17 additions & 0 deletions src/Illuminate/Database/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Closure;
use DateTimeInterface;
use Illuminate\Contracts\Database\Query\Builder as BuilderContract;
use Illuminate\Contracts\Database\Query\ConditionExpression;
use Illuminate\Contracts\Database\Query\Expression as ExpressionContract;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Concerns\BuildsQueries;
Expand Down Expand Up @@ -753,6 +754,14 @@ public function mergeWheres($wheres, $bindings)
*/
public function where($column, $operator = null, $value = null, $boolean = 'and')
{
if ($column instanceof ConditionExpression) {
$type = 'Expression';

$this->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.
Expand Down Expand Up @@ -2083,6 +2092,14 @@ public function having($column, $operator = null, $value = null, $boolean = 'and
{
$type = 'Basic';

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.
Expand Down
25 changes: 25 additions & 0 deletions src/Illuminate/Database/Query/Grammars/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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.
*
Expand Down
33 changes: 33 additions & 0 deletions tests/Database/DatabaseQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1833,6 +1834,22 @@ 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();
Expand Down Expand Up @@ -5076,6 +5093,22 @@ 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();
Expand Down

0 comments on commit e0788c9

Please sign in to comment.