diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f26ed1c3..a43be0222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - Enh #378: Improve loading schemas of views (@Tigrov) - Enh #379: Remove `ColumnInterface` (@Tigrov) - Enh #380: Rename `ColumnSchemaInterface` to `ColumnInterface` (@Tigrov) +- Enh #381: Add `ColumnDefinitionParser` class (@Tigrov) ## 1.3.0 March 21, 2024 diff --git a/src/Column/ColumnDefinitionBuilder.php b/src/Column/ColumnDefinitionBuilder.php index 8f4da9348..450d0a557 100644 --- a/src/Column/ColumnDefinitionBuilder.php +++ b/src/Column/ColumnDefinitionBuilder.php @@ -64,30 +64,39 @@ protected function buildType(ColumnInterface $column): string protected function getDbType(ColumnInterface $column): string { + $dbType = $column->getDbType(); + /** @psalm-suppress DocblockTypeContradiction */ - return $column->getDbType() ?? match ($column->getType()) { - ColumnType::BOOLEAN => 'boolean', - ColumnType::BIT => 'varbit', - ColumnType::TINYINT => $column->isAutoIncrement() ? 'smallserial' : 'smallint', - ColumnType::SMALLINT => $column->isAutoIncrement() ? 'smallserial' : 'smallint', - ColumnType::INTEGER => $column->isAutoIncrement() ? 'serial' : 'integer', - ColumnType::BIGINT => $column->isAutoIncrement() ? 'bigserial' : 'bigint', - ColumnType::FLOAT => 'real', - ColumnType::DOUBLE => 'double precision', - ColumnType::DECIMAL => 'numeric', - ColumnType::MONEY => 'money', - ColumnType::CHAR => 'char', - ColumnType::STRING => 'varchar(' . ($column->getSize() ?? 255) . ')', - ColumnType::TEXT => 'text', - ColumnType::BINARY => 'bytea', - ColumnType::UUID => 'uuid', - ColumnType::DATETIME => 'timestamp', - ColumnType::TIMESTAMP => 'timestamp', - ColumnType::DATE => 'date', - ColumnType::TIME => 'time', - ColumnType::STRUCTURED => 'jsonb', - ColumnType::JSON => 'jsonb', - default => 'varchar', + return match ($dbType) { + default => $dbType, + null => match ($column->getType()) { + ColumnType::BOOLEAN => 'boolean', + ColumnType::BIT => 'varbit', + ColumnType::TINYINT => $column->isAutoIncrement() ? 'smallserial' : 'smallint', + ColumnType::SMALLINT => $column->isAutoIncrement() ? 'smallserial' : 'smallint', + ColumnType::INTEGER => $column->isAutoIncrement() ? 'serial' : 'integer', + ColumnType::BIGINT => $column->isAutoIncrement() ? 'bigserial' : 'bigint', + ColumnType::FLOAT => 'real', + ColumnType::DOUBLE => 'double precision', + ColumnType::DECIMAL => 'numeric', + ColumnType::MONEY => 'money', + ColumnType::CHAR => 'char', + ColumnType::STRING => 'varchar(' . ($column->getSize() ?? 255) . ')', + ColumnType::TEXT => 'text', + ColumnType::BINARY => 'bytea', + ColumnType::UUID => 'uuid', + ColumnType::DATETIME => 'timestamp', + ColumnType::TIMESTAMP => 'timestamp', + ColumnType::DATE => 'date', + ColumnType::TIME => 'time', + ColumnType::STRUCTURED => 'jsonb', + ColumnType::JSON => 'jsonb', + default => 'varchar', + }, + 'timestamp without time zone' => 'timestamp', + 'timestamp with time zone' => 'timestamptz', + 'time without time zone' => 'time', + 'time with time zone' => 'timetz', }; } diff --git a/src/Column/ColumnDefinitionParser.php b/src/Column/ColumnDefinitionParser.php new file mode 100644 index 000000000..f55e65d08 --- /dev/null +++ b/src/Column/ColumnDefinitionParser.php @@ -0,0 +1,47 @@ + $type]; + + $typeDetails = $matches[4] ?? $matches[2] ?? ''; + + if ($typeDetails !== '') { + if ($type === 'enum') { + $info += $this->enumInfo($typeDetails); + } else { + $info += $this->sizeInfo($typeDetails); + } + } + + $extra = substr($definition, strlen($matches[0])); + + return $info + $this->extraInfo($extra); + } +} diff --git a/src/Column/ColumnFactory.php b/src/Column/ColumnFactory.php index d79b960c3..b2641c60c 100644 --- a/src/Column/ColumnFactory.php +++ b/src/Column/ColumnFactory.php @@ -139,6 +139,11 @@ public function fromType(string $type, array $info = []): ColumnInterface return $column; } + protected function columnDefinitionParser(): ColumnDefinitionParser + { + return new ColumnDefinitionParser(); + } + protected function getColumnClass(string $type, array $info = []): string { return match ($type) { diff --git a/tests/ColumnDefinitionParserTest.php b/tests/ColumnDefinitionParserTest.php new file mode 100644 index 000000000..976c476fb --- /dev/null +++ b/tests/ColumnDefinitionParserTest.php @@ -0,0 +1,27 @@ + 'double precision']], + ['character varying(126)', ['type' => 'character varying', 'size' => 126]], + ['bit varying(8)', ['type' => 'bit varying', 'size' => 8]], + ['timestamp without time zone', ['type' => 'timestamp without time zone']], + ['timestamp(3) with time zone', ['type' => 'timestamp with time zone', 'size' => 3]], + ['time without time zone', ['type' => 'time without time zone']], + ['time (3) with time zone', ['type' => 'time with time zone', 'size' => 3]], + ]; + } +} diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index f0dc4d1fc..f8117eb21 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -636,7 +636,14 @@ public static function buildColumnDefinition(): array $values['uuidPrimaryKey()'][0] = "uuid PRIMARY KEY DEFAULT $uuidExpression"; } - return $values; + return [ + ...$values, + ['character varying(255)', 'character varying(255)'], + ['timestamp(5)', 'timestamp (5) without time zone'], + ['timestamptz', 'timestamp with time zone'], + ['time(3)', 'time(3) without time zone'], + ['timetz(0)', 'time(0) with time zone'], + ]; } public static function prepareParam(): array