Skip to content

Commit 7415ff4

Browse files
committed
wip
1 parent c1561e0 commit 7415ff4

File tree

4 files changed

+102
-5
lines changed

4 files changed

+102
-5
lines changed

packages/database/src/Builder/QueryBuilders/SelectQueryBuilder.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ final class SelectQueryBuilder implements BuildsQuery
3737

3838
private SelectStatement $select;
3939

40+
private array $joins = [];
41+
4042
private array $relations = [];
4143

4244
private array $bindings = [];
@@ -170,6 +172,14 @@ public function offset(int $offset): self
170172
return $this;
171173
}
172174

175+
/** @return self<TModelClass> */
176+
public function join(string ...$joins): self
177+
{
178+
$this->joins = [...$this->joins, ...$joins];
179+
180+
return $this;
181+
}
182+
173183
/** @return self<TModelClass> */
174184
public function with(string ...$relations): self
175185
{
@@ -203,6 +213,10 @@ public function build(mixed ...$bindings): Query
203213
{
204214
$resolvedRelations = $this->resolveRelations();
205215

216+
foreach ($this->joins as $join) {
217+
$this->select->join[] = new JoinStatement($join);
218+
}
219+
206220
foreach ($resolvedRelations as $relation) {
207221
$this->select->columns = $this->select->columns->append(...$relation->getFieldDefinitions()->map(fn (FieldDefinition $field) => (string) $field->withAlias()));
208222
$this->select->join[] = new JoinStatement($relation->getStatement());

packages/database/src/QueryStatements/JoinStatement.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,22 @@
44

55
use Tempest\Database\Config\DatabaseDialect;
66
use Tempest\Database\QueryStatement;
7+
use function Tempest\Support\str;
78

89
final readonly class JoinStatement implements QueryStatement
910
{
1011
public function __construct(
11-
private string $join,
12+
private string $statement,
1213
) {}
1314

1415
public function compile(DatabaseDialect $dialect): string
1516
{
16-
return $this->join;
17+
$statement = $this->statement;
18+
19+
if (! str($statement)->lower()->startsWith(['join', 'inner join', 'left join', 'right join', 'full join', 'full outer join', 'self join'])) {
20+
$statement = sprintf('INNER JOIN %s', $statement);
21+
}
22+
23+
return $statement;
1724
}
1825
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace Tempest\Database\Tests\QueryStatements;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use Tempest\Database\Config\DatabaseDialect;
7+
use Tempest\Database\QueryStatements\JoinStatement;
8+
9+
final class JoinStatementTest extends TestCase
10+
{
11+
public function test_inner_join_is_added_when_needed(): void
12+
{
13+
$this->assertSame(
14+
'INNER JOIN authors on authors.id = books.author_id',
15+
new JoinStatement('authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
16+
);
17+
18+
$this->assertSame(
19+
'inner join authors on authors.id = books.author_id',
20+
new JoinStatement('inner join authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
21+
);
22+
23+
$this->assertSame(
24+
'INNER JOIN authors on authors.id = books.author_id',
25+
new JoinStatement('INNER JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
26+
);
27+
28+
$this->assertSame(
29+
'LEFT JOIN authors on authors.id = books.author_id',
30+
new JoinStatement('LEFT JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
31+
);
32+
33+
$this->assertSame(
34+
'RIGHT JOIN authors on authors.id = books.author_id',
35+
new JoinStatement('RIGHT JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
36+
);
37+
38+
$this->assertSame(
39+
'FULL JOIN authors on authors.id = books.author_id',
40+
new JoinStatement('FULL JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
41+
);
42+
43+
$this->assertSame(
44+
'JOIN authors on authors.id = books.author_id',
45+
new JoinStatement('JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
46+
);
47+
48+
$this->assertSame(
49+
'FULL OUTER JOIN authors on authors.id = books.author_id',
50+
new JoinStatement('FULL OUTER JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
51+
);
52+
53+
$this->assertSame(
54+
'FULL JOIN authors on authors.id = books.author_id',
55+
new JoinStatement('FULL JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
56+
);
57+
58+
$this->assertSame(
59+
'SELF JOIN authors on authors.id = books.author_id',
60+
new JoinStatement('SELF JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
61+
);
62+
}
63+
}

tests/Integration/Database/Builder/SelectQueryBuilderTest.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
namespace Tests\Tempest\Integration\Database\Builder;
66

77
use Tempest\Database\Builder\QueryBuilders\SelectQueryBuilder;
8-
use Tempest\Database\Database;
98
use Tempest\Database\Migrations\CreateMigrationsTable;
10-
use Tempest\Database\Query;
11-
use Tempest\Database\QueryStatements\CreateTableStatement;
129
use Tests\Tempest\Fixtures\Migrations\CreateAuthorTable;
1310
use Tests\Tempest\Fixtures\Migrations\CreateBookTable;
1411
use Tests\Tempest\Fixtures\Modules\Books\Models\Author;
@@ -95,6 +92,22 @@ public function test_where_statement(): void
9592
$this->assertSame('B', $book->title);
9693
}
9794

95+
public function test_join(): void
96+
{
97+
$this->migrate(
98+
CreateMigrationsTable::class,
99+
CreateAuthorTable::class,
100+
CreateBookTable::class,
101+
);
102+
103+
$author = Author::new(name: 'Brent')->save();
104+
Book::new(title: 'A', author: $author)->save();
105+
106+
$query = query(Book::class)->select()->join('authors on authors.id = books.author_id')->first();
107+
108+
$this->assertSame('Brent', $query->author->name);
109+
}
110+
98111
public function test_order_by(): void
99112
{
100113
$this->migrate(

0 commit comments

Comments
 (0)