Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new column definition builder #905

Merged
merged 10 commits into from
Dec 23, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
- New #902: Add `QueryBuilderInterface::prepareParam()` and `QueryBuilderInterface::prepareValue()` methods (@Tigrov)
- Enh #902: Refactor `Quoter::quoteValue()` method (@Tigrov)
- New #906: Add `ServerInfoInterface` and its implementation (@Tigrov)
- Enh #905: Use `AbstractColumnDefinitionBuilder` to generate table column SQL representation (@Tigrov)

## 1.3.0 March 21, 2024

Expand Down
5 changes: 3 additions & 2 deletions src/Command/AbstractCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Yiisoft\Db\QueryBuilder\DMLQueryBuilderInterface;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
use Yiisoft\Db\Schema\Builder\ColumnInterface;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;

use function explode;
use function get_resource_type;
Expand Down Expand Up @@ -131,7 +132,7 @@ public function addCheck(string $table, string $name, string $expression): stati
return $this->setSql($sql)->requireTableSchemaRefresh($table);
}

public function addColumn(string $table, string $column, ColumnInterface|string $type): static
public function addColumn(string $table, string $column, ColumnInterface|ColumnSchemaInterface|string $type): static
{
$sql = $this->getQueryBuilder()->addColumn($table, $column, $type);
return $this->setSql($sql)->requireTableSchemaRefresh($table);
Expand Down Expand Up @@ -188,7 +189,7 @@ public function addUnique(string $table, string $name, array|string $columns): s
return $this->setSql($sql)->requireTableSchemaRefresh($table);
}

