diff --git a/packages/database/src/QueryStatements/IntegerStatement.php b/packages/database/src/QueryStatements/IntegerStatement.php index 9a274ee290..6358b058bd 100644 --- a/packages/database/src/QueryStatements/IntegerStatement.php +++ b/packages/database/src/QueryStatements/IntegerStatement.php @@ -21,6 +21,10 @@ public function compile(DatabaseDialect $dialect): string { $name = $dialect->quoteIdentifier($this->name); + $type = is_int($this->size) + ? DatabaseIntegerSize::fromBytes($this->size)->toString() + : $this->size->toString(); + return match ($dialect) { DatabaseDialect::SQLITE => sprintf( '%s INTEGER %s %s %s', @@ -29,10 +33,18 @@ public function compile(DatabaseDialect $dialect): string $this->default !== null ? "DEFAULT {$this->default}" : '', $this->nullable ? '' : 'NOT NULL', ), - default => sprintf( + // Postgres has no unsigned integer type, so omit the keyword there. + DatabaseDialect::POSTGRESQL => sprintf( + '%s %s %s %s', + $name, + $type, + $this->default !== null ? "DEFAULT {$this->default}" : '', + $this->nullable ? '' : 'NOT NULL', + ), + DatabaseDialect::MYSQL => sprintf( '%s %s %s %s %s', $name, - is_int($this->size) ? DatabaseIntegerSize::fromBytes($this->size)->toString() : $this->size->toString(), + $type, $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 b6322454a6..d184bed1f7 100644 --- a/packages/database/tests/QueryStatements/CreateTableStatementTest.php +++ b/packages/database/tests/QueryStatements/CreateTableStatementTest.php @@ -113,7 +113,7 @@ public static function provide_fk_create_table_database_drivers(): Generator <<primary() + ->integer('small', unsigned: true, size: DatabaseIntegerSize::SMALL) + ->integer('regular', unsigned: true) + ->integer('big', unsigned: true, size: DatabaseIntegerSize::BIG) + ->integer('nullable_with_default', unsigned: true, nullable: true, default: 1); + } + }; + + $this->database->migrate(CreateMigrationsTable::class, $migration); + + $this->expectNotToPerformAssertions(); + } + + #[Test] + #[TestWith([DatabaseDialect::MYSQL, true])] + #[TestWith([DatabaseDialect::SQLITE, true])] + #[TestWith([DatabaseDialect::POSTGRESQL, false])] + public function unsigned_is_only_emitted_on_dialects_that_have_it(DatabaseDialect $dialect, bool $expected): void + { + $statement = new IntegerStatement('votes', unsigned: true)->compile($dialect); + + if ($expected) { + $this->assertStringContainsString('UNSIGNED', $statement); + } else { + $this->assertStringNotContainsString('UNSIGNED', $statement); + } + } + + #[Test] + #[TestWith([DatabaseDialect::MYSQL])] + #[TestWith([DatabaseDialect::POSTGRESQL])] + public function the_size_chooses_the_type(DatabaseDialect $dialect): void + { + $this->assertStringContainsString( + 'SMALLINT', + new IntegerStatement('n', size: DatabaseIntegerSize::SMALL)->compile($dialect), + ); + + $this->assertStringContainsString( + 'BIGINT', + new IntegerStatement('n', size: DatabaseIntegerSize::BIG)->compile($dialect), + ); + + // A byte count is rounded up to the size that can hold it. + $this->assertStringContainsString( + 'BIGINT', + new IntegerStatement('n', size: 8)->compile($dialect), + ); + } +}