Passed
Push — dev ( cc6591...c9f34d )
by Wilmer
04:23 queued 23s
created

QueryBuilderPDOMssql::newBuildOrderByAndLimit()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 27
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 9
nc 8
nop 5
dl 0
loc 27
ccs 10
cts 10
cp 1
crap 4
rs 9.9666
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Mssql\PDO;
6
7
use Yiisoft\Db\Command\CommandInterface;
8
use Yiisoft\Db\Exception\Exception;
9
use Yiisoft\Db\Exception\InvalidArgumentException;
10
use Yiisoft\Db\Expression\Expression;
11
use Yiisoft\Db\Mssql\Condition\InConditionBuilder;
12
use Yiisoft\Db\Mssql\Condition\LikeConditionBuilder;
13
use Yiisoft\Db\Mssql\DDLQueryBuilder;
14
use Yiisoft\Db\Mssql\DMLQueryBuilder;
15
use Yiisoft\Db\Query\Conditions\InCondition;
16
use Yiisoft\Db\Query\Conditions\LikeCondition;
17
use Yiisoft\Db\Query\Query;
18
use Yiisoft\Db\Query\QueryBuilder;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Query\QueryBuilder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use Yiisoft\Db\Schema\ColumnSchemaBuilder;
20
use Yiisoft\Db\Schema\QuoterInterface;
21
use Yiisoft\Db\Schema\Schema;
22
use Yiisoft\Db\Schema\SchemaInterface;
23
24
use function preg_match;
25
use function preg_replace;
26
27
final class QueryBuilderPDOMssql extends QueryBuilder
28
{
29
    /**
30
     * @psalm-var string[] $typeMap Mapping from abstract column types (keys) to physical column types (values).
31
     */
32
    protected array $typeMap = [
33
        Schema::TYPE_PK => 'int IDENTITY PRIMARY KEY',
34
        Schema::TYPE_UPK => 'int IDENTITY PRIMARY KEY',
35
        Schema::TYPE_BIGPK => 'bigint IDENTITY PRIMARY KEY',
36
        Schema::TYPE_UBIGPK => 'bigint IDENTITY PRIMARY KEY',
37
        Schema::TYPE_CHAR => 'nchar(1)',
38
        Schema::TYPE_STRING => 'nvarchar(255)',
39
        Schema::TYPE_TEXT => 'nvarchar(max)',
40
        Schema::TYPE_TINYINT => 'tinyint',
41
        Schema::TYPE_SMALLINT => 'smallint',
42
        Schema::TYPE_INTEGER => 'int',
43
        Schema::TYPE_BIGINT => 'bigint',
44
        Schema::TYPE_FLOAT => 'float',
45
        Schema::TYPE_DOUBLE => 'float',
46
        Schema::TYPE_DECIMAL => 'decimal(18,0)',
47
        Schema::TYPE_DATETIME => 'datetime',
48
        Schema::TYPE_TIMESTAMP => 'datetime',
49
        Schema::TYPE_TIME => 'time',
50
        Schema::TYPE_DATE => 'date',
51
        Schema::TYPE_BINARY => 'varbinary(max)',
52
        Schema::TYPE_BOOLEAN => 'bit',
53
        Schema::TYPE_MONEY => 'decimal(19,4)',
54
    ];
55
56 367
    public function __construct(
57
        private CommandInterface $command,
58
        private QuoterInterface $quoter,
59
        private SchemaInterface $schema
60
    ) {
61 367
        $this->ddlBuilder = new DDLQueryBuilder($this);
0 ignored issues
show
Bug Best Practice introduced by
The property ddlBuilder does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
62 367
        $this->dmlBuilder = new DMLQueryBuilder($this);
0 ignored issues
show
Bug Best Practice introduced by
The property dmlBuilder does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
63 367
        parent::__construct($quoter, $schema);
64
    }
65
66 4
    public function addCommentOnColumn(string $table, string $column, string $comment): string
67
    {
68 4
        return $this->ddlBuilder->addCommentOnColumn($table, $column, $comment);
69
    }
70
71 4
    public function addCommentOnTable(string $table, string $comment): string
72
    {
73 4
        return $this->ddlBuilder->addCommentOnTable($table, $comment);
74
    }
75
76 1
    public function alterColumn(string $table, string $column, string $type): string
77
    {
78 1
        $type = $this->getColumnType($type);
79 1
        return $this->ddlBuilder->alterColumn($table, $column, $type);
80
    }
81
82 170
    public function buildOrderByAndLimit(string $sql, array $orderBy, $limit, $offset, array &$params = []): string
83
    {
84 170
        if (!$this->hasOffset($offset) && !$this->hasLimit($limit)) {
85 161
            $orderBy = $this->buildOrderBy($orderBy, $params);
86
87 161
            return $orderBy === '' ? $sql : $sql . $this->separator . $orderBy;
88
        }
89
90 13
        return $this->newBuildOrderByAndLimit($sql, $orderBy, $limit, $offset, $params);
91
    }
92
93 1
    public function checkIntegrity(string $schema = '', string $table = '', bool $check = true): string
94
    {
95 1
        return $this->ddlBuilder->checkIntegrity($schema, $table, $check);
96
    }
97
98 1
    public function command(): CommandInterface
99
    {
100 1
        return $this->command;
101
    }
102
103 2
    public function dropCommentFromColumn(string $table, string $column): string
104
    {
105 2
        return $this->ddlBuilder->dropCommentFromColumn($table, $column);
106
    }
107
108 2
    public function dropCommentFromTable(string $table): string
109
    {
110 2
        return $this->ddlBuilder->dropCommentFromTable($table);
111
    }
112
113 13
    public function getColumnType(ColumnSchemaBuilder|string $type): string
114
    {
115 13
        $columnType = parent::getColumnType($type);
116
117
        /** remove unsupported keywords*/
118 13
        $columnType = preg_replace("/\s*comment '.*'/i", '', $columnType);
119 13
        return preg_replace('/ first$/i', '', $columnType);
120
    }
121
122 303
    public function quoter(): QuoterInterface
123
    {
124 303
        return $this->quoter;
125
    }
126
127 2
    public function renameTable(string $oldName, string $newName): string
128
    {
129 2
        return $this->ddlBuilder->renameTable($oldName, $newName);
130
    }
131
132 1
    public function renameColumn(string $table, string $oldName, string $newName): string
133
    {
134 1
        return $this->ddlBuilder->renameColumn($table, $oldName, $newName);
135
    }
136
137 1
    public function selectExists(string $rawSql): string
138
    {
139 1
        return 'SELECT CASE WHEN EXISTS(' . $rawSql . ') THEN 1 ELSE 0 END';
140
    }
141
142 181
    public function schema(): SchemaInterface
143
    {
144 181
        return $this->schema;
145
    }
146
147 367
    protected function defaultExpressionBuilders(): array
148
    {
149 367
        return array_merge(parent::defaultExpressionBuilders(), [
150
            InCondition::class => InConditionBuilder::class,
151
            LikeCondition::class => LikeConditionBuilder::class,
152
        ]);
153
    }
154
155
    /**
156
     * Builds the ORDER BY/LIMIT/OFFSET clauses for SQL SERVER 2012 or newer.
157
     *
158
     * @param string $sql the existing SQL (without ORDER BY/LIMIT/OFFSET).
159
     * @param array $orderBy the order by columns. See {@see Query::orderBy} for more details on how to specify
160
     * this parameter.
161
     * @param Expression|int|null $limit the limit number. See {@see Query::limit} for more details.
162
     * @param Expression|int|null $offset the offset number. See {@see Query::offset} for more details.
163
     * @param array $params the binding parameters to be populated.
164
     *
165
     * @psalm-param array<string, Expression|int|string> $orderBy
166
     *
167
     * @throws Exception|InvalidArgumentException
168
     *
169
     * @return string the SQL completed with ORDER BY/LIMIT/OFFSET (if any).
170
     */
171 13
    protected function newBuildOrderByAndLimit(
172
        string $sql,
173
        array $orderBy,
174
        Expression|int|null $limit,
175
        Expression|int|null $offset,
176
        array &$params = []
177
    ): string {
178 13
        $orderBy = $this->buildOrderBy($orderBy, $params);
179
180 13
        if ($orderBy === '') {
181
            /** ORDER BY clause is required when FETCH and OFFSET are in the SQL */
182 10
            $orderBy = 'ORDER BY (SELECT NULL)';
183
        }
184
185 13
        $sql .= $this->separator . $orderBy;
186
187
        /**
188
         * {@see http://technet.microsoft.com/en-us/library/gg699618.aspx}
189
         */
190 13
        $offset = $this->hasOffset($offset) ? $offset : '0';
191 13
        $sql .= $this->separator . 'OFFSET ' . (string) $offset . ' ROWS';
192
193 13
        if ($this->hasLimit($limit)) {
194 12
            $sql .= $this->separator . 'FETCH NEXT ' . (string) $limit . ' ROWS ONLY';
195
        }
196
197 13
        return $sql;
198
    }
199
200
    /**
201
     * Extracts table alias if there is one or returns false
202
     *
203
     * @param string $table
204
     *
205
     * @psalm-return string[]|bool
206
     */
207 61
    protected function extractAlias(string $table): array|bool
208
    {
209 61
        if (preg_match('/^\[.*]$/', $table)) {
210
            return false;
211
        }
212
213 61
        return parent::extractAlias($table);
214
    }
215
}
216