public function alterColumn(string $table, string $column, ColumnInterface|string $type): static
public function alterColumn(string $table, string $column, ColumnInterface|ColumnSchemaInterface|string $type): static
{
$sql = $this->getQueryBuilder()->alterColumn($table, $column, $type);
return $this->setSql($sql)->requireTableSchemaRefresh($table);
Expand Down
60 changes: 41 additions & 19 deletions src/Command/CommandInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use JsonException;
use Throwable;
use Yiisoft\Db\Connection\ConnectionInterface;
use Yiisoft\Db\Constant\ColumnType;
use Yiisoft\Db\Constant\PseudoType;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidArgumentException;
use Yiisoft\Db\Exception\InvalidCallException;
Expand All @@ -17,6 +19,7 @@
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\QueryBuilder\DMLQueryBuilderInterface;
use Yiisoft\Db\Schema\Builder\ColumnInterface;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;

/**
* This interface represents a database command, such as a `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statement.
Expand Down Expand Up @@ -44,13 +47,13 @@ public function addCheck(string $table, string $name, string $expression): stati
*
* @param string $table The name of the table to add new column to.
* @param string $column The name of the new column.
* @param ColumnInterface|string $type The column type. {@see QueryBuilder::getColumnType()} will be called
* to convert the given column type to the database one.
* @param ColumnInterface|ColumnSchemaInterface|string $type The column type.
* {@see QueryBuilder::buildColumnDefinition()} will be called to convert the given column type to the database one.
* For example, `string` will be converted to `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
*
* Note: The method will quote the `table` and `column` parameters before using them in the generated SQL.
*/
public function addColumn(string $table, string $column, ColumnInterface|string $type): static;
public function addColumn(string $table, string $column, ColumnInterface|ColumnSchemaInterface|string $type): static;

/**
* Builds an SQL command for adding a comment to a column.
Expand Down Expand Up @@ -144,13 +147,13 @@ public function addPrimaryKey(string $table, string $name, array|string $columns
*
* @param string $table The table whose column is to change.
* @param string $column The name of the column to change.
* @param ColumnInterface|string $type The column type. {@see QueryBuilder::getColumnType()} will be called to
* convert the give column type to the physical one. For example, `string` will be converted as `varchar(255)`, and
* `string not null` becomes `varchar(255) not null`.
* @param ColumnInterface|ColumnSchemaInterface|string $type The column type.
* {@see QueryBuilder::buildColumnDefinition()} will be called to convert the give column type to the physical one.
* For example, `string` will be converted as `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
*
* Note: The method will quote the `table` and `column` parameters before using them in the generated SQL.
*/
public function alterColumn(string $table, string $column, ColumnInterface|string $type): static;
public function alterColumn(string $table, string $column, ColumnInterface|ColumnSchemaInterface|string $type): static;

/**
* Creates a batch INSERT command.
Expand Down Expand Up @@ -314,21 +317,40 @@ public function createIndex(
/**
* Creates an SQL command for creating a new DB table.
*
* Specify the columns in the new table as name-definition pairs ('name' => 'string'), where name
* stands for a column name which will be quoted by the method, and definition stands for the column type
* which can contain an abstract DB type.
* The columns in the new table should be specified as name-definition pairs (e.g. 'name' => 'string'), where name
* is the name of the column which will be properly quoted by the method, and definition is the type of the column
* which can contain a native database column type, {@see ColumnType abstract} or {@see PseudoType pseudo} type,
* or can be represented as instance of {@see ColumnSchemaInterface}.
*
* The method {@see QueryBuilder::getColumnType()} will be called to convert the abstract column types to physical
* ones.
* For example, it will convert `string` to `varchar(255)`, and `string not null` to
* `varchar(255) not null`.
* The {@see QueryBuilderInterface::buildColumnDefinition()} method will be invoked to convert column definitions
* into SQL representation. For example, it will convert `string not null` to `varchar(255) not null`
* and `pk` to `int PRIMARY KEY AUTO_INCREMENT` (for MySQL).
*
* If you specify a column with definition only (`PRIMARY KEY (name, type)`), it will be directly inserted
* into the generated SQL.
* The preferred method is to use {@see ColumnBuilder} to generate column definitions as instances of
* {@see ColumnSchemaInterface}.
*
* ```php
* $this->createTable(
* 'example_table',
* [
* 'id' => ColumnBuilder::primaryKey(),
* 'name' => ColumnBuilder::string(64)->notNull(),
* 'type' => ColumnBuilder::integer()->notNull()->defaultValue(10),
* 'description' => ColumnBuilder::text(),
* 'rule_name' => ColumnBuilder::string(64),
* 'data' => ColumnBuilder::text(),
* 'created_at' => ColumnBuilder::datetime()->notNull(),
* 'updated_at' => ColumnBuilder::datetime(),
* ],
* );
* ```
*
* If a column is specified with definition only (e.g. 'PRIMARY KEY (name, type)'), it will be directly put into the
* generated SQL.
*
* @param string $table The name of the table to create.
* @param array $columns The columns (name => definition) in the new table.
* The definition can be `string` or {@see ColumnInterface} instance.
* @param (ColumnSchemaInterface|string)[] $columns The columns (name => definition) in the new table.
* The definition can be `string` or {@see ColumnSchemaInterface} instance.
* @param string|null $options More SQL fragments to append to the generated SQL.
*
* @throws Exception
Expand All @@ -337,7 +359,7 @@ public function createIndex(
*
* Note: The method will quote the `table` and `columns` parameter before using it in the generated SQL.
*
* @psalm-param array<string, ColumnInterface>|string[] $columns
* @psalm-param array<string, ColumnSchemaInterface>|string[] $columns
*/
public function createTable(string $table, array $columns, string $options = null): static;

Expand Down
5 changes: 3 additions & 2 deletions src/Debug/CommandInterfaceProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Yiisoft\Db\Query\Data\DataReaderInterface;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\Schema\Builder\ColumnInterface;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;

final class CommandInterfaceProxy implements CommandInterface
{
Expand All @@ -30,7 +31,7 @@ public function addCheck(string $table, string $name, string $expression): stati
/**
* @psalm-suppress MixedArgument
*/
public function addColumn(string $table, string $column, ColumnInterface|string $type): static
public function addColumn(string $table, string $column, ColumnInterface|ColumnSchemaInterface|string $type): static
{
return new self($this->decorated->{__FUNCTION__}(...func_get_args()), $this->collector);
}
Expand Down Expand Up @@ -93,7 +94,7 @@ public function addUnique(string $table, string $name, array|string $columns): s
/**
* @psalm-suppress MixedArgument
*/
public function alterColumn(string $table, string $column, ColumnInterface|string $type): static
public function alterColumn(string $table, string $column, ColumnInterface|ColumnSchemaInterface|string $type): static
{
return new self($this->decorated->{__FUNCTION__}(...func_get_args()), $this->collector);
}
Expand Down
24 changes: 17 additions & 7 deletions src/QueryBuilder/AbstractColumnDefinitionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ abstract class AbstractColumnDefinitionBuilder implements ColumnDefinitionBuilde
*/
protected const AUTO_INCREMENT_KEYWORD = '';

/**
* @var string The expression used to generate a UUID value.
*/
protected const GENERATE_UUID_EXPRESSION = '';

/**
* @var string[] The list of database column types (in lower case) that allow size specification.
*/
Expand Down Expand Up @@ -65,6 +60,11 @@ public function build(ColumnSchemaInterface $column): string
. $this->buildExtra($column);
}

public function buildAlter(ColumnSchemaInterface $column): string
{
return $this->build($column);
}

/**
* Builds the auto increment clause for the column.
*
Expand Down Expand Up @@ -114,12 +114,14 @@ protected function buildComment(ColumnSchemaInterface $column): string
*/
protected function buildDefault(ColumnSchemaInterface $column): string
{
if (!empty(static::GENERATE_UUID_EXPRESSION)
$uuidExpression = $this->getDefaultUuidExpression();

if (!empty($uuidExpression)
&& $column->getType() === ColumnType::UUID
&& $column->isAutoIncrement()
&& $column->getDefaultValue() === null
) {
return ' DEFAULT ' . static::GENERATE_UUID_EXPRESSION;
return " DEFAULT $uuidExpression";
}

if ($column->isAutoIncrement() && $column->getType() !== ColumnType::UUID
Expand Down Expand Up @@ -298,4 +300,12 @@ protected function buildUnsigned(ColumnSchemaInterface $column): string
{
return $column->isUnsigned() ? ' UNSIGNED' : '';
}

/**
* Get the expression used to generate a UUID as a default value.
*/
protected function getDefaultUuidExpression(): string
{
return '';
}
}
14 changes: 6 additions & 8 deletions src/QueryBuilder/AbstractDDLQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\Schema\Builder\ColumnInterface;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
use Yiisoft\Db\Schema\QuoterInterface;
use Yiisoft\Db\Schema\SchemaInterface;

Expand Down Expand Up @@ -39,15 +40,14 @@ public function addCheck(string $table, string $name, string $expression): strin
. ' CHECK (' . $this->quoter->quoteSql($expression) . ')';
}

public function addColumn(string $table, string $column, ColumnInterface|string $type): string
public function addColumn(string $table, string $column, ColumnInterface|ColumnSchemaInterface|string $type): string
{
/** @psalm-suppress DeprecatedMethod */
return 'ALTER TABLE '
. $this->quoter->quoteTableName($table)
. ' ADD '
. $this->quoter->quoteColumnName($column)
. ' '
. $this->queryBuilder->getColumnType($type);
. $this->queryBuilder->buildColumnDefinition($type);
}

public function addCommentOnColumn(string $table, string $column, string $comment): string
Expand Down Expand Up @@ -137,16 +137,15 @@ public function addUnique(string $table, string $name, array|string $columns): s
public function alterColumn(
string $table,
string $column,
ColumnInterface|string $type
ColumnInterface|ColumnSchemaInterface|string $type
): string {
/** @psalm-suppress DeprecatedMethod */
return 'ALTER TABLE '
. $this->quoter->quoteTableName($table)
. ' CHANGE '
. $this->quoter->quoteColumnName($column)
. ' '
. $this->quoter->quoteColumnName($column) . ' '
. $this->queryBuilder->getColumnType($type);
. $this->queryBuilder->buildColumnDefinition($type);
}

public function checkIntegrity(string $schema = '', string $table = '', bool $check = true): string
Expand All @@ -173,11 +172,10 @@ public function createTable(string $table, array $columns, string $options = nul

foreach ($columns as $name => $type) {
if (is_string($name)) {
/** @psalm-suppress DeprecatedMethod */
$cols[] = "\t"
. $this->quoter->quoteColumnName($name)
. ' '
. $this->queryBuilder->getColumnType($type);
. $this->queryBuilder->buildColumnDefinition($type);
} else {
/** @psalm-var string $type */
$cols[] = "\t" . $type;
Expand Down
15 changes: 12 additions & 3 deletions src/QueryBuilder/AbstractQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public function addCheck(string $table, string $name, string $expression): strin
return $this->ddlBuilder->addCheck($table, $name, $expression);
}

public function addColumn(string $table, string $column, ColumnInterface|string $type): string
public function addColumn(string $table, string $column, ColumnInterface|ColumnSchemaInterface|string $type): string
{
return $this->ddlBuilder->addColumn($table, $column, $type);
}
Expand Down Expand Up @@ -131,7 +131,7 @@ public function addUnique(string $table, string $name, array|string $columns): s
return $this->ddlBuilder->addUnique($table, $name, $columns);
}

public function alterColumn(string $table, string $column, ColumnInterface|string $type): string
public function alterColumn(string $table, string $column, ColumnInterface|ColumnSchemaInterface|string $type): string
{
return $this->ddlBuilder->alterColumn($table, $column, $type);
}
Expand Down Expand Up @@ -175,8 +175,12 @@ public function build(QueryInterface $query, array $params = []): array
return $this->dqlBuilder->build($query, $params);
}

public function buildColumnDefinition(ColumnSchemaInterface|string $column): string
public function buildColumnDefinition(ColumnInterface|ColumnSchemaInterface|string $column): string
{
if ($column instanceof ColumnInterface) {
$column = $column->asString();
}

if (is_string($column)) {
$column = $this->schema->getColumnFactory()->fromDefinition($column);
}
Expand Down Expand Up @@ -355,6 +359,11 @@ public function dropView(string $viewName): string
return $this->ddlBuilder->dropView($viewName);
}

public function getColumnDefinitionBuilder(): ColumnDefinitionBuilderInterface
{
return $this->columnDefinitionBuilder;
}

/** @deprecated Use {@see buildColumnDefinition()}. Will be removed in version 2.0. */
public function getColumnType(ColumnInterface|string $type): string
{
Expand Down
5 changes: 5 additions & 0 deletions src/QueryBuilder/ColumnDefinitionBuilderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ interface ColumnDefinitionBuilderInterface
* @return string the column SQL definition.
*/
public function build(ColumnSchemaInterface $column): string;

/**
* Builds column definition for `ALTER` operation based on given column instance.
*/
public function buildAlter(ColumnSchemaInterface $column): string;
}
Loading
Loading