diff --git a/packages/database/src/QueryStatements/IntegerStatement.php b/packages/database/src/QueryStatements/IntegerStatement.php index 9a274ee29..867500f0e 100644 --- a/packages/database/src/QueryStatements/IntegerStatement.php +++ b/packages/database/src/QueryStatements/IntegerStatement.php @@ -29,14 +29,29 @@ 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, + $this->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(), + $this->type(), $this->unsigned ? 'UNSIGNED' : '', $this->default !== null ? "DEFAULT {$this->default}" : '', $this->nullable ? '' : 'NOT NULL', ), }; } + + private function type(): string + { + return is_int($this->size) + ? DatabaseIntegerSize::fromBytes($this->size)->toString() + : $this->size->toString(); + } } diff --git a/packages/database/tests/QueryStatements/CreateTableStatementTest.php b/packages/database/tests/QueryStatements/CreateTableStatementTest.php index b6322454a..d184bed1f 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] + public function postgres_is_not_told_about_a_keyword_it_does_not_have(): void + { + $statement = new IntegerStatement('votes', unsigned: true)->compile(DatabaseDialect::POSTGRESQL); + + $this->assertStringNotContainsString('UNSIGNED', $statement); + $this->assertStringContainsString('INTEGER', $statement); + } + + #[Test] + public function mysql_keeps_its_unsigned_range(): void + { + // MySQL supports `UNSIGNED`; dropping it globally would silently halve the requested range. + $this->assertStringContainsString( + 'UNSIGNED', + new IntegerStatement('votes', unsigned: true)->compile(DatabaseDialect::MYSQL), + ); + + $this->assertStringNotContainsString( + 'UNSIGNED', + new IntegerStatement('votes')->compile(DatabaseDialect::MYSQL), + ); + } + + #[Test] + public function the_size_chooses_the_type(): void + { + foreach ([DatabaseDialect::MYSQL, DatabaseDialect::POSTGRESQL] as $dialect) { + $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), + ); + } + } +}