Skip to content

Commit

Permalink
[5.6] Add helpers for subquery join clauses (#23818)
Browse files Browse the repository at this point in the history
* Add joinSub(), leftJoinSub(), rightJoinSub() to query builder

* Add joinSub() test with multiple subqueries
  • Loading branch information
staudenmeir authored and taylorotwell committed Apr 17, 2018
1 parent e3d958b commit e881c50
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
55 changes: 55 additions & 0 deletions src/Illuminate/Database/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,31 @@ public function joinWhere($table, $first, $operator, $second, $type = 'inner')
return $this->join($table, $first, $operator, $second, $type, true);
}

/**
* Add a subquery join clause to the query.
*
* @param \Closure|\Illuminate\Database\Query\Builder|string $query
* @param string $as
* @param string $first
* @param string|null $operator
* @param string|null $second
* @param string $type
* @param bool $where
* @return \Illuminate\Database\Query\Builder|static
*
* @throws \InvalidArgumentException
*/
public function joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false)
{
list($query, $bindings) = $this->createSub($query);

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

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

return $this->join(new Expression($expression), $first, $operator, $second, $type, $where);
}

/**
* Add a left join to the query.
*
Expand Down Expand Up @@ -451,6 +476,21 @@ public function leftJoinWhere($table, $first, $operator, $second)
return $this->joinWhere($table, $first, $operator, $second, 'left');
}

/**
* Add a subquery left join to the query.
*
* @param \Closure|\Illuminate\Database\Query\Builder|string $query
* @param string $as
* @param string $first
* @param string|null $operator
* @param string|null $second
* @return \Illuminate\Database\Query\Builder|static
*/
public function leftJoinSub($query, $as, $first, $operator = null, $second = null)
{
return $this->joinSub($query, $as, $first, $operator, $second, 'left');
}

/**
* Add a right join to the query.
*
Expand Down Expand Up @@ -479,6 +519,21 @@ public function rightJoinWhere($table, $first, $operator, $second)
return $this->joinWhere($table, $first, $operator, $second, 'right');
}

/**
* Add a subquery right join to the query.
*
* @param \Closure|\Illuminate\Database\Query\Builder|string $query
* @param string $as
* @param string $first
* @param string|null $operator
* @param string|null $second
* @return \Illuminate\Database\Query\Builder|static
*/
public function rightJoinSub($query, $as, $first, $operator = null, $second = null)
{
return $this->joinSub($query, $as, $first, $operator, $second, 'right');
}

/**
* Add a "cross join" clause to the query.
*
Expand Down
39 changes: 39 additions & 0 deletions tests/Database/DatabaseQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,45 @@ public function testJoinsWithNestedJoinWithAdvancedSubqueryCondition()
$this->assertEquals(['1', 10000], $builder->getBindings());
}

public function testJoinSub()
{
$builder = $this->getBuilder();
$builder->from('users')->joinSub('select * from "contacts"', 'sub', 'users.id', '=', 'sub.id');
$this->assertEquals('select * from "users" inner join (select * from "contacts") as "sub" on "users"."id" = "sub"."id"', $builder->toSql());

$builder = $this->getBuilder();
$builder->from('users')->joinSub(function ($q) {
$q->from('contacts');
}, 'sub', 'users.id', '=', 'sub.id');
$this->assertEquals('select * from "users" inner join (select * from "contacts") as "sub" on "users"."id" = "sub"."id"', $builder->toSql());

$builder = $this->getBuilder();
$sub1 = $this->getBuilder()->from('contacts')->where('name', 'foo');
$sub2 = $this->getBuilder()->from('contacts')->where('name', 'bar');
$builder->from('users')
->joinSub($sub1, 'sub1', 'users.id', '=', 1, 'inner', true)
->joinSub($sub2, 'sub2', 'users.id', '=', 'sub2.user_id');
$expected = 'select * from "users" ';
$expected .= 'inner join (select * from "contacts" where "name" = ?) as "sub1" on "users"."id" = ? ';
$expected .= 'inner join (select * from "contacts" where "name" = ?) as "sub2" on "users"."id" = "sub2"."user_id"';
$this->assertEquals($expected, $builder->toSql());
$this->assertEquals(['foo', 1, 'bar'], $builder->getRawBindings()['join']);
}

public function testLeftJoinSub()
{
$builder = $this->getBuilder();
$builder->from('users')->leftJoinSub($this->getBuilder()->from('contacts'), 'sub', 'users.id', '=', 'sub.id');
$this->assertEquals('select * from "users" left join (select * from "contacts") as "sub" on "users"."id" = "sub"."id"', $builder->toSql());
}

public function testRightJoinSub()
{
$builder = $this->getBuilder();
$builder->from('users')->rightJoinSub($this->getBuilder()->from('contacts'), 'sub', 'users.id', '=', 'sub.id');
$this->assertEquals('select * from "users" right join (select * from "contacts") as "sub" on "users"."id" = "sub"."id"', $builder->toSql());
}

public function testRawExpressionsInSelect()
{
$builder = $this->getBuilder();
Expand Down

0 comments on commit e881c50

Please sign in to comment.