Skip to content

Commit

Permalink
Improve ColumnDefinitionParser::extraInfo() method (#900)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov authored Nov 17, 2024
1 parent 3167625 commit ba043b6
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 13 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
- New #864, #897, #898: Realize column factory (@Tigrov)
- Enh #875: Ignore "Packets out of order..." warnings in `AbstractPdoCommand::internalExecute()` method (@Tigrov)
- Enh #877: Separate column type constants (@Tigrov)
- Enh #878: Realize `ColumnBuilder` class (@Tigrov)
- New #878: Realize `ColumnBuilder` class (@Tigrov)
- New #878, #900: Realize `ColumnDefinitionParser` class (@Tigrov)
- Enh #881: Refactor `ColumnSchemaInterface` and `AbstractColumnSchema` (@Tigrov)
- New #882: Move `ArrayColumnSchema` and `StructuredColumnSchema` classes from `db-pgsql` package (@Tigrov)
- New #883, #901: Add `ColumnDefinitionBuilder` class and `QueryBuilderInterface::buildColumnDefinition()` method (@Tigrov)
Expand Down
49 changes: 44 additions & 5 deletions src/Syntax/ColumnDefinitionParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
use function explode;
use function preg_match;
use function preg_match_all;
use function str_ireplace;
use function stripos;
use function str_replace;
use function strlen;
use function strtolower;
use function substr;
Expand All @@ -27,11 +26,15 @@ final class ColumnDefinitionParser
* @return array The column information.
*
* @psalm-return array{
* check?: string,
* defaultValueRaw?: string,
* enumValues?: list<string>,
* extra?: string,
* notNull?: bool,
* scale?: int,
* size?: int,
* type: lowercase-string,
* unique?: bool,
* unsigned?: bool,
* }
*/
Expand Down Expand Up @@ -66,7 +69,14 @@ private function enumInfo(string $values): array
}

/**
* @psalm-return array{unsigned?: bool, extra?: string}
* @psalm-return array{
* check?: string,
* defaultValueRaw?: string,
* extra?: string,
* notNull?: bool,
* unique?: bool,
* unsigned?: bool
* }
*/
private function extraInfo(string $extra): array
{
Expand All @@ -75,12 +85,41 @@ private function extraInfo(string $extra): array
}

$info = [];
$bracketsPattern = '(\(((?>[^()]+)|(?-2))*\))';
$defaultPattern = "/\\s*\\bDEFAULT\\s+('(?:[^']|'')*'|\"(?:[^\"]|\"\")*\"|[^(\\s]*$bracketsPattern?\\S*)/i";

if (preg_match($defaultPattern, $extra, $matches) === 1) {
$info['defaultValueRaw'] = $matches[1];
$extra = str_replace($matches[0], '', $extra);
}

if (preg_match("/\\s*\\bCHECK\\s+$bracketsPattern/i", $extra, $matches) === 1) {
$info['check'] = substr($matches[1], 1, -1);
$extra = str_replace($matches[0], '', $extra);
}

