Skip to content

Commit

Permalink
Add lateral join support to Query Builder
Browse files Browse the repository at this point in the history
  • Loading branch information
Bakke committed Feb 21, 2024
1 parent 08bf276 commit 0e82968
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 3 deletions.
38 changes: 36 additions & 2 deletions src/Illuminate/Database/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,39 @@ public function joinSub($query, $as, $first, $operator = null, $second = null, $
return $this->join(new Expression($expression), $first, $operator, $second, $type, $where);
}

/**
* Add a lateral join clause to the query.
*
* @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string $query
* @param string $as
* @param string $type
* @return $this
*/
public function joinLateral($query, string $as, string $type = 'inner'): static
{
[$query, $bindings] = $this->createSub($query);

$expression = '('.$query.') as '.$this->grammar->wrapTable($as);

$this->addBinding($bindings, 'join');

$this->joins[] = $this->newJoinClause($this, $type, new Expression($expression), true);

return $this;
}

/**
* Add a lateral left join to the query.
*
* @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string $query
* @param string $as
* @return $this
*/
public function leftJoinLateral($query, string $as): static
{
return $this->joinLateral($query, $as, 'left');
}

/**
* Add a left join to the query.
*
Expand Down Expand Up @@ -718,11 +751,12 @@ public function crossJoinSub($query, $as)
* @param \Illuminate\Database\Query\Builder $parentQuery
* @param string $type
* @param string $table
* @param bool $lateral
* @return \Illuminate\Database\Query\JoinClause
*/
protected function newJoinClause(self $parentQuery, $type, $table)
protected function newJoinClause(self $parentQuery, $type, $table, $lateral = false)
{
return new JoinClause($parentQuery, $type, $table);
return new JoinClause($parentQuery, $type, $table, $lateral);
}

/**
Expand Down
18 changes: 18 additions & 0 deletions src/Illuminate/Database/Query/Grammars/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,28 @@ protected function compileJoins(Builder $query, $joins)

$tableAndNestedJoins = is_null($join->joins) ? $table : '('.$table.$nestedJoins.')';

if ($join->lateral) {
return $this->compileJoinLateral($join, $tableAndNestedJoins);
}

return trim("{$join->type} join {$tableAndNestedJoins} {$this->compileWheres($join)}");
})->implode(' ');
}

/**
* Compile a "lateral join" clause.
*
* @param \Illuminate\Database\Query\JoinClause $join
* @param string $expression
* @return string
*
* @throws \RuntimeException
*/
public function compileJoinLateral(JoinClause $join, string $expression): string
{
throw new RuntimeException('This database engine does not support lateral joins.');
}

/**
* Compile the "where" portions of the query.
*
Expand Down
13 changes: 13 additions & 0 deletions src/Illuminate/Database/Query/Grammars/MySqlGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Illuminate\Database\Query\Grammars;

use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Str;

class MySqlGrammar extends Grammar
Expand Down Expand Up @@ -233,6 +234,18 @@ protected function compileUpdateColumns(Builder $query, array $values)
})->implode(', ');
}

/**
* Compile a "lateral join" clause.
*
* @param \Illuminate\Database\Query\JoinClause $join
* @param string $expression
* @return string
*/
public function compileJoinLateral(JoinClause $join, string $expression): string
{
return trim("{$join->type} join lateral {$expression} on true");
}

/**
* Compile an "upsert" statement into SQL.
*
Expand Down
13 changes: 13 additions & 0 deletions src/Illuminate/Database/Query/Grammars/PostgresGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Illuminate\Database\Query\Grammars;

use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

Expand Down Expand Up @@ -385,6 +386,18 @@ protected function compileUpdateColumns(Builder $query, array $values)
})->implode(', ');
}

/**
* Compile a "lateral join" clause.
*
* @param \Illuminate\Database\Query\JoinClause $join
* @param string $expression
* @return string
*/
public function compileJoinLateral(JoinClause $join, string $expression): string
{
return trim("{$join->type} join lateral {$expression} on true");
}

/**
* Compile an "upsert" statement into SQL.
*
Expand Down
15 changes: 15 additions & 0 deletions src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Illuminate\Database\Query\Grammars;

use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

Expand Down Expand Up @@ -386,6 +387,20 @@ protected function compileUpdateWithJoins(Builder $query, $table, $columns, $whe
return "update {$alias} set {$columns} from {$table} {$joins} {$where}";
}

/**
* Compile a "lateral join" clause.
*
* @param \Illuminate\Database\Query\JoinClause $join
* @param string $expression
* @return string
*/
public function compileJoinLateral(JoinClause $join, string $expression): string
{
$type = $join->type == 'left' ? 'outer' : 'cross';

return trim("{$type} apply {$expression}");
}

/**
* Compile an "upsert" statement into SQL.
*
Expand Down
11 changes: 10 additions & 1 deletion src/Illuminate/Database/Query/JoinClause.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ class JoinClause extends Builder
*/
public $table;

/**
* Indicates if the join is a "lateral" join.
*
* @var bool
*/
public $lateral;

/**
* The connection of the parent query builder.
*
Expand Down Expand Up @@ -54,12 +61,14 @@ class JoinClause extends Builder
* @param \Illuminate\Database\Query\Builder $parentQuery
* @param string $type
* @param string $table
* @param bool $lateral
* @return void
*/
public function __construct(Builder $parentQuery, $type, $table)
public function __construct(Builder $parentQuery, $type, $table, $lateral = false)
{
$this->type = $type;
$this->table = $table;
$this->lateral = $lateral;
$this->parentClass = get_class($parentQuery);
$this->parentGrammar = $parentQuery->getGrammar();
$this->parentProcessor = $parentQuery->getProcessor();
Expand Down

0 comments on commit 0e82968

Please sign in to comment.