Passed
Pull Request — master (#229)
by Def
15:58 queued 12:13
created

DDLQueryBuilder   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Test Coverage

Coverage 98.61%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 66
c 2
b 0
f 0
dl 0
loc 159
ccs 71
cts 72
cp 0.9861
rs 10
wmc 27

9 Methods

Rating   Name   Duplication   Size   Complexity  
A addDefaultValue() 0 3 1
A __construct() 0 6 1
A dropDefaultValue() 0 3 1
A createIndex() 0 7 3
A truncateTable() 0 3 1
A renameTable() 0 6 1
A checkIntegrity() 0 28 6
A dropIndex() 0 18 5
B alterColumn() 0 53 8
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Pgsql;
6
7
use Throwable;
8
use Yiisoft\Db\Exception\Exception;
9
use Yiisoft\Db\Exception\InvalidArgumentException;
10
use Yiisoft\Db\Exception\NotSupportedException;
11
use Yiisoft\Db\QueryBuilder\AbstractDDLQueryBuilder;
12
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
13
use Yiisoft\Db\Schema\ColumnSchemaBuilderInterface;
14
use Yiisoft\Db\Schema\QuoterInterface;
15
use Yiisoft\Db\Schema\SchemaInterface;
16
17
use function array_diff;
18
use function array_unshift;
19
use function explode;
20
use function implode;
21
use function preg_match;
22
use function preg_replace;
23
use function str_contains;
24
25
final class DDLQueryBuilder extends AbstractDDLQueryBuilder
26
{
27 561
    public function __construct(
28
        private QueryBuilderInterface $queryBuilder,
29
        private QuoterInterface $quoter,
30
        private SchemaInterface $schema
31
    ) {
32 561
        parent::__construct($queryBuilder, $quoter, $schema);
33
    }
34
35
    /**
36
     * @throws NotSupportedException
37
     */
38 3
    public function addDefaultValue(string $name, string $table, string $column, mixed $value): string
39
    {
40 3
        throw new NotSupportedException(__METHOD__ . ' is not supported by PostgreSQL.');
41
    }
42
43 1
    public function alterColumn(string $table, string $column, ColumnSchemaBuilderInterface|string $type): string
44
    {
45 1
        $columnName = $this->quoter->quoteColumnName($column);
46 1
        $tableName = $this->quoter->quoteTableName($table);
47
48 1
        if ($type instanceof ColumnSchemaBuilderInterface) {
49
            $type = $type->asString();
50
        }
51
52
        /**
53
         * {@see https://github.com/yiisoft/yii2/issues/4492}
54
         * {@see http://www.postgresql.org/docs/9.1/static/sql-altertable.html}
55
         */
56 1
        if (preg_match('/^(DROP|SET|RESET|USING)\s+/i', $type)) {
57 1
            return "ALTER TABLE $tableName ALTER COLUMN $columnName $type";
58
        }
59
60 1
        $type = 'TYPE ' . $this->queryBuilder->getColumnType($type);
61 1
        $multiAlterStatement = [];
62 1
        $constraintPrefix = preg_replace('/[^a-z0-9_]/i', '', $table . '_' . $column);
63
64 1
        if (preg_match('/\s+DEFAULT\s+(["\']?\w*["\']?)/i', $type, $matches)) {
65 1
            $type = preg_replace('/\s+DEFAULT\s+(["\']?\w*["\']?)/i', '', $type);
66 1
            $multiAlterStatement[] = "ALTER COLUMN $columnName SET DEFAULT $matches[1]";
67
        }
68
69 1
        $type = preg_replace('/\s+NOT\s+NULL/i', '', $type, -1, $count);
70
71 1
        if ($count) {
72 1
            $multiAlterStatement[] = "ALTER COLUMN $columnName SET NOT NULL";
73
        } else {
74
            /** remove additional null if any */
75 1
            $type = preg_replace('/\s+NULL/i', '', $type, -1, $count);
76 1
            if ($count) {
77 1
                $multiAlterStatement[] = "ALTER COLUMN $columnName DROP NOT NULL";
78
            }
79
        }
80
81 1
        if (preg_match('/\s+CHECK\s+\((.+)\)/i', $type, $matches)) {
82 1
            $type = preg_replace('/\s+CHECK\s+\((.+)\)/i', '', $type);
83 1
            $multiAlterStatement[] = "ADD CONSTRAINT {$constraintPrefix}_check CHECK ($matches[1])";
84
        }
85
86 1
        $type = preg_replace('/\s+UNIQUE/i', '', $type, -1, $count);
87
88 1
        if ($count) {
89 1
            $multiAlterStatement[] = "ADD UNIQUE ($columnName)";
90
        }
91
92
        /** add what's left at the beginning */
93 1
        array_unshift($multiAlterStatement, "ALTER COLUMN $columnName $type");
94
95 1
        return 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $multiAlterStatement);
96
    }
97
98
    /**
99
     * @throws Exception
100
     * @throws NotSupportedException
101
     * @throws Throwable
102
     */
103 2
    public function checkIntegrity(string $schema = '', string $table = '', bool $check = true): string
104
    {
105
        /** @psalm-var Schema $schemaInstance */
106 2
        $schemaInstance = $this->schema;
107 2
        $enable = $check ? 'ENABLE' : 'DISABLE';
108 2
        $schema = $schema ?: $schemaInstance->getDefaultSchema();
109 2
        $tableNames = [];
110 2
        $viewNames = [];
111
112 2
        if ($schema !== null) {
113 2
            $tableNames = $table ? [$table] : $schemaInstance->getTableNames($schema);
114 2
            $viewNames = $schemaInstance->getViewNames($schema);
115
        }
116
117 2
        $tableNames = array_diff($tableNames, $viewNames);
118 2
        $command = '';
119
120
        /** @psalm-var string[] $tableNames */
121 2
        foreach ($tableNames as $tableName) {
122 2
            $tableName = $this->quoter->quoteTableName("$schema.$tableName");
123 2
            $command .= "ALTER TABLE $tableName $enable TRIGGER ALL; ";
124
        }
125
126
        /** enable to have ability to alter several tables */
127
        //$pdo = $db->getSlavePdo();
128
        //$pdo?->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
129
130 2
        return $command;
131
    }
132
133
    /**
134
     * @throws Exception|InvalidArgumentException
135
     */
136 10
    public function createIndex(string $name, string $table, array|string $columns, ?string $indexType = null, ?string $indexMethod = null): string
137
    {
138 10
        return 'CREATE ' . ($indexType ? ($indexType . ' ') : '') . 'INDEX '
139 10
            . $this->quoter->quoteTableName($name) . ' ON '
140 10
            . $this->quoter->quoteTableName($table)
141 10
            . ($indexMethod !== null ? " USING $indexMethod" : '')
142 10
            . ' (' . $this->queryBuilder->buildColumns($columns) . ')';
143
    }
144
145
    /**
146
     * @throws NotSupportedException
147
     */
148 2
    public function dropDefaultValue(string $name, string $table): string
149
    {
150 2
        throw new NotSupportedException(__METHOD__ . ' is not supported by PostgreSQL.');
151
    }
152
153 2
    public function dropIndex(string $name, string $table): string
154
    {
155 2
        if (str_contains($table, '.') && !str_contains($name, '.')) {
156 1
            if (str_contains($table, '{{')) {
157 1
                $table = preg_replace('/{{(.*?)}}/', '\1', $table);
158 1
                [$schema] = explode('.', $table);
159 1
                if (!str_contains($schema, '%')) {
160 1
                    $name = $schema . '.' . $name;
161
                } else {
162 1
                    $name = '{{' . $schema . '.' . $name . '}}';
163
                }
164
            } else {
165 1
                [$schema] = explode('.', $table);
166 1
                $name = $schema . '.' . $name;
167
            }
168
        }
169
170 2
        return 'DROP INDEX ' . $this->quoter->quoteTableName($name);
171
    }
172
173 2
    public function truncateTable(string $table): string
174
    {
175 2
        return 'TRUNCATE TABLE ' . $this->quoter->quoteTableName($table) . ' RESTART IDENTITY';
176
    }
177
178 3
    public function renameTable(string $oldName, string $newName): string
179
    {
180 3
        return 'ALTER TABLE '
181 3
            . $this->quoter->quoteTableName($oldName)
182 3
            . ' RENAME TO '
183 3
            . $this->quoter->quoteTableName($newName);
184
    }
185
}
186