Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -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|DatabaseIntegerSize $size = DatabaseIntegerSize::DEFAULT, ?int $default = null): self
{
$this->statements[] = new IntegerStatement(
name: $name,
unsigned: $unsigned,
nullable: $nullable,
size: $size,
default: $default,
);

Expand Down
30 changes: 30 additions & 0 deletions packages/database/src/QueryStatements/DatabaseIntegerSize.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Tempest\Database\QueryStatements;

enum DatabaseIntegerSize: int
{
case SMALL = 2;
case DEFAULT = 4;
case BIG = 8;

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,
};
}

public function toString(): string
{
return match ($this) {
self::SMALL => 'SMALLINT',
self::DEFAULT => 'INTEGER',
self::BIG => 'BIGINT',
};
}
}
25 changes: 18 additions & 7 deletions packages/database/src/QueryStatements/IntegerStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,28 @@ public function __construct(
private string $name,
private bool $unsigned = false,
private bool $nullable = false,
private int|DatabaseIntegerSize $size = DatabaseIntegerSize::DEFAULT,
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,
DatabaseIntegerSize::fromBytes($this->size)->toString(),
$this->unsigned ? 'UNSIGNED' : '',
$this->default !== null ? "DEFAULT {$this->default}" : '',
$this->nullable ? '' : 'NOT NULL',
),
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading