Skip to content

Commit

Permalink
Support Lateral Join to Hyperf\Database\Query\Builder (#6774)
Browse files Browse the repository at this point in the history
  • Loading branch information
zds-s authored May 23, 2024
1 parent 2501a5e commit f430d57
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 39 deletions.
9 changes: 9 additions & 0 deletions src/Query/Grammars/PostgresGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Hyperf\Collection\Arr;
use Hyperf\Database\Query\Builder;
use Hyperf\Database\Query\Grammars\Grammar;
use Hyperf\Database\Query\JoinLateralClause;
use Hyperf\Stringable\Str;

use function Hyperf\Collection\collect;
Expand Down Expand Up @@ -153,6 +154,14 @@ public function compileTruncate(Builder $query): array
return ['truncate ' . $this->wrapTable($query->from) . ' restart identity cascade' => []];
}

/**
* Compile a "lateral join" clause.
*/
public function compileJoinLateral(JoinLateralClause $join, string $expression): string
{
return trim("{$join->type} join lateral {$expression} on true");
}

/**
* Substitute the given bindings into the given raw SQL query.
*
Expand Down
97 changes: 92 additions & 5 deletions tests/Cases/DatabasePostgresBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Schema\Schema;
use Hyperf\DbConnection\Db;
use Hyperf\Stringable\Str;
use HyperfTest\Database\PgSQL\Stubs\ContainerStub;
use HyperfTest\Database\PgSQL\Stubs\SwooleVersionStub;
use Mockery as m;
use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;

/**
Expand All @@ -42,9 +43,9 @@ protected function tearDown(): void
m::close();
}

#[RequiresPhpExtension('swoole', '< 6.0')]
public function testCreateDatabase()
{
SwooleVersionStub::skipV6();
$grammar = new PostgresGrammar();

$connection = m::mock(Connection::class);
Expand All @@ -58,9 +59,9 @@ public function testCreateDatabase()
$this->assertEquals(true, $builder->createDatabase('my_temporary_database'));
}

#[RequiresPhpExtension('swoole', '< 6.0')]
public function testDropDatabaseIfExists()
{
SwooleVersionStub::skipV6();
$grammar = new PostgresGrammar();

$connection = m::mock(Connection::class);
Expand All @@ -73,9 +74,9 @@ public function testDropDatabaseIfExists()
$this->assertEquals(true, $builder->dropDatabaseIfExists('my_database_a'));
}

#[RequiresPhpExtension('swoole', '< 6.0')]
public function testWhereFullText()
{
SwooleVersionStub::skipV6();
$builder = $this->getPostgresBuilderWithProcessor();
$builder->select('*')->from('users')->whereFullText('body', 'Hello World');
$this->assertSame('select * from "users" where (to_tsvector(\'english\', "body")) @@ plainto_tsquery(\'english\', ?)', $builder->toSql());
Expand Down Expand Up @@ -112,9 +113,95 @@ public function testWhereFullText()
$this->assertEquals(['Car Plane'], $builder->getBindings());
}

#[RequiresPhpExtension('swoole', '< 6.0')]
public function testJoinLateralPostgres()
{
$builder = $this->getPostgresBuilderWithProcessor();
$builder->getConnection()->shouldReceive('getDatabaseName');
$builder->from('users')->joinLateral(function ($q) {
$q->from('contacts')->whereColumn('contracts.user_id', 'users.id');
}, 'sub');
$this->assertSame('select * from "users" inner join lateral (select * from "contacts" where "contracts"."user_id" = "users"."id") as "sub" on true', $builder->toSql());
}

#[RequiresPhpExtension('swoole', '< 6.0')]
public function testJoinLateralTest(): void
{
$container = ContainerStub::getContainer();
$container->shouldReceive('get')->with(Db::class)->andReturn(new Db($container));
Schema::dropIfExists('join_posts');
Schema::dropIfExists('join_users');
Schema::create('join_users', static function (Blueprint $table) {
$table->id('id');
$table->string('name');
});

Schema::create('join_posts', static function (Blueprint $table) {
$table->id('id');
$table->string('title');
$table->integer('rating');
$table->unsignedBigInteger('user_id');
});
Db::table('join_users')->insert([
['name' => Str::random()],
['name' => Str::random()],
]);

Db::table('join_posts')->insert([
['title' => Str::random(), 'rating' => 1, 'user_id' => 1],
['title' => Str::random(), 'rating' => 3, 'user_id' => 1],
['title' => Str::random(), 'rating' => 7, 'user_id' => 1],
]);
$subquery = Db::table('join_posts')
->select('title as best_post_title', 'rating as best_post_rating')
->whereColumn('user_id', 'join_users.id')
->orderBy('rating', 'desc')
->limit(2);

$userWithPosts = Db::table('join_users')
->where('id', 1)
->joinLateral($subquery, 'best_post')
->get();

$this->assertCount(2, $userWithPosts);
$this->assertEquals(7, $userWithPosts[0]['best_post_rating']);
$this->assertEquals(3, $userWithPosts[1]['best_post_rating']);

$userWithoutPosts = Db::table('join_users')
->where('id', 2)
->joinLateral($subquery, 'best_post')
->get();

$this->assertCount(0, $userWithoutPosts);

$subquery = Db::table('join_posts')
->select('title as best_post_title', 'rating as best_post_rating')
->whereColumn('user_id', 'join_users.id')
->orderBy('rating', 'desc')
->limit(2);

$userWithPosts = Db::table('join_users')
->where('id', 1)
->leftJoinLateral($subquery, 'best_post')
->get();

$this->assertCount(2, $userWithPosts);
$this->assertEquals(7, $userWithPosts[0]['best_post_rating']);
$this->assertEquals(3, $userWithPosts[1]['best_post_rating']);

$userWithoutPosts = Db::table('join_users')
->where('id', 2)
->leftJoinLateral($subquery, 'best_post')
->get();

$this->assertCount(1, $userWithoutPosts);
$this->assertNull($userWithoutPosts[0]['best_post_title']);
$this->assertNull($userWithoutPosts[0]['best_post_rating']);
}

#[RequiresPhpExtension('swoole', '< 6.0')]
public function testWhereFullTextForReal()
{
SwooleVersionStub::skipV6();
$container = ContainerStub::getContainer();
$container->shouldReceive('get')->with(Db::class)->andReturn(new Db($container));

Expand Down
4 changes: 2 additions & 2 deletions tests/Cases/PostgreSqlSwooleExtConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
use Hyperf\Database\Schema\Schema;
use Hyperf\Support\Filesystem\Filesystem;
use HyperfTest\Database\PgSQL\Stubs\ContainerStub;
use HyperfTest\Database\PgSQL\Stubs\SwooleVersionStub;
use Mockery;
use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Style\OutputStyle;

Expand All @@ -34,13 +34,13 @@
* @coversNothing
*/
#[CoversNothing]
#[RequiresPhpExtension('swoole', '< 6.0')]
class PostgreSqlSwooleExtConnectionTest extends TestCase
{
protected Migrator $migrator;

public function setUp(): void
{
SwooleVersionStub::skipV6();
$resolver = ContainerStub::getContainer()->get(ConnectionResolverInterface::class);

$this->migrator = new Migrator(
Expand Down
4 changes: 2 additions & 2 deletions tests/DBAL/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
use Hyperf\Database\PgSQL\DBAL\Connection;
use Hyperf\Database\PgSQL\DBAL\Result;
use Hyperf\Database\PgSQL\DBAL\Statement;
use HyperfTest\Database\PgSQL\Stubs\SwooleVersionStub;
use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;
use Swoole\Coroutine\PostgreSQL;

Expand All @@ -25,13 +25,13 @@
* @coversNothing
*/
#[CoversNothing]
#[RequiresPhpExtension('swoole', '< 6.0')]
class ConnectionTest extends TestCase
{
protected Connection $connection;

public function setUp(): void
{
SwooleVersionStub::skipV6();
$pgsql = new PostgreSQL();
$connected = $pgsql->connect('host=127.0.0.1 port=5432 dbname=postgres user=postgres password=postgres');
if (! $connected) {
Expand Down
30 changes: 0 additions & 30 deletions tests/Stubs/SwooleVersionStub.php

This file was deleted.

0 comments on commit f430d57

Please sign in to comment.