Skip to content

Commit c3a816d

Browse files
committed
wip
1 parent 7415ff4 commit c3a816d

File tree

8 files changed

+146
-28
lines changed

8 files changed

+146
-28
lines changed

packages/database/src/Query.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public function execute(mixed ...$bindings): Id
3636

3737
public function fetch(mixed ...$bindings): array
3838
{
39+
lw($this->getSql());
3940
return $this->getDatabase()->fetch($this->withBindings($bindings));
4041
}
4142

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Tempest\Database\QueryStatements;
4+
5+
use Stringable;
6+
use Tempest\Database\Config\DatabaseDialect;
7+
use Tempest\Database\QueryStatement;
8+
9+
use function Tempest\Support\arr;
10+
11+
final readonly class FieldStatement implements QueryStatement
12+
{
13+
public function __construct(
14+
private string|Stringable $field,
15+
) {}
16+
17+
public function compile(DatabaseDialect $dialect): string
18+
{
19+
20+
21+
return arr(explode(' AS ', (string) $this->field))
22+
->map(function (string $part) use ($dialect) {
23+
return
24+
arr(explode('.', $part))
25+
->map(fn (string $part) => trim($part, '` '))
26+
->map(fn (string $part) => match ($dialect) {
27+
DatabaseDialect::SQLITE => $part,
28+
default => sprintf('`%s`', $part),
29+
})
30+
->implode('.');
31+
})
32+
->implode(' AS ');
33+
}
34+
}

packages/database/src/QueryStatements/JoinStatement.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

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

910
final readonly class JoinStatement implements QueryStatement

packages/database/src/QueryStatements/SelectStatement.php

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,12 @@ public function compile(DatabaseDialect $dialect): string
2929
$columns = $this->columns->isEmpty()
3030
? '*'
3131
: $this->columns
32-
->map(function (string|Stringable $column) {
32+
->map(function (string|Stringable $column) use ($dialect) {
3333
if ($column instanceof FieldDefinition) {
3434
return (string) $column;
3535
}
3636

37-
if (! str_starts_with($column, '`')) {
38-
$column = "`{$column}";
39-
}
40-
41-
if (! str_ends_with($column, '`')) {
42-
$column = "{$column}`";
43-
}
44-
45-
return (string) $column;
37+
return new FieldStatement($column)->compile($dialect);
4638
})
4739
->implode(', ');
4840

@@ -95,6 +87,15 @@ public function compile(DatabaseDialect $dialect): string
9587
->implode(PHP_EOL);
9688
}
9789

98-
return $query->implode(PHP_EOL);
90+
$compiled = $query->implode(PHP_EOL);
91+
92+
/* TODO: this should be improved.
93+
* More specifically, \Tempest\Database\Builder\FieldDefinition should be aware of the dialect,
94+
* or the whole ORM should be refactored to use \Tempest\Database\QueryStatements\FieldStatement*/
95+
// if ($dialect === DatabaseDialect::SQLITE) {
96+
// $compiled = $compiled->replace('`', '');
97+
// }
98+
99+
return $compiled;
99100
}
100101
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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\FieldStatement;
8+
9+
final class FieldStatementTest extends TestCase
10+
{
11+
public function test_sqlite(): void
12+
{
13+
$this->assertSame(
14+
'table.field',
15+
new FieldStatement('table.field')->compile(DatabaseDialect::SQLITE),
16+
);
17+
18+
$this->assertSame(
19+
'table.field',
20+
new FieldStatement('`table`.`field`')->compile(DatabaseDialect::SQLITE),
21+
);
22+
}
23+
24+
public function test_mysql(): void
25+
{
26+
$this->assertSame(
27+
'`table`.`field`',
28+
new FieldStatement('`table`.`field`')->compile(DatabaseDialect::MYSQL),
29+
);
30+
31+
$this->assertSame(
32+
'`table`.`field`',
33+
new FieldStatement('table.field')->compile(DatabaseDialect::MYSQL),
34+
);
35+
}
36+
37+
public function test_postgres(): void
38+
{
39+
$this->assertSame(
40+
'`table`.`field`',
41+
new FieldStatement('`table`.`field`')->compile(DatabaseDialect::POSTGRESQL),
42+
);
43+
44+
$this->assertSame(
45+
'`table`.`field`',
46+
new FieldStatement('table.field')->compile(DatabaseDialect::POSTGRESQL),
47+
);
48+
}
49+
50+
public function test_with_as(): void
51+
{
52+
$this->assertSame(
53+
'parent.through[].id AS parent.through[].id',
54+
new FieldStatement('`parent.through[]`.`id` AS `parent.through[].id`')->compile(DatabaseDialect::SQLITE),
55+
);
56+
57+
$this->assertSame(
58+
'`parent.through[]`.`id` AS `parent.through[].id`',
59+
new FieldStatement('`parent.through[]`.`id` AS `parent.through[].id`')->compile(DatabaseDialect::MYSQL),
60+
);
61+
}
62+
}