if (stripos($extra, 'unsigned') !== false) {
$extra = preg_replace('/\s*\bUNSIGNED\b/i', '', $extra, 1, $count);
if ($count > 0) {
$info['unsigned'] = true;
$extra = trim(str_ireplace('unsigned', '', $extra));
}

$extra = preg_replace('/\s*\bUNIQUE\b/i', '', $extra, 1, $count);
if ($count > 0) {
$info['unique'] = true;
}

$extra = preg_replace('/\s*\bNOT\s+NULL\b/i', '', $extra, 1, $count);
if ($count > 0) {
$info['notNull'] = true;
} else {
$extra = preg_replace('/\s*\bNULL\b/i', '', $extra, 1, $count);
if ($count > 0) {
$info['notNull'] = false;
}
}

$extra = trim($extra);

if (!empty($extra)) {
$info['extra'] = $extra;
}
Expand Down
4 changes: 2 additions & 2 deletions tests/AbstractColumnFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,12 @@ public function testFromDefinitionWithExtra(): void
$db = $this->getConnection();
$columnFactory = $db->getSchema()->getColumnFactory();

$column = $columnFactory->fromDefinition('char(1) NOT NULL', ['extra' => 'UNIQUE']);
$column = $columnFactory->fromDefinition('char(1) INVISIBLE', ['extra' => 'COLLATE utf8mb4']);

$this->assertInstanceOf(StringColumnSchema::class, $column);
$this->assertSame('char', $column->getType());
$this->assertSame(1, $column->getSize());
$this->assertSame('NOT NULL UNIQUE', $column->getExtra());
$this->assertSame('INVISIBLE COLLATE utf8mb4', $column->getExtra());

$db->close();
}
Expand Down
17 changes: 13 additions & 4 deletions tests/Provider/ColumnDefinitionParserProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,21 @@ public static function parse(): array
['int', ['type' => 'int']],
['int(10)', ['type' => 'int', 'size' => 10]],
['int UNSIGNED', ['type' => 'int', 'unsigned' => true]],
['int UNIQUE', ['type' => 'int', 'unique' => true]],
['int(10) UNSIGNED', ['type' => 'int', 'size' => 10, 'unsigned' => true]],
['int(10) UNSIGNED NOT NULL', ['type' => 'int', 'size' => 10, 'unsigned' => true, 'extra' => 'NOT NULL']],
['int(10) NOT NULL', ['type' => 'int', 'size' => 10, 'extra' => 'NOT NULL']],
['text NOT NULL', ['type' => 'text', 'extra' => 'NOT NULL']],
['int(10) UNSIGNED NOT NULL', ['type' => 'int', 'size' => 10, 'unsigned' => true, 'notNull' => true]],
['int(10) NOT NULL', ['type' => 'int', 'size' => 10, 'notNull' => true]],
['text NOT NULL', ['type' => 'text', 'notNull' => true]],
['text NULL', ['type' => 'text', 'notNull' => false]],
['text COLLATE utf8mb4', ['type' => 'text', 'extra' => 'COLLATE utf8mb4']],
['text DEFAULT NULL', ['type' => 'text', 'defaultValueRaw' => 'NULL']],
["text DEFAULT 'value'", ['type' => 'text', 'defaultValueRaw' => "'value'"]],
['varchar(36) DEFAULT uuid()', ['type' => 'varchar', 'size' => 36, 'defaultValueRaw' => 'uuid()']],
['varchar(36) DEFAULT uuid()::varchar(36)', ['type' => 'varchar', 'size' => 36, 'defaultValueRaw' => 'uuid()::varchar(36)']],
['int DEFAULT (1 + 2)', ['type' => 'int', 'defaultValueRaw' => '(1 + 2)']],
['int CHECK (value > (1 + 5))', ['type' => 'int', 'check' => 'value > (1 + 5)']],
["enum('a','b','c')", ['type' => 'enum', 'enumValues' => ['a', 'b', 'c']]],
["enum('a','b','c') NOT NULL", ['type' => 'enum', 'enumValues' => ['a', 'b', 'c'], 'extra' => 'NOT NULL']],
["enum('a','b','c') NOT NULL", ['type' => 'enum', 'enumValues' => ['a', 'b', 'c'], 'notNull' => true]],
];
}
}
2 changes: 1 addition & 1 deletion tests/Provider/ColumnFactoryProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static function definitions(): array
// definition, expected type, expected instance of, expected column method results
'' => ['', ColumnType::STRING, StringColumnSchema::class, ['getDbType' => '']],
'text' => ['text', ColumnType::TEXT, StringColumnSchema::class, ['getDbType' => 'text']],
'text NOT NULL' => ['text NOT NULL', ColumnType::TEXT, StringColumnSchema::class, ['getDbType' => 'text', 'getExtra' => 'NOT NULL']],
'text NOT NULL' => ['text NOT NULL', ColumnType::TEXT, StringColumnSchema::class, ['getDbType' => 'text', 'isNotNull' => true]],
'char(1)' => ['char(1)', ColumnType::CHAR, StringColumnSchema::class, ['getDbType' => 'char', 'getSize' => 1]],
'decimal(10,2)' => ['decimal(10,2)', ColumnType::DECIMAL, DoubleColumnSchema::class, ['getDbType' => 'decimal', 'getSize' => 10, 'getScale' => 2]],
'bigint UNSIGNED' => ['bigint UNSIGNED', ColumnType::BIGINT, BigIntColumnSchema::class, ['getDbType' => 'bigint', 'isUnsigned' => true]],
Expand Down

0 comments on commit ba043b6

Please sign in to comment.