Skip to content

Commit 6c8b9fe

Browse files
authored
feat(database): autodetect char size by default value (#2099)
1 parent f84cf41 commit 6c8b9fe

3 files changed

Lines changed: 75 additions & 6 deletions

File tree

packages/database/src/QueryStatements/CharStatement.php

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

77
use Tempest\Database\Config\DatabaseDialect;
8+
use Tempest\Database\Exceptions\DefaultValueWasInvalid;
89
use Tempest\Database\QueryStatement;
910

1011
final readonly class CharStatement implements QueryStatement
1112
{
1213
public function __construct(
1314
private string $name,
14-
private int $size,
15+
private ?int $size = null,
1516
private bool $nullable = false,
1617
private ?string $default = null,
1718
) {}
1819

1920
public function compile(DatabaseDialect $dialect): string
2021
{
22+
if ($this->size !== null && $this->default !== null && $this->size < mb_strlen($this->default)) {
23+
throw new DefaultValueWasInvalid($this->name, $this->default);
24+
}
25+
2126
return sprintf(
22-
'%s CHAR(%s) %s %s',
27+
'%s CHAR(%s)%s%s',
2328
$dialect->quoteIdentifier($this->name),
24-
$this->size,
25-
$this->default !== null ? "DEFAULT '{$this->default}'" : '',
26-
$this->nullable ? '' : 'NOT NULL',
29+
$this->determineSize(),
30+
$this->default !== null ? " DEFAULT '{$this->default}'" : '',
31+
$this->nullable ? '' : ' NOT NULL',
2732
);
2833
}
34+
35+
public function determineSize(): int
36+
{
37+
if ($this->size !== null) {
38+
return $this->size;
39+
}
40+
41+
if ($this->default !== null) {
42+
return mb_strlen($this->default);
43+
}
44+
45+
return 1;
46+
}
2947
}

packages/database/src/QueryStatements/CreateTableStatement.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ public function string(string $name, int $length = 255, bool $nullable = false,
186186
/**
187187
* Adds a `CHAR` column to the table.
188188
*/
189-
public function char(string $name, bool $nullable = false, ?string $default = null, int $size = 1): self
189+
public function char(string $name, bool $nullable = false, ?string $default = null, ?int $size = null): self
190190
{
191191
$this->statements[] = new CharStatement(
192192
name: $name,

packages/database/tests/QueryStatements/CharStatementTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PHPUnit\Framework\Attributes\Test;
66
use PHPUnit\Framework\TestCase;
77
use Tempest\Database\Config\DatabaseDialect;
8+
use Tempest\Database\Exceptions\DefaultValueWasInvalid;
89
use Tempest\Database\QueryStatements\CharStatement;
910

1011
final class CharStatementTest extends TestCase
@@ -25,4 +26,54 @@ public function test_char(): void
2526
$this->assertSame($expectedMysql, $statement->compile(DatabaseDialect::MYSQL));
2627
$this->assertSame($expectedPgsql, $statement->compile(DatabaseDialect::POSTGRESQL));
2728
}
29+
30+
#[Test]
31+
public function test_determine_char_size(): void
32+
{
33+
$fixedSizeStatement = new CharStatement(
34+
name: 'foo',
35+
size: 10,
36+
);
37+
$expectedMysql = '`foo` CHAR(10) NOT NULL';
38+
$this->assertSame($expectedMysql, $fixedSizeStatement->compile(DatabaseDialect::MYSQL));
39+
40+
$defaultSizeStatement = new CharStatement(
41+
name: 'foo',
42+
default: 'foo_bar',
43+
);
44+
$expectedMysql = '`foo` CHAR(7) DEFAULT \'foo_bar\' NOT NULL';
45+
$this->assertSame($expectedMysql, $defaultSizeStatement->compile(DatabaseDialect::MYSQL));
46+
47+
$fixedAndDefaultSizeStatement = new CharStatement(
48+
name: 'foo',
49+
size: 7,
50+
default: 'foo_bar',
51+
);
52+
$expectedMysql = '`foo` CHAR(7) DEFAULT \'foo_bar\' NOT NULL';
53+
$this->assertSame($expectedMysql, $fixedAndDefaultSizeStatement->compile(DatabaseDialect::MYSQL));
54+
}
55+
56+
#[Test]
57+
public function test_char_size_less_than_default_value_length(): void
58+
{
59+
$this->expectException(DefaultValueWasInvalid::class);
60+
61+
$statement = new CharStatement(
62+
name: 'foo',
63+
size: 1,
64+
default: 'foo_bar',
65+
);
66+
$statement->compile(DatabaseDialect::MYSQL);
67+
}
68+
69+
public function test_char_size_greater_than_default_value_length(): void
70+
{
71+
$statement = new CharStatement(
72+
name: 'foo',
73+
size: 10,
74+
default: 'foo_bar',
75+
);
76+
$expectedMysql = '`foo` CHAR(10) DEFAULT \'foo_bar\' NOT NULL';
77+
$this->assertSame($expectedMysql, $statement->compile(DatabaseDialect::MYSQL));
78+
}
2879
}

0 commit comments

Comments
 (0)