Skip to content

Commit e4a97bd

Browse files
committed
wip
1 parent 76f204e commit e4a97bd

File tree

4 files changed

+55
-46
lines changed

4 files changed

+55
-46
lines changed

packages/database/src/Config/DatabaseDialect.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Tempest\Database\Config;
66

7+
use PDOException;
8+
79
enum DatabaseDialect: string
810
{
911
case SQLITE = 'sqlite';
@@ -18,4 +20,13 @@ public function tableNotFoundCode(): string
1820
self::SQLITE => 'HY000',
1921
};
2022
}
23+
24+
public function isTableNotFoundError(PDOException $exception): bool
25+
{
26+
return match($this) {
27+
self::MYSQL => $exception->getCode() === '42S02' && str_contains($exception->getMessage(), 'table'),
28+
self::SQLITE => $exception->getCode() === 'HY000' && str_contains($exception->getMessage(), 'table'),
29+
self::POSTGRESQL => $exception->getCode() === '42P01' && str_contains($exception->getMessage(), 'relation'),
30+
};
31+
}
2132
}

packages/database/src/GenericDatabase.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@ public function getLastInsertId(): Id|null
6969

7070
public function fetch(Query $query): array
7171
{
72+
$bindings = $this->resolveBindings($query);
73+
7274
$pdoQuery = $this->connection->prepare($query->toSql());
7375

74-
$pdoQuery->execute($this->resolveBindings($query));
76+
$pdoQuery->execute($bindings);
7577

7678
return $pdoQuery->fetchAll(PDO::FETCH_NAMED);
7779
}
@@ -89,8 +91,6 @@ public function withinTransaction(callable $callback): bool
8991
$callback();
9092

9193
$this->transactionManager->commit();
92-
} catch (PDOException) {
93-
return false;
9494
} catch (Throwable) {
9595
$this->transactionManager->rollback();
9696

packages/database/src/Migrations/MigrationManager.php

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use PDOException;
88
use Tempest\Database\Builder\ModelDefinition;
9-
use Tempest\Database\Config\DatabaseConfig;
109
use Tempest\Database\Config\DatabaseDialect;
1110
use Tempest\Database\Database;
1211
use Tempest\Database\DatabaseMigration as MigrationInterface;
@@ -18,14 +17,13 @@
1817
use Tempest\Database\QueryStatements\SetForeignKeyChecksStatement;
1918
use Tempest\Database\QueryStatements\ShowTablesStatement;
2019
use Throwable;
21-
use UnhandledMatchError;
2220

2321
use function Tempest\event;
2422

2523
final readonly class MigrationManager
2624
{
2725
public function __construct(
28-
private DatabaseConfig $databaseConfig,
26+
private DatabaseDialect $dialect,
2927
private Database $database,
3028
private RunnableMigrations $migrations,
3129
) {}
@@ -35,7 +33,7 @@ public function up(): void
3533
try {
3634
$existingMigrations = Migration::all();
3735
} catch (PDOException $pdoException) {
38-
if ($pdoException->getCode() === $this->databaseConfig->dialect->tableNotFoundCode() && str_contains($pdoException->getMessage(), 'table')) {
36+
if ($this->dialect->isTableNotFoundError($pdoException)) {
3937
$this->executeUp(new CreateMigrationsTable());
4038
$existingMigrations = Migration::all();
4139
} else {
@@ -62,13 +60,14 @@ public function down(): void
6260
try {
6361
$existingMigrations = Migration::all();
6462
} catch (PDOException $pdoException) {
65-
/** @throw UnhandledMatchError */
66-
match ((string) $pdoException->getCode()) {
67-
$this->databaseConfig->dialect->tableNotFoundCode() => event(
68-
event: new MigrationFailed(name: new ModelDefinition(Migration::class)->getTableDefinition()->name, exception: new TableNotFoundException()),
69-
),
70-
default => throw new UnhandledMatchError($pdoException->getMessage()),
71-
};
63+
if (! $this->dialect->isTableNotFoundError($pdoException)) {
64+
throw $pdoException;
65+
}
66+
67+
event(new MigrationFailed(
68+
name: new ModelDefinition(Migration::class)->getTableDefinition()->name,
69+
exception: new TableNotFoundException(),
70+
));
7271

7372
return;
7473
}
@@ -90,26 +89,24 @@ public function down(): void
9089

9190
public function dropAll(): void
9291
{
93-
$dialect = $this->databaseConfig->dialect;
94-
9592
try {
9693
// Get all tables
97-
$tables = $this->getTableDefinitions($dialect);
94+
$tables = $this->getTableDefinitions();
9895

9996
// Disable foreign key checks
100-
new SetForeignKeyChecksStatement(enable: false)->execute($dialect);
97+
new SetForeignKeyChecksStatement(enable: false)->execute($this->dialect);
10198

10299
// Drop each table
103100
foreach ($tables as $table) {
104-
new DropTableStatement($table->name)->execute($dialect);
101+
new DropTableStatement($table->name)->execute($this->dialect);
105102

106103
event(new TableDropped($table->name));
107104
}
108105
} catch (Throwable $throwable) {
109106
event(new FreshMigrationFailed($throwable));
110107
} finally {
111108
// Enable foreign key checks
112-
new SetForeignKeyChecksStatement(enable: true)->execute($dialect);
109+
new SetForeignKeyChecksStatement(enable: true)->execute($this->dialect);
113110
}
114111
}
115112

@@ -180,9 +177,7 @@ public function executeUp(MigrationInterface $migration): void
180177
return;
181178
}
182179

183-
$dialect = $this->databaseConfig->dialect;
184-
185-
$query = new Query($statement->compile($dialect));
180+
$query = new Query($statement->compile($this->dialect));
186181

187182
try {
188183
$this->database->execute($query);
@@ -208,23 +203,21 @@ public function executeDown(MigrationInterface $migration): void
208203
return;
209204
}
210205

211-
$dialect = $this->databaseConfig->dialect;
212-
213-
$query = new Query($statement->compile($dialect));
206+
$query = new Query($statement->compile($this->dialect));
214207

215208
try {
216209
// TODO: don't just disable FK checking when executing down
217210

218211
// Disable foreign key checks
219-
new SetForeignKeyChecksStatement(enable: false)->execute($dialect);
212+
new SetForeignKeyChecksStatement(enable: false)->execute($this->dialect);
220213

221214
$this->database->execute($query);
222215

223216
// Disable foreign key checks
224-
new SetForeignKeyChecksStatement(enable: true)->execute($dialect);
217+
new SetForeignKeyChecksStatement(enable: true)->execute($this->dialect);
225218
} catch (PDOException $pdoException) {
226219
// Disable foreign key checks
227-
new SetForeignKeyChecksStatement(enable: true)->execute($dialect);
220+
new SetForeignKeyChecksStatement(enable: true)->execute($this->dialect);
228221

229222
event(new MigrationFailed($migration->name, $pdoException));
230223

@@ -253,15 +246,15 @@ public function executeDown(MigrationInterface $migration): void
253246
/**
254247
* @return \Tempest\Database\Migrations\TableMigrationDefinition[]
255248
*/
256-
private function getTableDefinitions(DatabaseDialect $dialect): array
249+
private function getTableDefinitions(): array
257250
{
258251
return array_map(
259-
fn (array $item) => match ($dialect) {
252+
fn (array $item) => match ($this->dialect) {
260253
DatabaseDialect::SQLITE => new TableMigrationDefinition($item['name']),
261254
DatabaseDialect::POSTGRESQL => new TableMigrationDefinition($item['table_name']),
262255
DatabaseDialect::MYSQL => new TableMigrationDefinition(array_values($item)[0]),
263256
},
264-
new ShowTablesStatement()->fetch($dialect),
257+
new ShowTablesStatement()->fetch($this->dialect),
265258
);
266259
}
267260

@@ -279,7 +272,7 @@ private function getMinifiedSqlFromStatement(?QueryStatement $statement): string
279272
return '';
280273
}
281274

282-
$query = new Query($statement->compile($this->databaseConfig->dialect));
275+
$query = new Query($statement->compile($this->dialect));
283276

284277
// Remove comments
285278
$sql = preg_replace('/--.*$/m', '', $query->toSql()); // Remove SQL single-line comments

tests/Integration/Database/GenericDatabaseTest.php

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
use Exception;
88
use Tempest\Database\Database;
99
use Tempest\Database\Migrations\CreateMigrationsTable;
10-
use Tempest\Database\Migrations\Migration;
1110
use Tests\Tempest\Fixtures\Migrations\CreateAuthorTable;
1211
use Tests\Tempest\Fixtures\Migrations\CreatePublishersTable;
1312
use Tests\Tempest\Fixtures\Modules\Books\Models\Author;
1413
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
14+
use function Tempest\Database\query;
1515

1616
/**
1717
* @internal
@@ -20,28 +20,33 @@ final class GenericDatabaseTest extends FrameworkIntegrationTestCase
2020
{
2121
public function test_transaction_manager_execute(): void
2222
{
23-
$manager = $this->container->get(Database::class);
23+
$this->migrate(CreateMigrationsTable::class, CreatePublishersTable::class, CreateAuthorTable::class);
24+
25+
$db = $this->container->get(Database::class);
2426

25-
$manager->withinTransaction(function (): void {
26-
$this->console
27-
->call('migrate:up');
27+
$db->withinTransaction(function (): void {
28+
query(Author::class)->insert(
29+
name: 'Brent',
30+
)->execute();
2831
});
2932

30-
$this->assertNotEmpty(Migration::all());
33+
$this->assertSame(1, query(Author::class)->count()->execute());
3134
}
3235

33-
public function test_execute_with_fail_works_correctly(): void
36+
public function test_transaction_manager_fails(): void
3437
{
35-
$database = $this->container->get(Database::class);
36-
3738
$this->migrate(CreateMigrationsTable::class, CreatePublishersTable::class, CreateAuthorTable::class);
3839

39-
$database->withinTransaction(function (): never {
40-
new Author(name: 'test')->save();
40+
$db = $this->container->get(Database::class);
41+
42+
$db->withinTransaction(function (): void {
43+
query(Author::class)->insert(
44+
name: 'Brent',
45+
)->execute();
4146

42-
throw new Exception('Dummy exception to force rollback');
47+
throw new Exception('Test');
4348
});
4449

45-
$this->assertCount(0, Author::all());
50+
$this->assertSame(0, query(Author::class)->count()->execute());
4651
}
4752
}

0 commit comments

Comments
 (0)