Skip to content

Commit a4acaee

Browse files
vjikTigrov
andauthored
Add ENUM column (#1107)
Co-authored-by: Sergei Tigrov <[email protected]>
1 parent b78617d commit a4acaee

18 files changed

+287
-61
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
- Chg #1103: Remove `AbstractCommand::refreshTableSchema()` method (@vjik)
179179
- Chg #1106: Remove parameters from `PdoConnectionInterface::getActivePdo()` method (@vjik)
180180
- Bug #1109: Fix column definition parsing in cases with brackets and escaped quotes (@vjik)
181+
- New #1107: Add abstract enumeration column type (@vjik)
181182

182183
## 1.3.0 March 21, 2024
183184

src/Constant/ColumnType.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,8 @@ final class ColumnType
105105
* Define the abstract column type as `json`.
106106
*/
107107
public const JSON = 'json';
108+
/**
109+
* Define the abstract column type as `enum`.
110+
*/
111+
public const ENUM = 'enum';
108112
}

src/QueryBuilder/AbstractColumnDefinitionBuilder.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Yiisoft\Db\Constant\ReferentialAction;
99
use Yiisoft\Db\Schema\Column\CollatableColumnInterface;
1010
use Yiisoft\Db\Schema\Column\ColumnInterface;
11+
use Yiisoft\Db\Schema\Column\EnumColumn;
1112

1213
use function in_array;
1314
use function strtolower;
@@ -122,6 +123,25 @@ protected function buildCheck(ColumnInterface $column): string
122123
{
123124
$check = $column->getCheck();
124125

126+
if (empty($check)
127+
&& $column instanceof EnumColumn
128+
&& $column->getDbType() === null
129+
) {
130+
$name = $column->getName();
131+
if (!empty($name)) {
132+
$quoter = $this->queryBuilder->getQuoter();
133+
$quotedItems = implode(
134+
',',
135+
array_map(
136+
$quoter->quoteValue(...),
137+
$column->getValues(),
138+
),
139+
);
140+
$quotedName = $quoter->quoteColumnName($name);
141+
$check = "$quotedName IN ($quotedItems)";
142+
}
143+
}
144+
125145
return !empty($check) ? " CHECK ($check)" : '';
126146
}
127147

src/Schema/Column/AbstractColumn.php

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ abstract class AbstractColumn implements ColumnInterface
6161
* @param string|null $comment The column's comment.
6262
* @param bool $computed Whether the column is a computed column.
6363
* @param string|null $dbType The column's database type.
64-
* @param array|null $enumValues The list of possible values for an ENUM column.
6564
* @param string|null $extra Any extra information that needs to be appended to the column's definition.
6665
* @param bool $primaryKey Whether the column is a primary key.
6766
* @param string|null $name The column's name.
@@ -83,7 +82,6 @@ public function __construct(
8382
private ?string $comment = null,
8483
private bool $computed = false,
8584
private ?string $dbType = null,
86-
private ?array $enumValues = null,
8785
private ?string $extra = null,
8886
private bool $primaryKey = false,
8987
private ?string $name = null,
@@ -146,12 +144,6 @@ public function defaultValue(mixed $defaultValue): static
146144
return $this;
147145
}
148146

149-
public function enumValues(?array $enumValues): static
150-
{
151-
$this->enumValues = $enumValues;
152-
return $this;
153-
}
154-
155147
public function extra(?string $extra): static
156148
{
157149
$this->extra = $extra;
@@ -182,12 +174,6 @@ public function getDefaultValue(): mixed
182174
return $this->defaultValue ?? null;
183175
}
184176

185-
/** @psalm-mutation-free */
186-
public function getEnumValues(): ?array
187-
{
188-
return $this->enumValues;
189-
}
190-
191177
/** @psalm-mutation-free */
192178
public function getExtra(): ?string
193179
{

src/Schema/Column/AbstractColumnFactory.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ protected function getColumnClass(string $type, array $info = []): string
256256
ColumnType::ARRAY => ArrayColumn::class,
257257
ColumnType::STRUCTURED => StructuredColumn::class,
258258
ColumnType::JSON => JsonColumn::class,
259+
ColumnType::ENUM => EnumColumn::class,
259260
default => StringColumn::class,
260261
};
261262
}
@@ -277,6 +278,10 @@ protected function getType(string $dbType, array $info = []): string
277278
return ColumnType::ARRAY;
278279
}
279280

281+
if (isset($info['values'])) {
282+
return ColumnType::ENUM;
283+
}
284+
280285
return static::TYPE_MAP[$dbType] ?? ColumnType::STRING;
281286
}
282287

