Skip to content

Commit

Permalink
feat(database): improved database indexing (#851)
Browse files Browse the repository at this point in the history
  • Loading branch information
brendt authored Dec 13, 2024
1 parent 6f457af commit 82f1808
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 61 deletions.
49 changes: 32 additions & 17 deletions src/Tempest/Database/src/QueryStatements/AlterTableStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
use Tempest\Database\Builder\TableName;
use Tempest\Database\DatabaseDialect;
use Tempest\Database\QueryStatement;
use Tempest\Support\StringHelper;
use function Tempest\Support\arr;
use function Tempest\Support\str;

final class AlterTableStatement implements QueryStatement
{
public function __construct(
private readonly string $tableName,
private array $statements = [],
) {
}
private array $createIndexStatements = [],
) {}

/** @param class-string<\Tempest\Database\DatabaseModel> $modelClass */
public static function forModel(string $modelClass): self
Expand Down Expand Up @@ -57,16 +60,22 @@ public function constraint(string $constraintName, ?QueryStatement $statement =
return $this;
}

public function unique(string $columnName): self
public function unique(string ...$columns): self
{
$this->statements[] = new UniqueStatement($columnName);
$this->createIndexStatements[] = new UniqueStatement(
tableName: $this->tableName,
columns: $columns,
);

return $this;
}

public function index(string $indexName): self
public function index(string ...$columns): self
{
$this->statements[] = new IndexStatement($indexName);
$this->createIndexStatements[] = new IndexStatement(
tableName: $this->tableName,
columns: $columns,
);

return $this;
}
Expand All @@ -80,20 +89,26 @@ public function drop(QueryStatement $statement): self

public function compile(DatabaseDialect $dialect): string
{
$compiled = sprintf(
$alterTable = sprintf(
'ALTER TABLE %s %s;',
new TableName($this->tableName),
implode(
' ',
array_filter(
array_map(
static fn (QueryStatement $statement) => $statement->compile($dialect),
$this->statements,
),
),
),
arr($this->statements)
->map(fn (QueryStatement $queryStatement) => str($queryStatement->compile($dialect))->trim()->replace(' ', ' '))
->filter(fn (StringHelper $line) => $line->isNotEmpty())
->implode(', ' . PHP_EOL . ' ')
->wrap(before: PHP_EOL . ' ', after: PHP_EOL)
->toString(),
);

return str_replace(' ', ' ', $compiled);
if ($this->createIndexStatements !== []) {
$createIndices = PHP_EOL . arr($this->createIndexStatements)
->map(fn (QueryStatement $queryStatement) => str($queryStatement->compile($dialect))->trim()->replace(' ', ' '))
->implode(';' . PHP_EOL)
->append(';');
} else {
$createIndices = '';
}

return $alterTable . $createIndices;
}
}
88 changes: 64 additions & 24 deletions src/Tempest/Database/src/QueryStatements/CreateTableStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
use Tempest\Database\Builder\TableName;
use Tempest\Database\DatabaseDialect;
use Tempest\Database\QueryStatement;
use Tempest\Support\StringHelper;
use function Tempest\Support\arr;
use function Tempest\Support\str;

final class CreateTableStatement implements QueryStatement
{
public function __construct(
private readonly string $tableName,
private array $statements = [],
) {
}
private array $indexStatements = [],
) {}

/** @param class-string<\Tempest\Database\DatabaseModel> $modelClass */
public static function forModel(string $modelClass): self
Expand All @@ -35,7 +38,8 @@ public function belongsTo(
OnDelete $onDelete = OnDelete::RESTRICT,
OnUpdate $onUpdate = OnUpdate::NO_ACTION,
bool $nullable = false,
): self {
): self
{
[$localTable, $localKey] = explode('.', $local);

$this->integer($localKey, nullable: $nullable);
Expand All @@ -54,7 +58,8 @@ public function text(
string $name,
bool $nullable = false,
?string $default = null,
): self {
): self
{
$this->statements[] = new TextStatement(
name: $name,
nullable: $nullable,
Expand All @@ -69,7 +74,8 @@ public function varchar(
int $length = 255,
bool $nullable = false,
?string $default = null,
): self {
): self
{
$this->statements[] = new VarcharStatement(
name: $name,
size: $length,
Expand All @@ -84,7 +90,8 @@ public function char(
string $name,
bool $nullable = false,
?string $default = null,
): self {
): self
{
$this->statements[] = new CharStatement(
name: $name,
nullable: $nullable,
Expand All @@ -99,7 +106,8 @@ public function integer(
bool $unsigned = false,
bool $nullable = false,
?int $default = null,
): self {
): self
{
$this->statements[] = new IntegerStatement(
name: $name,
unsigned: $unsigned,
Expand All @@ -114,7 +122,8 @@ public function float(
string $name,
bool $nullable = false,
?float $default = null,
): self {
): self
{
$this->statements[] = new FloatStatement(
name: $name,
nullable: $nullable,
Expand All @@ -128,7 +137,8 @@ public function datetime(
string $name,
bool $nullable = false,
?string $default = null,
): self {
): self
{
$this->statements[] = new DatetimeStatement(
name: $name,
nullable: $nullable,
Expand All @@ -142,7 +152,8 @@ public function date(
string $name,
bool $nullable = false,
?string $default = null,
): self {
): self
{
$this->statements[] = new DateStatement(
name: $name,
nullable: $nullable,
Expand All @@ -156,7 +167,8 @@ public function boolean(
string $name,
bool $nullable = false,
?bool $default = null,
): self {
): self
{
$this->statements[] = new BooleanStatement(
name: $name,
nullable: $nullable,
Expand All @@ -170,7 +182,8 @@ public function json(
string $name,
bool $nullable = false,
?string $default = null,
): self {
): self
{
$this->statements[] = new JsonStatement(
name: $name,
nullable: $nullable,
Expand All @@ -185,7 +198,8 @@ public function set(
array $values,
bool $nullable = false,
?string $default = null,
): self {
): self
{
$this->statements[] = new SetStatement(
name: $name,
values: $values,
Expand All @@ -196,22 +210,48 @@ public function set(
return $this;
}

public function unique(string ...$columns): self
{
$this->indexStatements[] = new UniqueStatement(
tableName: $this->tableName,
columns: $columns,
);

return $this;
}

public function index(string ...$columns): self
{
$this->indexStatements[] = new IndexStatement(
tableName: $this->tableName,
columns: $columns,
);

return $this;
}

public function compile(DatabaseDialect $dialect): string
{
$compiled = sprintf(
$createTable = sprintf(
'CREATE TABLE %s (%s);',
new TableName($this->tableName),
implode(
', ',
array_filter(
array_map(
fn (QueryStatement $queryStatement) => $queryStatement->compile($dialect),
$this->statements,
),
),
),
arr($this->statements)
->map(fn (QueryStatement $queryStatement) => str($queryStatement->compile($dialect))->trim()->replace(' ', ' '))
->filter(fn (StringHelper $line) => $line->isNotEmpty())
->implode(', ' . PHP_EOL . ' ')
->wrap(before: PHP_EOL . ' ', after: PHP_EOL)
->toString(),
);

return str_replace(' ', ' ', $compiled);
if ($this->indexStatements !== []) {
$createIndices = PHP_EOL . arr($this->indexStatements)
->map(fn (QueryStatement $queryStatement) => str($queryStatement->compile($dialect))->trim()->replace(' ', ' '))
->implode(';' . PHP_EOL)
->append(';');
} else {
$createIndices = '';
}

return $createTable . $createIndices;
}
}
13 changes: 11 additions & 2 deletions src/Tempest/Database/src/QueryStatements/IndexStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,25 @@

use Tempest\Database\DatabaseDialect;
use Tempest\Database\QueryStatement;
use function Tempest\Support\arr;
use function Tempest\Support\str;

final readonly class IndexStatement implements QueryStatement
{
public function __construct(
private string $indexName,
private string $tableName,
private array $columns,
) {
}

public function compile(DatabaseDialect $dialect): string
{
return sprintf('INDEX %s', $this->indexName);
$columns = arr($this->columns)->implode('`, `')->wrap('`', '`');

$indexName = str($this->tableName . ' ' . $columns->replace(',', '')->snake())->snake()->toString();

$on = sprintf('`%s` (%s)', $this->tableName, $columns);

return sprintf('CREATE INDEX `%s` ON %s', $indexName, $on);
}
}
13 changes: 11 additions & 2 deletions src/Tempest/Database/src/QueryStatements/UniqueStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,25 @@

use Tempest\Database\DatabaseDialect;
use Tempest\Database\QueryStatement;
use function Tempest\Support\arr;
use function Tempest\Support\str;

final readonly class UniqueStatement implements QueryStatement
{
public function __construct(
private string $columnName,
private string $tableName,
private array $columns,
) {
}

public function compile(DatabaseDialect $dialect): string
{
return sprintf('UNIQUE (%s)', $this->columnName);
$columns = arr($this->columns)->implode('`, `')->wrap('`', '`');

$indexName = str($this->tableName . ' ' . $columns->replace(',', '')->snake())->snake()->toString();

$on = sprintf('`%s` (%s)', $this->tableName, $columns);

return sprintf('CREATE UNIQUE INDEX `%s` ON %s', $indexName, $on);
}
}
Loading

0 comments on commit 82f1808

Please sign in to comment.