Skip to content

Commit fd63ec0

Browse files
authored
fix(database): make AlterTableStatement produce valid SQL (#979)
1 parent 768c6fb commit fd63ec0

18 files changed

+478
-280
lines changed

src/Tempest/Database/src/QueryStatements/Alter.php

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/Tempest/Database/src/QueryStatements/AlterStatement.php renamed to src/Tempest/Database/src/QueryStatements/AlterAddColumnStatement.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,15 @@
77
use Tempest\Database\Config\DatabaseDialect;
88
use Tempest\Database\QueryStatement;
99

10-
final readonly class AlterStatement implements QueryStatement
10+
final readonly class AlterAddColumnStatement implements QueryStatement
1111
{
1212
public function __construct(
13-
private Alter $type,
1413
private QueryStatement $statement,
1514
) {
1615
}
1716

1817
public function compile(DatabaseDialect $dialect): string
1918
{
20-
return sprintf(
21-
'%s %s',
22-
$this->type->compile($dialect),
23-
$this->statement->compile($dialect),
24-
);
19+
return sprintf('ADD %s', $this->statement->compile($dialect));
2520
}
2621
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Database\QueryStatements;
6+
7+
use Tempest\Database\Config\DatabaseDialect;
8+
use Tempest\Database\QueryStatement;
9+
10+
final readonly class AlterDropStatement implements QueryStatement
11+
{
12+
public function __construct(
13+
private ColumnNameStatement|ConstraintNameStatement $toDrop,
14+
) {
15+
}
16+
17+
public function compile(DatabaseDialect $dialect): string
18+
{
19+
return sprintf('DROP %s', $this->toDrop->compile($dialect));
20+
}
21+
}

src/Tempest/Database/src/QueryStatements/AlterTableStatement.php

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,62 +29,58 @@ public static function forModel(string $modelClass): self
2929

3030
public function add(QueryStatement $statement): self
3131
{
32-
$this->statements[] = new AlterStatement(Alter::ADD, $statement);
32+
$this->statements[] = new AlterAddColumnStatement($statement);
3333

3434
return $this;
3535
}
3636

37-
public function update(QueryStatement $statement): self
37+
public function unique(string ...$columns): self
3838
{
39-
$this->statements[] = new AlterStatement(Alter::UPDATE, $statement);
39+
$this->createIndexStatements[] = new UniqueStatement(
40+
tableName: $this->tableName,
41+
columns: $columns,
42+
);
4043

4144
return $this;
4245
}
4346

44-
public function delete(string $table): self
47+
public function index(string ...$columns): self
4548
{
46-
$this->statements[] = new AlterStatement(
47-
Alter::DELETE,
48-
new RawStatement($table),
49+
$this->createIndexStatements[] = new IndexStatement(
50+
tableName: $this->tableName,
51+
columns: $columns,
4952
);
5053

5154
return $this;
5255
}
5356

54-
public function constraint(string $constraintName, ?QueryStatement $statement = null): self
57+
public function dropColumn(string $name): self
5558
{
56-
$this->statements[] = new ConstraintStatement($constraintName, $statement);
57-
58-
if ($statement !== null) {
59-
$this->statements[] = $statement;
60-
}
59+
$this->statements[] = new AlterDropStatement(ColumnNameStatement::fromString($name));
6160

6261
return $this;
6362
}
6463

65-
public function unique(string ...$columns): self
64+
public function dropConstraint(string $name): self
6665
{
67-
$this->createIndexStatements[] = new UniqueStatement(
68-
tableName: $this->tableName,
69-
columns: $columns,
70-
);
66+
$this->statements[] = new AlterDropStatement(ConstraintNameStatement::fromString($name));
7167

7268
return $this;
7369
}
7470

75-
public function index(string ...$columns): self
71+
public function rename(string $from, string $to): self
7672
{
77-
$this->createIndexStatements[] = new IndexStatement(
78-
tableName: $this->tableName,
79-
columns: $columns,
73+
$this->statements[] = new RenameColumnStatement(
74+
new IdentityStatement($from),
75+
new IdentityStatement($to),
8076
);
8177

8278
return $this;
8379
}
8480

85-
public function drop(QueryStatement $statement): self
81+
public function modify(QueryStatement $column): self
8682
{
87-
$this->statements[] = new AlterStatement(Alter::DROP, $statement);
83+
$this->statements[] = new ModifyColumnStatement($column);
8884

8985
return $this;
9086
}

src/Tempest/Database/src/QueryStatements/BelongsToStatement.php

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

77
use Tempest\Database\Config\DatabaseDialect;
88
use Tempest\Database\QueryStatement;
9+
use Tempest\Database\UnsupportedDialect;
910

1011
final readonly class BelongsToStatement implements QueryStatement
1112
{
@@ -24,11 +25,13 @@ public function compile(DatabaseDialect $dialect): string
2425

2526
return match ($dialect) {
2627
DatabaseDialect::MYSQL, DatabaseDialect::POSTGRESQL => new ConstraintStatement(
27-
sprintf(
28-
'fk_%s_%s_%s',
29-
strtolower($foreignTable),
30-
strtolower($localTable),
31-
strtolower($localKey),
28+
ConstraintNameStatement::fromString(
29+
sprintf(
30+
'fk_%s_%s_%s',
31+
strtolower($foreignTable),
32+
strtolower($localTable),
33+
strtolower($localKey),
34+
),
3235
),
3336
new RawStatement(
3437
sprintf(
@@ -42,7 +45,7 @@ public function compile(DatabaseDialect $dialect): string
4245
),
4346
),
4447
)->compile($dialect),
45-
DatabaseDialect::SQLITE => '',
48+
DatabaseDialect::SQLITE => throw new UnsupportedDialect(),
4649
};
4750
}
4851
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Database\QueryStatements;
6+
7+
use Tempest\Database\Config\DatabaseDialect;
8+
use Tempest\Database\QueryStatement;
9+
10+
final readonly class ColumnNameStatement implements QueryStatement
11+
{
12+
public static function fromString(string $name): self
13+
{
14+
return new self(new IdentityStatement($name));
15+
}
16+
17+
public function __construct(
18+
private IdentityStatement $name,
19+
) {
20+
}
21+
22+
public function compile(DatabaseDialect $dialect): string
23+
{
24+
return sprintf('COLUMN %s', $this->name->compile($dialect));
25+
}
26+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Database\QueryStatements;
6+
7+
use Tempest\Database\Config\DatabaseDialect;
8+
use Tempest\Database\QueryStatement;
9+
use Tempest\Database\UnsupportedDialect;
10+
11+
final readonly class ConstraintNameStatement implements QueryStatement
12+
{
13+
public static function fromString(string $name): self
14+
{
15+
return new self(new IdentityStatement($name));
16+
}
17+
18+
public function __construct(
19+
private IdentityStatement $name,
20+
) {
21+
}
22+
23+
public function compile(DatabaseDialect $dialect): string
24+
{
25+
return match ($dialect) {
26+
DatabaseDialect::MYSQL, DatabaseDialect::POSTGRESQL => sprintf('CONSTRAINT %s', $this->name->compile($dialect)),
27+
default => throw new UnsupportedDialect(),
28+
};
29+
}
30+
}

src/Tempest/Database/src/QueryStatements/ConstraintStatement.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,21 @@
66

77
use Tempest\Database\Config\DatabaseDialect;
88
use Tempest\Database\QueryStatement;
9+
use Tempest\Database\UnsupportedDialect;
910

1011
final readonly class ConstraintStatement implements QueryStatement
1112
{
1213
public function __construct(
13-
private string $constraintName,
14+
private ConstraintNameStatement $constraintName,
1415
private QueryStatement $statement,
1516
) {
1617
}
1718

1819
public function compile(DatabaseDialect $dialect): string
1920
{
2021
return sprintf(
21-
'CONSTRAINT %s %s',
22-
$this->constraintName,
22+
'%s %s',
23+
$this->constraintName->compile($dialect),
2324
$this->statement->compile($dialect),
2425
);
2526
}

src/Tempest/Database/src/QueryStatements/CreateTableStatement.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Tempest\Database\QueryStatements;
66

77
use BackedEnum;
8+
use Symfony\Component\VarDumper\Cloner\Data;
89
use Tempest\Database\Builder\TableName;
910
use Tempest\Database\Config\DatabaseDialect;
1011
use Tempest\Database\QueryStatement;
@@ -43,7 +44,7 @@ public function belongsTo(
4344
OnUpdate $onUpdate = OnUpdate::NO_ACTION,
4445
bool $nullable = false,
4546
): self {
46-
[$localTable, $localKey] = explode('.', $local);
47+
[, $localKey] = explode('.', $local);
4748

4849
$this->integer($localKey, nullable: $nullable);
4950

@@ -268,8 +269,10 @@ public function compile(DatabaseDialect $dialect): string
268269
'CREATE TABLE %s (%s);',
269270
new TableName($this->tableName),
270271
arr($this->statements)
272+
// Remove BelongsTo for sqlLite as it does not support those queries
273+
->filter(fn (QueryStatement $queryStatement) => ! ($dialect === DatabaseDialect::SQLITE && $queryStatement instanceof BelongsToStatement))
271274
->map(fn (QueryStatement $queryStatement) => str($queryStatement->compile($dialect))->trim()->replace(' ', ' '))
272-
->filter(fn (ImmutableString $line) => $line->isNotEmpty())
275+
->filter(fn (ImmutableString $str) => $str->isNotEmpty())
273276
->implode(', ' . PHP_EOL . ' ')
274277
->wrap(before: PHP_EOL . ' ', after: PHP_EOL)
275278
->toString(),

src/Tempest/Database/src/QueryStatements/ForeignKeyStatement.php

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)