@@ -333,7 +338,8 @@ protected function isType(string $type): bool
333338
ColumnType::DATE,
334339
ColumnType::ARRAY,
335340
ColumnType::STRUCTURED,
336-
ColumnType::JSON => true,
341+
ColumnType::JSON,
342+
ColumnType::ENUM => true,
337343
default => isset($this->classMap[$type]),
338344
};
339345
}

src/Schema/Column/ColumnBuilder.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,4 +271,15 @@ public static function json(): ColumnInterface
271271
{
272272
return new JsonColumn(ColumnType::JSON);
273273
}
274+
275+
/**
276+
* Builds a column with the abstract type `enum`.
277+
*
278+
* @param string[]|null $values The list of possible values for the enum column.
279+
* @param string|null $dbType The database type of the column. When null, the column will use a CHECK constraint.
280+
*/
281+
public static function enum(?array $values = null, ?string $dbType = null): EnumColumn
282+
{
283+
return new EnumColumn(dbType: $dbType, values: $values);
284+
}
274285
}

src/Schema/Column/ColumnFactoryInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
* defaultValue?: mixed,
2626
* defaultValueRaw?: string|null,
2727
* dimension?: positive-int,
28-
* enumValues?: array|null,
2928
* extra?: string|null,
3029
* fromResult?: bool,
3130
* primaryKey?: bool,
@@ -39,6 +38,7 @@
3938
* type?: ColumnType::*,
4039
* unique?: bool,
4140
* unsigned?: bool,
41+
* values?: array|null,
4242
* }
4343
*/
4444
interface ColumnFactoryInterface

src/Schema/Column/ColumnInterface.php

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,6 @@ public function dbTypecast(mixed $value): mixed;
105105
*/
106106
public function defaultValue(mixed $defaultValue): static;
107107

108-
/**
109-
* The list of possible values for the `ENUM` column.
110-
*
111-
* ```php
112-
* $columns = [
113-
* 'status' => ColumnBuilder::string(16)->enumValues(['active', 'inactive']),
114-
* ];
115-
* ```
116-
*/
117-
public function enumValues(?array $enumValues): static;
118-
119108
/**
120109
* Extra SQL to append to the generated SQL for a column.
121110
*
@@ -166,14 +155,6 @@ public function getDbType(): ?string;
166155
*/
167156
public function getDefaultValue(): mixed;
168157

169-
/**
170-
* @return array|null The enum values of the column.
171-
*
172-
* @see enumValues()
173-
* @psalm-mutation-free
174-
*/
175-
public function getEnumValues(): ?array;
176-
177158
/**
178159
* @return string|null The extra SQL for the column.
179160
*

src/Schema/Column/EnumColumn.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\Db\Schema\Column;
6+
7+
use LogicException;
8+
use Yiisoft\Db\Constant\ColumnType;
9+
10+
final class EnumColumn extends StringColumn
11+
{
12+
protected const DEFAULT_TYPE = ColumnType::ENUM;
13+
14+
/**
15+
* @var string[]|null $values The list of possible values for an ENUM column.
16+
* @psalm-var non-empty-list<string>|null
17+
*/
18+
protected ?array $values = null;
19+
20+
/**
21+
* @param string[] $values The list of possible values for the `ENUM` column.
22+
* @psalm-param non-empty-list<string> $values
23+
*/
24+
public function values(array $values): static
25+
{
26+
$this->values = $values;
27+
return $this;
28+
}
29+
30+
/**
31+
* @return string[] The enum values of the column.
32+
* @psalm-return non-empty-list<string>
33+
*
34+
* @see values()
35+
*/
36+
public function getValues(): array
37+
{
38+
if ($this->values === null) {
39+
throw new LogicException('Enum values have not been set.');
40+
}
41+
return $this->values;
42+
}
43+
}

src/Syntax/ColumnDefinitionParser.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ class ColumnDefinitionParser
4444
* comment?: string,
4545
* defaultValueRaw?: string,
4646
* dimension?: positive-int,
47-
* enumValues?: list<string>,
4847
* extra?: string,
4948
* notNull?: bool,
5049
* scale?: int,
5150
* size?: int,
5251
* type: lowercase-string,
5352
* unique?: bool,
5453
* unsigned?: bool,
54+
* values?: list<string>,
5555
* }
5656
*/
5757
public function parse(string $definition): array
@@ -80,7 +80,7 @@ public function parse(string $definition): array
8080
}
8181

8282
/**
83-
* @psalm-return array{enumValues: list<string>}
83+
* @psalm-return array{values: list<string>}
8484
*/
8585
protected function enumInfo(string $values): array
8686
{
@@ -91,7 +91,7 @@ protected function enumInfo(string $values): array
9191
$matches[1],
9292
);
9393

94-
return ['enumValues' => $values];
94+
return ['values' => $values];
9595
}
9696

9797
/**

0 commit comments

Comments
 (0)