From 4450dab3bc00b82362897f55b3be4adee0b447b4 Mon Sep 17 00:00:00 2001 From: DevPandi Date: Mon, 16 Feb 2026 20:37:27 +0100 Subject: [PATCH 1/5] 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 ab3bba8d7..4ecdc6c94 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 000000000..ab3e9f39d --- /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 793ac4899..fcbc90e13 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 2d68cefe9..8893315d7 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 cefccf14a..86863df1f 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/5] 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 ab3e9f39d..1ec8d80e2 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', }; } } From 96760290c6f2c4b25ae5a8a6c9d0fb9097eb1119 Mon Sep 17 00:00:00 2001 From: DevPandi Date: Wed, 18 Feb 2026 18:32:49 +0100 Subject: [PATCH 3/5] Remove unused test. --- .../tests/QueryStatements/CreateTableStatementTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/database/tests/QueryStatements/CreateTableStatementTest.php b/packages/database/tests/QueryStatements/CreateTableStatementTest.php index 8893315d7..2d68cefe9 100644 --- a/packages/database/tests/QueryStatements/CreateTableStatementTest.php +++ b/packages/database/tests/QueryStatements/CreateTableStatementTest.php @@ -18,10 +18,6 @@ */ 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 { From 6fa720a960f4beca309c700ef7a5637395eac3f4 Mon Sep 17 00:00:00 2001 From: DevPandi Date: Mon, 9 Mar 2026 11:25:20 +0100 Subject: [PATCH 4/5] Rename IntegerBytes to DatabaseIntegerSize, Add union type. --- .../database/src/QueryStatements/CreateTableStatement.php | 4 ++-- .../{IntegerBytes.php => DatabaseIntegerSize.php} | 2 +- packages/database/src/QueryStatements/IntegerStatement.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename packages/database/src/QueryStatements/{IntegerBytes.php => DatabaseIntegerSize.php} (95%) diff --git a/packages/database/src/QueryStatements/CreateTableStatement.php b/packages/database/src/QueryStatements/CreateTableStatement.php index 4ecdc6c94..57207c2f6 100644 --- a/packages/database/src/QueryStatements/CreateTableStatement.php +++ b/packages/database/src/QueryStatements/CreateTableStatement.php @@ -199,13 +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 $bytes = 4, ?int $default = null): self + public function integer(string $name, bool $unsigned = false, bool $nullable = false, int|DatabaseIntegerSize $size = DatabaseIntegerSize::DEFAULT, ?int $default = null): self { $this->statements[] = new IntegerStatement( name: $name, unsigned: $unsigned, nullable: $nullable, - bytes: $bytes, + size: $size, default: $default, ); diff --git a/packages/database/src/QueryStatements/IntegerBytes.php b/packages/database/src/QueryStatements/DatabaseIntegerSize.php similarity index 95% rename from packages/database/src/QueryStatements/IntegerBytes.php rename to packages/database/src/QueryStatements/DatabaseIntegerSize.php index 1ec8d80e2..477aa883e 100644 --- a/packages/database/src/QueryStatements/IntegerBytes.php +++ b/packages/database/src/QueryStatements/DatabaseIntegerSize.php @@ -4,7 +4,7 @@ namespace Tempest\Database\QueryStatements; -enum IntegerBytes: int +enum DatabaseIntegerSize: int { case SMALL = 2; case DEFAULT = 4; diff --git a/packages/database/src/QueryStatements/IntegerStatement.php b/packages/database/src/QueryStatements/IntegerStatement.php index fcbc90e13..5011024bd 100644 --- a/packages/database/src/QueryStatements/IntegerStatement.php +++ b/packages/database/src/QueryStatements/IntegerStatement.php @@ -13,7 +13,7 @@ public function __construct( private string $name, private bool $unsigned = false, private bool $nullable = false, - private int $bytes = 4, + private int|DatabaseIntegerSize $size = DatabaseIntegerSize::DEFAULT, private ?int $default = null, ) {} @@ -30,7 +30,7 @@ public function compile(DatabaseDialect $dialect): string DEFAULT => sprintf( '`%s` %s %s %s %s', $this->name, - IntegerBytes::fromBytes($this->bytes)->toString(), + DatabaseIntegerSize::fromBytes($this->size)->toString(), $this->unsigned ? 'UNSIGNED' : '', $this->default !== null ? "DEFAULT {$this->default}" : '', $this->nullable ? '' : 'NOT NULL', From 37b8549e4962ddd86c8e268e99a2c6b975a06098 Mon Sep 17 00:00:00 2001 From: brendt Date: Tue, 10 Mar 2026 08:23:40 +0100 Subject: [PATCH 5/5] QA --- .../database/src/QueryStatements/DatabaseIntegerSize.php | 4 ++-- packages/database/src/QueryStatements/IntegerStatement.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/database/src/QueryStatements/DatabaseIntegerSize.php b/packages/database/src/QueryStatements/DatabaseIntegerSize.php index 477aa883e..4f55be72b 100644 --- a/packages/database/src/QueryStatements/DatabaseIntegerSize.php +++ b/packages/database/src/QueryStatements/DatabaseIntegerSize.php @@ -15,13 +15,13 @@ public static function fromBytes(int $bytes): self return match (true) { $bytes > self::DEFAULT->value => self::BIG, $bytes > self::SMALL->value => self::DEFAULT, - DEFAULT => self::SMALL, + default => self::SMALL, }; } public function toString(): string { - return match($this) { + return match ($this) { self::SMALL => 'SMALLINT', self::DEFAULT => 'INTEGER', self::BIG => 'BIGINT', diff --git a/packages/database/src/QueryStatements/IntegerStatement.php b/packages/database/src/QueryStatements/IntegerStatement.php index 5011024bd..17943e609 100644 --- a/packages/database/src/QueryStatements/IntegerStatement.php +++ b/packages/database/src/QueryStatements/IntegerStatement.php @@ -19,7 +19,7 @@ public function __construct( public function compile(DatabaseDialect $dialect): string { - return match($dialect) { + return match ($dialect) { DatabaseDialect::SQLITE => sprintf( '`%s` INTEGER %s %s %s', $this->name, @@ -27,14 +27,14 @@ public function compile(DatabaseDialect $dialect): string $this->default !== null ? "DEFAULT {$this->default}" : '', $this->nullable ? '' : 'NOT NULL', ), - DEFAULT => sprintf( + default => sprintf( '`%s` %s %s %s %s', $this->name, DatabaseIntegerSize::fromBytes($this->size)->toString(), $this->unsigned ? 'UNSIGNED' : '', $this->default !== null ? "DEFAULT {$this->default}" : '', $this->nullable ? '' : 'NOT NULL', - ) + ), }; } }