Skip to content

Commit 7c9e306

Browse files
Feature: add support straight join in mysql (#55786)
* feat: add support in grammar * feat: add functions in builder * test: add tests * test: adjust syntax mysql * test: adjust syntax mysql * test: remove line noused * test: execute compileJoins * formatting --------- Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent d8306c9 commit 7c9e306

File tree

4 files changed

+111
-1
lines changed

4 files changed

+111
-1
lines changed

src/Illuminate/Database/Query/Builder.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,49 @@ public function crossJoinSub($query, $as)
776776
return $this;
777777
}
778778

779+
/**
780+
* Add a straight join to the query.
781+
*
782+
* @param \Illuminate\Contracts\Database\Query\Expression|string $table
783+
* @param \Closure|string $first
784+
* @param string|null $operator
785+
* @param \Illuminate\Contracts\Database\Query\Expression|string|null $second
786+
* @return $this
787+
*/
788+
public function straightJoin($table, $first, $operator = null, $second = null)
789+
{
790+
return $this->join($table, $first, $operator, $second, 'straight_join');
791+
}
792+
793+
/**
794+
* Add a "straight join where" clause to the query.
795+
*
796+
* @param \Illuminate\Contracts\Database\Query\Expression|string $table
797+
* @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first
798+
* @param string $operator
799+
* @param \Illuminate\Contracts\Database\Query\Expression|string $second
800+
* @return $this
801+
*/
802+
public function straightJoinWhere($table, $first, $operator, $second)
803+
{
804+
return $this->joinWhere($table, $first, $operator, $second, 'straight_join');
805+
}
806+
807+
/**
808+
* Add a subquery straight join to the query.
809+
*
810+
* @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query
811+
* @param string $as
812+
* @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first
813+
* @param string|null $operator
814+
* @param \Illuminate\Contracts\Database\Query\Expression|string|null $second
815+
* @return $this
816+
*/
817+
public function straightJoinSub($query, $as, $first, $operator = null, $second = null)
818+
{
819+
return $this->joinSub($query, $as, $first, $operator, $second, 'straight_join');
820+
}
821+
779822
/**
780823
* Get a new join clause.
781824
*

src/Illuminate/Database/Query/Grammars/Grammar.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ protected function compileJoins(Builder $query, $joins)
199199
return $this->compileJoinLateral($join, $tableAndNestedJoins);
200200
}
201201

202-
return trim("{$join->type} join {$tableAndNestedJoins} {$this->compileWheres($join)}");
202+
$joinWord = ($join->type === 'straight_join' && $this->supportsStraightJoins()) ? '' : ' join';
203+
204+
return trim("{$join->type}{$joinWord} {$tableAndNestedJoins} {$this->compileWheres($join)}");
203205
})->implode(' ');
204206
}
205207

@@ -217,6 +219,16 @@ public function compileJoinLateral(JoinLateralClause $join, string $expression):
217219
throw new RuntimeException('This database engine does not support lateral joins.');
218220
}
219221

222+
/**
223+
* Determine if the grammar supports straight joins.
224+
*
225+
* @return bool
226+
*/
227+
protected function supportsStraightJoins()
228+
{
229+
throw new RuntimeException('This database engine does not support straight joins.');
230+
}
231+
220232
/**
221233
* Compile the "where" portions of the query.
222234
*

src/Illuminate/Database/Query/Grammars/MySqlGrammar.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,14 @@ public function compileJoinLateral(JoinLateralClause $join, string $expression):
387387
return trim("{$join->type} join lateral {$expression} on true");
388388
}
389389

390+
/**
391+
* {@inheritdoc}
392+
*/
393+
protected function supportsStraightJoins()
394+
{
395+
return true;
396+
}
397+
390398
/**
391399
* Prepare a JSON column being updated using the JSON_SET function.
392400
*

tests/Database/DatabaseQueryBuilderTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3299,6 +3299,53 @@ public function testRightJoinSub()
32993299
$builder->from('users')->rightJoinSub(['foo'], 'sub', 'users.id', '=', 'sub.id');
33003300
}
33013301

3302+
public function testStraightJoin()
3303+
{
3304+
$builder = $this->getMySqlBuilder();
3305+
$builder->getConnection()->shouldReceive('getDatabaseName');
3306+
$builder->select('*')->from('users')->straightJoin('contacts', 'users.id', 'contacts.id');
3307+
$this->assertSame('select * from `users` straight_join `contacts` on `users`.`id` = `contacts`.`id`', $builder->toSql());
3308+
3309+
$builder = $this->getMySqlBuilder();
3310+
$builder->getConnection()->shouldReceive('getDatabaseName');
3311+
$builder->select('*')->from('users')->join('contacts', 'users.id', '=', 'contacts.id')->straightJoin('photos', 'users.id', '=', 'photos.id');
3312+
$this->assertSame('select * from `users` inner join `contacts` on `users`.`id` = `contacts`.`id` straight_join `photos` on `users`.`id` = `photos`.`id`', $builder->toSql());
3313+
3314+
$builder = $this->getMySqlBuilder();
3315+
$builder->getConnection()->shouldReceive('getDatabaseName');
3316+
$builder->select('*')->from('users')->straightJoinWhere('photos', 'users.id', '=', 'bar')->joinWhere('photos', 'users.id', '=', 'foo');
3317+
$this->assertSame('select * from `users` straight_join `photos` on `users`.`id` = ? inner join `photos` on `users`.`id` = ?', $builder->toSql());
3318+
$this->assertEquals(['bar', 'foo'], $builder->getBindings());
3319+
}
3320+
3321+
public function testStraightJoinNoSupport()
3322+
{
3323+
$this->expectException(RuntimeException::class);
3324+
$builder = $this->getBuilder();
3325+
$builder->select('*')->from('users')->straightJoin('contacts', 'users.id', 'contacts.id');
3326+
$builder->toSql();
3327+
}
3328+
3329+
public function testStraightJoinSub()
3330+
{
3331+
$builder = $this->getMySqlBuilder();
3332+
$builder->getConnection()->shouldReceive('getDatabaseName');
3333+
$builder->from('users')->straightJoinSub($this->getBuilder()->from('contacts'), 'sub', 'users.id', '=', 'sub.id');
3334+
$this->assertSame('select * from `users` straight_join (select * from "contacts") as `sub` on `users`.`id` = `sub`.`id`', $builder->toSql());
3335+
3336+
$this->expectException(InvalidArgumentException::class);
3337+
$builder = $this->getBuilder();
3338+
$builder->from('users')->straightJoinSub(['foo'], 'sub', 'users.id', '=', 'sub.id');
3339+
}
3340+
3341+
public function testStraightJoinSubNoSupport()
3342+
{
3343+
$this->expectException(RuntimeException::class);
3344+
$builder = $this->getBuilder();
3345+
$builder->from('users')->straightJoinSub($this->getBuilder()->from('contacts'), 'sub', 'users.id', '=', 'sub.id');
3346+
$builder->toSql();
3347+
}
3348+
33023349
public function testJoinLateral()
33033350
{
33043351
$builder = $this->getMySqlBuilder();

0 commit comments

Comments
 (0)