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 #374

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions src/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
*
* Provides a fluent interface, which means that the methods can be chained together to create a column schema with
* many properties in a single line of code.
*
* @psalm-suppress DeprecatedClass
*
* @deprecated Use {@see StringColumnSchema} or other column classes instead. Will be removed in 2.0.0.
*/
final class Column extends AbstractColumn
{
Expand Down
6 changes: 6 additions & 0 deletions src/Column/ColumnDefinitionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ public function build(ColumnSchemaInterface $column): string
. $this->buildExtra($column);
}

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

protected function buildType(ColumnSchemaInterface $column): string
{
if ($column instanceof \Yiisoft\Db\Schema\Column\ArrayColumnSchema) {
Expand Down
58 changes: 27 additions & 31 deletions src/DDLQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\QueryBuilder\AbstractDDLQueryBuilder;
use Yiisoft\Db\Schema\Builder\ColumnInterface;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;

use function array_diff;
use function array_unshift;
use function explode;
use function implode;
use function is_string;
use function preg_match;
use function preg_replace;
use function str_contains;
Expand All @@ -27,7 +28,7 @@ public function addDefaultValue(string $table, string $name, string $column, mix
throw new NotSupportedException(__METHOD__ . ' is not supported by PostgreSQL.');
}

public function alterColumn(string $table, string $column, ColumnInterface|string $type): string
public function alterColumn(string $table, string $column, ColumnInterface|ColumnSchemaInterface|string $type): string
{
$columnName = $this->quoter->quoteColumnName($column);
$tableName = $this->quoter->quoteTableName($table);
Expand All @@ -40,47 +41,42 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin
* @link https://github.com/yiisoft/yii2/issues/4492
* @link https://www.postgresql.org/docs/9.1/static/sql-altertable.html
*/
if (preg_match('/^(DROP|SET|RESET|USING)\s+/i', $type)) {
return "ALTER TABLE $tableName ALTER COLUMN $columnName $type";
if (is_string($type)) {
if (preg_match('/^(DROP|SET|RESET|USING)\s+/i', $type) === 1) {
return "ALTER TABLE $tableName ALTER COLUMN $columnName $type";
}

$type = $this->schema->getColumnFactory()->fromDefinition($type);
}

/** @psalm-suppress DeprecatedMethod */
$type = 'TYPE ' . $this->queryBuilder->getColumnType($type);
$multiAlterStatement = [];
$constraintPrefix = preg_replace('/[^a-z0-9_]/i', '', $table . '_' . $column);
$columnDefinitionBuilder = $this->queryBuilder->getColumnDefinitionBuilder();

if (preg_match('/\s+DEFAULT\s+(["\']?\w*["\']?)/i', $type, $matches)) {
$type = preg_replace('/\s+DEFAULT\s+(["\']?\w*["\']?)/i', '', $type);
$multiAlterStatement[] = "ALTER COLUMN $columnName SET DEFAULT $matches[1]";
}
$multiAlterStatement = ["ALTER COLUMN $columnName TYPE " . $columnDefinitionBuilder->buildAlter($type)];

$type = preg_replace('/\s+NOT\s+NULL/i', '', $type, -1, $count);
if ($type->hasDefaultValue()) {
$defaultValue = $type->dbTypecast($type->getDefaultValue());
$defaultValue = $this->queryBuilder->prepareValue($defaultValue);

if ($count > 0) {
$multiAlterStatement[] = "ALTER COLUMN $columnName SET NOT NULL";
} else {
/** remove extra null if any */
$type = preg_replace('/\s+NULL/i', '', $type, -1, $count);
if ($count > 0) {
$multiAlterStatement[] = "ALTER COLUMN $columnName DROP NOT NULL";
}
$multiAlterStatement[] = "ALTER COLUMN $columnName SET DEFAULT $defaultValue";
}

if (preg_match('/\s+CHECK\s+\((.+)\)/i', $type, $matches)) {
$type = preg_replace('/\s+CHECK\s+\((.+)\)/i', '', $type);
$multiAlterStatement[] = "ADD CONSTRAINT {$constraintPrefix}_check CHECK ($matches[1])";
}
match ($type->isNotNull()) {
true => $multiAlterStatement[] = "ALTER COLUMN $columnName SET NOT NULL",
false => $multiAlterStatement[] = "ALTER COLUMN $columnName DROP NOT NULL",
default => null,
};

$type = preg_replace('/\s+UNIQUE/i', '', $type, -1, $count);
$check = $type->getCheck();
if (!empty($check)) {
$constraintPrefix = preg_replace('/\W/', '', $table . '_' . $column);
$multiAlterStatement[] = "ADD CONSTRAINT {$constraintPrefix}_check CHECK ($check)";
}

if ($count > 0) {
if ($type->isUnique()) {
$multiAlterStatement[] = "ADD UNIQUE ($columnName)";
}

/** add what's left at the beginning */
array_unshift($multiAlterStatement, "ALTER COLUMN $columnName $type");

return 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $multiAlterStatement);
return "ALTER TABLE $tableName " . implode(', ', $multiAlterStatement);
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ final class Schema extends AbstractPdoSchema
/** @deprecated Use {@see ColumnBuilder} instead. Will be removed in 2.0. */
public function createColumn(string $type, array|int|string $length = null): ColumnInterface
{
/** @psalm-suppress DeprecatedClass */
return new Column($type, $length);
}

Expand Down
26 changes: 0 additions & 26 deletions tests/ColumnSchemaBuilderTest.php

This file was deleted.

28 changes: 0 additions & 28 deletions tests/Provider/ColumnSchemaBuilderProvider.php

This file was deleted.

31 changes: 31 additions & 0 deletions tests/Provider/QueryBuilderProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,37 @@ final class QueryBuilderProvider extends \Yiisoft\Db\Tests\Provider\QueryBuilder

protected static string $driverName = 'pgsql';

public static function alterColumn(): array
{
return [
['SET NOT null', 'ALTER TABLE "foo1" ALTER COLUMN "bar" SET NOT null'],
['drop default', 'ALTER TABLE "foo1" ALTER COLUMN "bar" drop default'],
['reset xyz', 'ALTER TABLE "foo1" ALTER COLUMN "bar" reset xyz'],
['string', 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255)'],
['varchar(255)', 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255)'],
['string NOT NULL', 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ALTER COLUMN "bar" SET NOT NULL'],
['string NULL', 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ALTER COLUMN "bar" DROP NOT NULL'],
['string DEFAULT NULL', 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ALTER COLUMN "bar" SET DEFAULT NULL'],
["string DEFAULT ''", 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ALTER COLUMN "bar" SET DEFAULT \'\''],
['timestamp(0) DEFAULT now()', 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE timestamp(0), ALTER COLUMN "bar" SET DEFAULT now()'],
['string CHECK (char_length(bar) > 5)', 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ADD CONSTRAINT foo1_bar_check CHECK (char_length(bar) > 5)'],
['string(30) UNIQUE', 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(30), ADD UNIQUE ("bar")'],
['varchar(255) USING bar::varchar', 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255) USING bar::varchar'],
['varchar(255) using cast("bar" as varchar)', 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255) using cast("bar" as varchar)'],
[ColumnBuilder::string(), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255)'],
[ColumnBuilder::string()->notNull(), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ALTER COLUMN "bar" SET NOT NULL'],
[ColumnBuilder::string()->null(), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ALTER COLUMN "bar" DROP NOT NULL'],
[ColumnBuilder::string()->defaultValue(null), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ALTER COLUMN "bar" SET DEFAULT NULL'],
[ColumnBuilder::string()->defaultValue(''), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ALTER COLUMN "bar" SET DEFAULT \'\''],
[ColumnBuilder::string()->null()->defaultValue('xxx'), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ALTER COLUMN "bar" SET DEFAULT \'xxx\', ALTER COLUMN "bar" DROP NOT NULL'],
[ColumnBuilder::timestamp()->defaultValue(new Expression('now()')), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE timestamp(0), ALTER COLUMN "bar" SET DEFAULT now()'],
[ColumnBuilder::string()->check('char_length(bar) > 5'), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255), ADD CONSTRAINT foo1_bar_check CHECK (char_length(bar) > 5)'],
[ColumnBuilder::string(30)->unique(), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(30), ADD UNIQUE ("bar")'],
[ColumnBuilder::string()->extra('USING bar::varchar'), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255) USING bar::varchar'],
[ColumnBuilder::string()->extra('using cast("bar" as varchar)'), 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255) using cast("bar" as varchar)'],
];
}

public static function buildCondition(): array
{
$buildCondition = parent::buildCondition();
Expand Down
Loading
Loading