Skip to content

Commit 82f1808

Browse files
authored
feat(database): improved database indexing (#851)
1 parent 6f457af commit 82f1808

File tree

9 files changed

+184
-61
lines changed

9 files changed

+184
-61
lines changed

src/Tempest/Database/src/QueryStatements/AlterTableStatement.php

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@
77
use Tempest\Database\Builder\TableName;
88
use Tempest\Database\DatabaseDialect;
99
use Tempest\Database\QueryStatement;
10+
use Tempest\Support\StringHelper;
11+
use function Tempest\Support\arr;
12+
use function Tempest\Support\str;
1013

1114
final class AlterTableStatement implements QueryStatement
1215
{
1316
public function __construct(
1417
private readonly string $tableName,
1518
private array $statements = [],
16-
) {
17-
}
19+
private array $createIndexStatements = [],
20+
) {}
1821

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

60-
public function unique(string $columnName): self
63+
public function unique(string ...$columns): self
6164
{
62-
$this->statements[] = new UniqueStatement($columnName);
65+
$this->createIndexStatements[] = new UniqueStatement(
66+
tableName: $this->tableName,
67+
columns: $columns,
68+
);
6369

6470
return $this;
6571
}
6672

67-
public function index(string $indexName): self
73+
public function index(string ...$columns): self
6874
{
69-
$this->statements[] = new IndexStatement($indexName);
75+
$this->createIndexStatements[] = new IndexStatement(
76+
tableName: $this->tableName,
77+
columns: $columns,
78+
);
7079

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

8190
public function compile(DatabaseDialect $dialect): string
8291
{
83-
$compiled = sprintf(
92+
$alterTable = sprintf(
8493
'ALTER TABLE %s %s;',
8594
new TableName($this->tableName),
86-
implode(
87-
' ',
88-
array_filter(
89-
array_map(
90-
static fn (QueryStatement $statement) => $statement->compile($dialect),
91-
$this->statements,
92-
),
93-
),
94-
),
95+
arr($this->statements)
96+
->map(fn (QueryStatement $queryStatement) => str($queryStatement->compile($dialect))->trim()->replace(' ', ' '))
97+
->filter(fn (StringHelper $line) => $line->isNotEmpty())
98+
->implode(', ' . PHP_EOL . ' ')
99+
->wrap(before: PHP_EOL . ' ', after: PHP_EOL)
100+
->toString(),
95101
);
96102

97-
return str_replace(' ', ' ', $compiled);
103+
if ($this->createIndexStatements !== []) {
104+
$createIndices = PHP_EOL . arr($this->createIndexStatements)
105+
->map(fn (QueryStatement $queryStatement) => str($queryStatement->compile($dialect))->trim()->replace(' ', ' '))
106+
->implode(';' . PHP_EOL)
107+
->append(';');
108+
} else {
109+
$createIndices = '';
110+
}
111+
112+
return $alterTable . $createIndices;
98113
}
99114
}

src/Tempest/Database/src/QueryStatements/CreateTableStatement.php

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@
77
use Tempest\Database\Builder\TableName;
88
use Tempest\Database\DatabaseDialect;
99
use Tempest\Database\QueryStatement;
10+
use Tempest\Support\StringHelper;
11+
use function Tempest\Support\arr;
12+
use function Tempest\Support\str;
1013

1114
final class CreateTableStatement implements QueryStatement
1215
{
1316
public function __construct(
1417
private readonly string $tableName,
1518
private array $statements = [],
16-
) {
17-
}
19+
private array $indexStatements = [],
20+
) {}
1821

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

4145
$this->integer($localKey, nullable: $nullable);
@@ -54,7 +58,8 @@ public function text(
5458
string $name,
5559
bool $nullable = false,
5660
?string $default = null,
57-
): self {
61+
): self
62+
{
5863
$this->statements[] = new TextStatement(
5964
name: $name,
6065
nullable: $nullable,
@@ -69,7 +74,8 @@ public function varchar(
6974
int $length = 255,
7075
bool $nullable = false,
7176
?string $default = null,
72-
): self {
77+
): self
78+
{
7379
$this->statements[] = new VarcharStatement(
7480
name: $name,
7581
size: $length,
@@ -84,7 +90,8 @@ public function char(
8490
string $name,
8591
bool $nullable = false,
8692
?string $default = null,
87-
): self {
93+
): self
94+
{
8895
$this->statements[] = new CharStatement(
8996
name: $name,
9097
nullable: $nullable,
@@ -99,7 +106,8 @@ public function integer(
99106
bool $unsigned = false,
100107
bool $nullable = false,
101108
?int $default = null,
102-
): self {
109+
): self
110+
{
103111
$this->statements[] = new IntegerStatement(
104112
name: $name,
105113
unsigned: $unsigned,
@@ -114,7 +122,8 @@ public function float(
114122
string $name,
115123
bool $nullable = false,
116124
?float $default = null,
117-
): self {
125+
): self
126+
{
118127
$this->statements[] = new FloatStatement(
119128
name: $name,
120129
nullable: $nullable,
@@ -128,7 +137,8 @@ public function datetime(
128137
string $name,
129138
bool $nullable = false,
130139
?string $default = null,
131-
): self {
140+
): self
141+
{
132142
$this->statements[] = new DatetimeStatement(
133143
name: $name,
134144
nullable: $nullable,
@@ -142,7 +152,8 @@ public function date(
142152
string $name,
143153
bool $nullable = false,
144154
?string $default = null,
145-
): self {
155+
): self
156+
{
146157
$this->statements[] = new DateStatement(
147158
name: $name,
148159
nullable: $nullable,
@@ -156,7 +167,8 @@ public function boolean(
156167
string $name,
157168
bool $nullable = false,
158169
?bool $default = null,
159-
): self {
170+
): self
171+
{
160172
$this->statements[] = new BooleanStatement(
161173
name: $name,
162174
nullable: $nullable,
@@ -170,7 +182,8 @@ public function json(
170182
string $name,
171183
bool $nullable = false,
172184
?string $default = null,
173-
): self {
185+
): self
186+
{
174187
$this->statements[] = new JsonStatement(
175188
name: $name,
176189
nullable: $nullable,
@@ -185,7 +198,8 @@ public function set(
185198
array $values,
186199
bool $nullable = false,
187200
?string $default = null,
188-
): self {
201+
): self
202+
{
189203
$this->statements[] = new SetStatement(
190204
name: $name,
191205
values: $values,
@@ -196,22 +210,48 @@ public function set(
196210
return $this;
197211
}
198212

213+
public function unique(string ...$columns): self
214+
{
215+
$this->indexStatements[] = new UniqueStatement(
216+
tableName: $this->tableName,
217+
columns: $columns,
218+
);
219+
220+
return $this;
221+
}
222+
223+
public function index(string ...$columns): self
224+
{
225+
$this->indexStatements[] = new IndexStatement(
226+
tableName: $this->tableName,
227+
columns: $columns,
228+
);
229+
230+
return $this;
231+
}
232+
199233
public function compile(DatabaseDialect $dialect): string
200234
{
201-
$compiled = sprintf(
235+
$createTable = sprintf(
202236
'CREATE TABLE %s (%s);',
203237
new TableName($this->tableName),
204-
implode(
205-
', ',
206-
array_filter(
207-
array_map(
208-
fn (QueryStatement $queryStatement) => $queryStatement->compile($dialect),
209-
$this->statements,
210-
),
211-
),
212-
),
238+
arr($this->statements)
239+
->map(fn (QueryStatement $queryStatement) => str($queryStatement->compile($dialect))->trim()->replace(' ', ' '))
240+
->filter(fn (StringHelper $line) => $line->isNotEmpty())
241+
->implode(', ' . PHP_EOL . ' ')
242+
->wrap(before: PHP_EOL . ' ', after: PHP_EOL)
243+
->toString(),
213244
);
214245

215-
return str_replace(' ', ' ', $compiled);
246+
if ($this->indexStatements !== []) {
247+
$createIndices = PHP_EOL . arr($this->indexStatements)
248+
->map(fn (QueryStatement $queryStatement) => str($queryStatement->compile($dialect))->trim()->replace(' ', ' '))
249+
->implode(';' . PHP_EOL)
250+
->append(';');
251+
} else {
252+
$createIndices = '';
253+
}
254+
255+
return $createTable . $createIndices;
216256
}
217257
}

src/Tempest/Database/src/QueryStatements/IndexStatement.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,25 @@
66

77
use Tempest\Database\DatabaseDialect;
88
use Tempest\Database\QueryStatement;
9+
use function Tempest\Support\arr;
10+
use function Tempest\Support\str;
911

1012
final readonly class IndexStatement implements QueryStatement
1113
{
1214
public function __construct(
13-
private string $indexName,
15+
private string $tableName,
16+
private array $columns,
1417
) {
1518
}
1619

1720
public function compile(DatabaseDialect $dialect): string
1821
{
19-
return sprintf('INDEX %s', $this->indexName);
22+
$columns = arr($this->columns)->implode('`, `')->wrap('`', '`');
23+
24+
$indexName = str($this->tableName . ' ' . $columns->replace(',', '')->snake())->snake()->toString();
25+
26+
$on = sprintf('`%s` (%s)', $this->tableName, $columns);
27+
28+
return sprintf('CREATE INDEX `%s` ON %s', $indexName, $on);
2029
}
2130
}

src/Tempest/Database/src/QueryStatements/UniqueStatement.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,25 @@
66

77
use Tempest\Database\DatabaseDialect;
88
use Tempest\Database\QueryStatement;
9+
use function Tempest\Support\arr;
10+
use function Tempest\Support\str;
911

1012
final readonly class UniqueStatement implements QueryStatement
1113
{
1214
public function __construct(
13-
private string $columnName,
15+
private string $tableName,
16+
private array $columns,
1417
) {
1518
}
1619

1720
public function compile(DatabaseDialect $dialect): string
1821
{
19-
return sprintf('UNIQUE (%s)', $this->columnName);
22+
$columns = arr($this->columns)->implode('`, `')->wrap('`', '`');
23+
24+
$indexName = str($this->tableName . ' ' . $columns->replace(',', '')->snake())->snake()->toString();
25+
26+
$on = sprintf('`%s` (%s)', $this->tableName, $columns);
27+
28+
return sprintf('CREATE UNIQUE INDEX `%s` ON %s', $indexName, $on);
2029
}
2130
}

0 commit comments

Comments
 (0)