Skip to content

Commit

Permalink
Adding fromSub and fromRaw methods to query Builder
Browse files Browse the repository at this point in the history
  • Loading branch information
henriquepedrosa committed Mar 10, 2018
1 parent 086e43e commit ab69a8b
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 11 deletions.
68 changes: 57 additions & 11 deletions src/Illuminate/Database/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class Builder
*/
public $bindings = [
'select' => [],
'from' => [],
'join' => [],
'where' => [],
'having' => [],
Expand Down Expand Up @@ -241,15 +242,12 @@ public function selectRaw($expression, array $bindings = [])
}

/**
* Add a subselect expression to the query.
* Creates a subquery and parse it.
*
* @param \Closure|\Illuminate\Database\Query\Builder|string $query
* @param string $as
* @return \Illuminate\Database\Query\Builder|static
*
* @throws \InvalidArgumentException
* @return array
*/
public function selectSub($query, $as)
protected function createSub($query)
{
// If the given query is a Closure, we will execute it while passing in a new
// query instance to the Closure. This will give the developer a chance to
Expand All @@ -261,22 +259,70 @@ public function selectSub($query, $as)
}

// Here, we will parse this query into an SQL string and an array of bindings
// so we can add it to the query builder using the selectRaw method so the
// query is included in the real SQL generated by this builder instance.
list($query, $bindings) = $this->parseSubSelect($query);
// so we can later add it to the query builder using a componentRaw method
// to include the sub in the real SQL generated by the builder instance.
return $this->parseSub($query);
}

/**
* Add a subselect expression to the query.
*
* @param \Closure|\Illuminate\Database\Query\Builder|string $query
* @param string $as
* @return \Illuminate\Database\Query\Builder|static
*
* @throws \InvalidArgumentException
*/
public function selectSub($query, $as)
{
list($query, $bindings) = $this->createSub($query);

return $this->selectRaw(
'('.$query.') as '.$this->grammar->wrap($as), $bindings
);
}

/**
* Parse the sub-select query into SQL and bindings.
* Makes "from" fetch from a subquery.
*
* @param \Closure|\Illuminate\Database\Query\Builder|string $query
* @param string $as
* @return \Illuminate\Database\Query\Builder|static
*
* @throws \InvalidArgumentException
*/
public function fromSub($query, $as)
{
list($query, $bindings) = $this->createSub($query);

return $this->fromRaw(
'('.$query.') as '.$this->grammar->wrap($as), $bindings
);
}

/**
* Add a raw or where clause to the query.
*
* @param string $expression
* @param mixed $bindings
* @return \Illuminate\Database\Query\Builder|static
*/
public function fromRaw($expression, $bindings = [])
{
$this->from = new Expression($expression);

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

return $this;
}

/**
* Parse the subquery into SQL and bindings.
*
* @param mixed $query
* @return array
*/
protected function parseSubSelect($query)
protected function parseSub($query)
{
if ($query instanceof self) {
return [$query->toSql(), $query->getBindings()];
Expand Down
34 changes: 34 additions & 0 deletions tests/Database/DatabaseQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2505,6 +2505,40 @@ public function testWhereRowValuesArityMismatch()
$builder->select('*')->from('orders')->whereRowValues(['last_update'], '<', [1, 2]);
}

public function testFromSub()
{
$builder = $this->getBuilder();
$builder->fromSub(function ($query) {
$query->select(new Raw('max(last_seen_at) as last_seen_at'))->from('user_sessions')->where('foo', '=', '1');
}, 'sessions')->where('bar', '<', '10');
$this->assertEquals('select * from (select max(last_seen_at) as last_seen_at from "user_sessions" where "foo" = ?) as "sessions" where "bar" < ?', $builder->toSql());
$this->assertEquals(['1', '10'], $builder->getBindings());
}

public function testFromSubWithoutBindings()
{
$builder = $this->getBuilder();
$builder->fromSub(function ($query) {
$query->select(new Raw('max(last_seen_at) as last_seen_at'))->from('user_sessions');
}, 'sessions');
$this->assertEquals('select * from (select max(last_seen_at) as last_seen_at from "user_sessions") as "sessions"', $builder->toSql());
}

public function testFromRaw()
{
$builder = $this->getBuilder();
$builder->fromRaw(new Raw('(select max(last_seen_at) as last_seen_at from "user_sessions") as "sessions"'));
$this->assertEquals('select * from (select max(last_seen_at) as last_seen_at from "user_sessions") as "sessions"', $builder->toSql());
}

public function testFromRawWithWhereOnTheMainQuery()
{
$builder = $this->getBuilder();
$builder->fromRaw(new Raw('(select max(last_seen_at) as last_seen_at from "sessions") as "last_seen_at"'))->where('last_seen_at', '>', '1520652582');
$this->assertEquals('select * from (select max(last_seen_at) as last_seen_at from "sessions") as "last_seen_at" where "last_seen_at" > ?', $builder->toSql());
$this->assertEquals(['1520652582'], $builder->getBindings());
}

protected function getBuilder()
{
$grammar = new \Illuminate\Database\Query\Grammars\Grammar;
Expand Down

0 comments on commit ab69a8b

Please sign in to comment.