packages/database/tests/QueryStatements/JoinStatementTest.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,52 +12,52 @@ public function test_inner_join_is_added_when_needed(): void
1212
{
1313
$this->assertSame(
1414
'INNER JOIN authors on authors.id = books.author_id',
15-
new JoinStatement('authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
15+
new JoinStatement('authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL),
1616
);
1717

1818
$this->assertSame(
1919
'inner join authors on authors.id = books.author_id',
20-
new JoinStatement('inner join authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
20+
new JoinStatement('inner join authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL),
2121
);
2222

2323
$this->assertSame(
2424
'INNER JOIN authors on authors.id = books.author_id',
25-
new JoinStatement('INNER JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
25+
new JoinStatement('INNER JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL),
2626
);
2727

2828
$this->assertSame(
2929
'LEFT JOIN authors on authors.id = books.author_id',
30-
new JoinStatement('LEFT JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
30+
new JoinStatement('LEFT JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL),
3131
);
3232

3333
$this->assertSame(
3434
'RIGHT JOIN authors on authors.id = books.author_id',
35-
new JoinStatement('RIGHT JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
35+
new JoinStatement('RIGHT JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL),
3636
);
3737

3838
$this->assertSame(
3939
'FULL JOIN authors on authors.id = books.author_id',
40-
new JoinStatement('FULL JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
40+
new JoinStatement('FULL JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL),
4141
);
4242

4343
$this->assertSame(
4444
'JOIN authors on authors.id = books.author_id',
45-
new JoinStatement('JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
45+
new JoinStatement('JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL),
4646
);
4747

4848
$this->assertSame(
4949
'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)
50+
new JoinStatement('FULL OUTER JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL),
5151
);
5252

5353
$this->assertSame(
5454
'FULL JOIN authors on authors.id = books.author_id',
55-
new JoinStatement('FULL JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
55+
new JoinStatement('FULL JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL),
5656
);
5757

5858
$this->assertSame(
5959
'SELF JOIN authors on authors.id = books.author_id',
60-
new JoinStatement('SELF JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL)
60+
new JoinStatement('SELF JOIN authors on authors.id = books.author_id')->compile(DatabaseDialect::MYSQL),
6161
);
6262
}
63-
}
63+
}

packages/database/tests/QueryStatements/SelectStatementTest.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function test_select(): void
3333
offset: 100,
3434
);
3535

36-
$expected = <<<SQL
36+
$expectedWithBackticks = <<<SQL
3737
SELECT `a`, `b`, `c`, `bar`.`d` AS `d_alias`
3838
FROM `foo` AS `bar`
3939
INNER JOIN foo ON bar.id = foo.id
@@ -45,8 +45,21 @@ public function test_select(): void
4545
OFFSET 100
4646
SQL;
4747

48-
$this->assertSame($expected, $statement->compile(DatabaseDialect::MYSQL));
49-
$this->assertSame($expected, $statement->compile(DatabaseDialect::POSTGRESQL));
50-
$this->assertSame($expected, $statement->compile(DatabaseDialect::SQLITE));
48+
$this->assertSame($expectedWithBackticks, $statement->compile(DatabaseDialect::MYSQL));
49+
$this->assertSame($expectedWithBackticks, $statement->compile(DatabaseDialect::POSTGRESQL));
50+
51+
$expectedWithoutBackticks = <<<SQL
52+
SELECT a, b, c, bar.d AS d_alias
53+
FROM foo AS bar
54+
INNER JOIN foo ON bar.id = foo.id
55+
WHERE foo = "bar"
56+
ORDER BY foo DESC
57+
GROUP BY foo
58+
HAVING foo = "bar"
59+
LIMIT 10
60+
OFFSET 100
61+
SQL;
62+
63+
$this->assertSame($expectedWithoutBackticks, $statement->compile(DatabaseDialect::SQLITE));
5164
}
5265
}

tests/Integration/Database/Builder/SelectQueryBuilderTest.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,15 @@ public function test_join(): void
103103
$author = Author::new(name: 'Brent')->save();
104104
Book::new(title: 'A', author: $author)->save();
105105

106-
$query = query(Book::class)->select()->join('authors on authors.id = books.author_id')->first();
106+
$query = query('books')->select('books.title AS book_title', 'authors.name')->join('authors on authors.id = books.author_id');
107107

108-
$this->assertSame('Brent', $query->author->name);
108+
$this->assertSame(
109+
[
110+
'book_title' => 'A',
111+
'name' => 'Brent',
112+
],
113+
$query->first(),
114+
);
109115
}
110116

111117
public function test_order_by(): void

0 commit comments

Comments
 (0)