From 4450dab3bc00b82362897f55b3be4adee0b447b4 Mon Sep 17 00:00:00 2001 From: DevPandi Date: Mon, 16 Feb 2026 20:37:27 +0100 Subject: [PATCH 1/2] idea from #1972 integer in standard sql supports bigint (8 bytes), integer (4 bytes) and smallint (2 bytes). Tiny INT is SQL. --- .../QueryStatements/CreateTableStatement.php | 3 +- .../src/QueryStatements/IntegerBytes.php | 30 +++++++++++ .../src/QueryStatements/IntegerStatement.php | 25 ++++++--- .../CreateTableStatementTest.php | 4 ++ .../CreateTableStatementTest.php | 51 +++++++++++++++++++ 5 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 packages/database/src/QueryStatements/IntegerBytes.php diff --git a/packages/database/src/QueryStatements/CreateTableStatement.php b/packages/database/src/QueryStatements/CreateTableStatement.php index ab3bba8d73..4ecdc6c94b 100644 --- a/packages/database/src/QueryStatements/CreateTableStatement.php +++ b/packages/database/src/QueryStatements/CreateTableStatement.php @@ -199,12 +199,13 @@ public function char(string $name, bool $nullable = false, ?string $default = nu /** * Adds an `INTEGER` column to the table. */ - public function integer(string $name, bool $unsigned = false, bool $nullable = false, ?int $default = null): self + public function integer(string $name, bool $unsigned = false, bool $nullable = false, int $bytes = 4, ?int $default = null): self { $this->statements[] = new IntegerStatement( name: $name, unsigned: $unsigned, nullable: $nullable, + bytes: $bytes, default: $default, ); diff --git a/packages/database/src/QueryStatements/IntegerBytes.php b/packages/database/src/QueryStatements/IntegerBytes.php new file mode 100644 index 0000000000..ab3e9f39d6 --- /dev/null +++ b/packages/database/src/QueryStatements/IntegerBytes.php @@ -0,0 +1,30 @@ + self::DEFAULT->value => IntegerBytes::BIG, + $bytes > self::SMALL->value => IntegerBytes::DEFAULT, + DEFAULT => IntegerBytes::SMALL, + }; + } + + public function toString(): string + { + return match($this) { + IntegerBytes::SMALL => 'SMALLINT', + IntegerBytes::DEFAULT => 'INTEGER', + IntegerBytes::BIG => 'BIGINT', + }; + } +} diff --git a/packages/database/src/QueryStatements/IntegerStatement.php b/packages/database/src/QueryStatements/IntegerStatement.php index 793ac48990..fcbc90e13e 100644 --- a/packages/database/src/QueryStatements/IntegerStatement.php +++ b/packages/database/src/QueryStatements/IntegerStatement.php @@ -13,17 +13,28 @@ public function __construct( private string $name, private bool $unsigned = false, private bool $nullable = false, + private int $bytes = 4, private ?int $default = null, ) {} public function compile(DatabaseDialect $dialect): string { - return sprintf( - '`%s` INTEGER %s %s %s', - $this->name, - $this->unsigned ? 'UNSIGNED' : '', - $this->default !== null ? "DEFAULT {$this->default}" : '', - $this->nullable ? '' : 'NOT NULL', - ); + return match($dialect) { + DatabaseDialect::SQLITE => sprintf( + '`%s` INTEGER %s %s %s', + $this->name, + $this->unsigned ? 'UNSIGNED' : '', + $this->default !== null ? "DEFAULT {$this->default}" : '', + $this->nullable ? '' : 'NOT NULL', + ), + DEFAULT => sprintf( + '`%s` %s %s %s %s', + $this->name, + IntegerBytes::fromBytes($this->bytes)->toString(), + $this->unsigned ? 'UNSIGNED' : '', + $this->default !== null ? "DEFAULT {$this->default}" : '', + $this->nullable ? '' : 'NOT NULL', + ) + }; } } diff --git a/packages/database/tests/QueryStatements/CreateTableStatementTest.php b/packages/database/tests/QueryStatements/CreateTableStatementTest.php index 2d68cefe94..8893315d7d 100644 --- a/packages/database/tests/QueryStatements/CreateTableStatementTest.php +++ b/packages/database/tests/QueryStatements/CreateTableStatementTest.php @@ -18,6 +18,10 @@ */ final class CreateTableStatementTest extends TestCase { + public function test_integer_table_database_dialect(): void + { + + } #[DataProvider('provide_create_table_database_dialects')] public function test_create_a_table(DatabaseDialect $dialect, string $validSql): void { diff --git a/tests/Integration/Database/QueryStatements/CreateTableStatementTest.php b/tests/Integration/Database/QueryStatements/CreateTableStatementTest.php index cefccf14af..86863df1fb 100644 --- a/tests/Integration/Database/QueryStatements/CreateTableStatementTest.php +++ b/tests/Integration/Database/QueryStatements/CreateTableStatementTest.php @@ -287,6 +287,57 @@ public function test_object_method_produces_same_sql_as_json_and_dto(): void $this->assertSame($jsonStatement, $objectStatement); $this->assertSame($dtoStatement, $objectStatement); } + + public function test_integer_field_with_bytes_mysql(): void + { + $bigInteger = new CreateTableStatement('test-table') + ->integer('content', false, false, 6) + ->compile(dialect: DatabaseDialect::MYSQL); + $defaultInteger = new CreateTableStatement('test-table') + ->integer('content', false, false, 3) + ->compile(dialect: DatabaseDialect::MYSQL); + $smallInteger = new CreateTableStatement('test-table') + ->integer('content', false, false, 2) + ->compile(dialect: DatabaseDialect::MYSQL); + + $this->assertStringContainsString('BIGINT', $bigInteger); + $this->assertStringContainsString('INTEGER', $defaultInteger); + $this->assertStringContainsString('SMALL', $smallInteger); + } + + public function test_integer_field_with_bytes_postgresql(): void + { + $bigInteger = new CreateTableStatement('test-table') + ->integer('content', false, false, 6) + ->compile(dialect: DatabaseDialect::POSTGRESQL); + $defaultInteger = new CreateTableStatement('test-table') + ->integer('content', false, false, 3) + ->compile(dialect: DatabaseDialect::POSTGRESQL); + $smallInteger = new CreateTableStatement('test-table') + ->integer('content', false, false, 2) + ->compile(dialect: DatabaseDialect::POSTGRESQL); + + $this->assertStringContainsString('BIGINT', $bigInteger); + $this->assertStringContainsString('INTEGER', $defaultInteger); + $this->assertStringContainsString('SMALL', $smallInteger); + } + + public function test_integer_field_with_bytes_sqlite(): void + { + $bigInteger = new CreateTableStatement('test-table') + ->integer('content', false, false, 6) + ->compile(dialect: DatabaseDialect::SQLITE); + $defaultInteger = new CreateTableStatement('test-table') + ->integer('content', false, false, 3) + ->compile(dialect: DatabaseDialect::SQLITE); + $smallInteger = new CreateTableStatement('test-table') + ->integer('content', false, false, 2) + ->compile(dialect: DatabaseDialect::SQLITE); + + $this->assertStringContainsString('INTEGER', $bigInteger); + $this->assertStringContainsString('INTEGER', $defaultInteger); + $this->assertStringContainsString('INTEGER', $smallInteger); + } } enum CreateTableStatementTestEnumForCreateTable: string From d07202f490729d91b3a1b5e09682da414f635681 Mon Sep 17 00:00:00 2001 From: DevPandi Date: Mon, 16 Feb 2026 20:39:15 +0100 Subject: [PATCH 2/2] Use self for IntegerBytes --- .../database/src/QueryStatements/IntegerBytes.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/database/src/QueryStatements/IntegerBytes.php b/packages/database/src/QueryStatements/IntegerBytes.php index ab3e9f39d6..1ec8d80e21 100644 --- a/packages/database/src/QueryStatements/IntegerBytes.php +++ b/packages/database/src/QueryStatements/IntegerBytes.php @@ -13,18 +13,18 @@ enum IntegerBytes: int public static function fromBytes(int $bytes): self { return match (true) { - $bytes > self::DEFAULT->value => IntegerBytes::BIG, - $bytes > self::SMALL->value => IntegerBytes::DEFAULT, - DEFAULT => IntegerBytes::SMALL, + $bytes > self::DEFAULT->value => self::BIG, + $bytes > self::SMALL->value => self::DEFAULT, + DEFAULT => self::SMALL, }; } public function toString(): string { return match($this) { - IntegerBytes::SMALL => 'SMALLINT', - IntegerBytes::DEFAULT => 'INTEGER', - IntegerBytes::BIG => 'BIGINT', + self::SMALL => 'SMALLINT', + self::DEFAULT => 'INTEGER', + self::BIG => 'BIGINT', }; } }