Skip to content

Commit

Permalink
Realize ColumnBuilder (#878)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov authored Sep 16, 2024
1 parent e3e277d commit c765ca4
Show file tree
Hide file tree
Showing 21 changed files with 746 additions and 118 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
- Enh #864: 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)

## 1.3.0 March 21, 2024

Expand Down
2 changes: 1 addition & 1 deletion UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Each table column has its own class in the `Yiisoft\Db\Schema\Column` namespace
### New methods

- `QuoterInterface::getRawTableName()` - returns the raw table name without quotes;
- `SchemaInterface::getColumnFactory()` - returns the column factory.
- `ConnectionInterface::getColumnFactory()` - returns the column factory object for concrete DBMS.

### Remove methods

Expand Down
6 changes: 6 additions & 0 deletions src/Connection/ConnectionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Yiisoft\Db\Query\BatchQueryResultInterface;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
use Yiisoft\Db\Schema\Column\ColumnFactoryInterface;
use Yiisoft\Db\Schema\QuoterInterface;
use Yiisoft\Db\Schema\SchemaInterface;
use Yiisoft\Db\Schema\TableSchemaInterface;
Expand Down Expand Up @@ -85,6 +86,11 @@ public function createTransaction(): TransactionInterface;
*/
public function close(): void;

/**
* Returns the column factory for creating column instances.
*/
public function getColumnFactory(): ColumnFactoryInterface;

/**
* Returns the name of the DB driver for the current `dsn`.
*
Expand Down
6 changes: 6 additions & 0 deletions src/Debug/ConnectionInterfaceProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Yiisoft\Db\Query\BatchQueryResultInterface;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
use Yiisoft\Db\Schema\Column\ColumnFactoryInterface;
use Yiisoft\Db\Schema\QuoterInterface;
use Yiisoft\Db\Schema\SchemaInterface;
use Yiisoft\Db\Schema\TableSchemaInterface;
Expand Down Expand Up @@ -62,6 +63,11 @@ public function close(): void
$this->connection->close();
}

public function getColumnFactory(): ColumnFactoryInterface
{
return $this->connection->getColumnFactory();
}

public function getLastInsertID(string $sequenceName = null): string
{
return $this->connection->getLastInsertID($sequenceName);
Expand Down
128 changes: 94 additions & 34 deletions src/Schema/Column/AbstractColumnFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,8 @@
namespace Yiisoft\Db\Schema\Column;

use Yiisoft\Db\Constant\ColumnType;

use function explode;
use function preg_match;
use function str_ireplace;
use function stripos;
use function strlen;
use function strtolower;
use function substr;
use function trim;
use Yiisoft\Db\Constant\PseudoType;
use Yiisoft\Db\Syntax\ColumnDefinitionParser;

use const PHP_INT_SIZE;

Expand All @@ -38,6 +31,11 @@ abstract class AbstractColumnFactory implements ColumnFactoryInterface
*/
abstract protected function getType(string $dbType, array $info = []): string;

/**
* Checks if the column type is a database type.
*/
abstract protected function isDbType(string $dbType): bool;

public function fromDbType(string $dbType, array $info = []): ColumnSchemaInterface
{
$info['db_type'] = $dbType;
Expand All @@ -48,41 +46,45 @@ public function fromDbType(string $dbType, array $info = []): ColumnSchemaInterf

public function fromDefinition(string $definition, array $info = []): ColumnSchemaInterface
{
preg_match('/^(\w*)(?:\(([^)]+)\))?\s*/', $definition, $matches);
$definitionInfo = $this->columnDefinitionParser()->parse($definition);

$dbType = strtolower($matches[1]);
if (isset($info['extra'], $definitionInfo['extra'])) {
$info['extra'] = $definitionInfo['extra'] . ' ' . $info['extra'];
}

/** @var string $dbType */
$dbType = $definitionInfo['db_type'] ?? '';
unset($definitionInfo['db_type']);

if (isset($matches[2])) {
$values = explode(',', $matches[2]);
$info['size'] = (int) $values[0];
$info['precision'] = (int) $values[0];
$info += $definitionInfo;

if ($this->isDbType($dbType)) {
return $this->fromDbType($dbType, $info);
}

if (isset($values[1])) {
$info['scale'] = (int) $values[1];
}
if ($this->isType($dbType)) {
return $this->fromType($dbType, $info);
}

$extra = substr($definition, strlen($matches[0]));

if (!empty($extra)) {
if (stripos($extra, 'unsigned') !== false) {
$info['unsigned'] = true;
$extra = trim(str_ireplace('unsigned', '', $extra));
}

if (!empty($extra)) {
if (empty($info['extra'])) {
$info['extra'] = $extra;
} else {
/** @psalm-suppress MixedOperand */
$info['extra'] = $extra . ' ' . $info['extra'];
}
}
if ($this->isPseudoType($dbType)) {
return $this->fromPseudoType($dbType, $info);
}

return $this->fromDbType($dbType, $info);
}

public function fromPseudoType(string $pseudoType, array $info = []): ColumnSchemaInterface
{
return match ($pseudoType) {
PseudoType::PK => ColumnBuilder::primaryKey()->load($info),
PseudoType::UPK => ColumnBuilder::primaryKey()->unsigned()->load($info),
PseudoType::BIGPK => ColumnBuilder::bigPrimaryKey()->load($info),
PseudoType::UBIGPK => ColumnBuilder::bigPrimaryKey()->unsigned()->load($info),
PseudoType::UUID_PK => ColumnBuilder::uuidPrimaryKey()->load($info),
PseudoType::UUID_PK_SEQ => ColumnBuilder::uuidPrimaryKey(true)->load($info),
};
}

public function fromType(string $type, array $info = []): ColumnSchemaInterface
{
$column = match ($type) {
Expand All @@ -106,4 +108,62 @@ public function fromType(string $type, array $info = []): ColumnSchemaInterface

return $column->load($info);
}

/**
* Returns the column definition parser.
*/
protected function columnDefinitionParser(): ColumnDefinitionParser
{
return new ColumnDefinitionParser();
}

/**
* Checks if the column type is a pseudo-type.
*
* @psalm-assert-if-true PseudoType::* $pseudoType
*/
protected function isPseudoType(string $pseudoType): bool
{
return match ($pseudoType) {
PseudoType::PK,
PseudoType::UPK,
PseudoType::BIGPK,
PseudoType::UBIGPK,
PseudoType::UUID_PK,
PseudoType::UUID_PK_SEQ => true,
default => false,
};
}

/**
* Checks if the column type is an abstract type.
*
* @psalm-assert-if-true ColumnType::* $type
*/
protected function isType(string $type): bool
{
return match ($type) {
ColumnType::BOOLEAN,
ColumnType::BIT,
ColumnType::TINYINT,
ColumnType::SMALLINT,
ColumnType::INTEGER,
ColumnType::BIGINT,
ColumnType::FLOAT,
ColumnType::DOUBLE,
ColumnType::DECIMAL,
ColumnType::MONEY,
ColumnType::CHAR,
ColumnType::STRING,
ColumnType::TEXT,
ColumnType::BINARY,
ColumnType::UUID,
ColumnType::DATETIME,
ColumnType::TIMESTAMP,
ColumnType::DATE,
ColumnType::TIME,
ColumnType::JSON => true,
default => false,
};
}
}
Loading

0 comments on commit c765ca4

Please sign in to comment.