Test Failed
Pull Request — master (#82)
by Wilmer
24:21 queued 13:10
created

QueryBuilderPDOSqlite::build()   B

Complexity

Conditions 10
Paths 32

Size

Total Lines 47
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 26
dl 0
loc 47
rs 7.6666
c 1
b 0
f 0
cc 10
nc 32
nop 2

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Sqlite\PDO;
6
7
use Generator;
8
use JsonException;
9
use Throwable;
10
use Yiisoft\Db\Command\CommandInterface;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Command\CommandInterface 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...
11
use Yiisoft\Db\Connection\ConnectionInterface;
12
use Yiisoft\Db\Constraint\Constraint;
13
use Yiisoft\Db\Exception\Exception;
14
use Yiisoft\Db\Exception\InvalidArgumentException;
15
use Yiisoft\Db\Exception\InvalidConfigException;
16
use Yiisoft\Db\Exception\NotSupportedException;
17
use Yiisoft\Db\Expression\Expression;
18
use Yiisoft\Db\Expression\ExpressionBuilder;
19
use Yiisoft\Db\Expression\ExpressionInterface;
20
use Yiisoft\Db\Query\Conditions\InCondition;
21
use Yiisoft\Db\Query\Conditions\LikeCondition;
22
use Yiisoft\Db\Query\Query;
23
use Yiisoft\Db\Query\QueryBuilder;
24
use Yiisoft\Db\Schema\QuoterInterface;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Schema\QuoterInterface 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...
25
use Yiisoft\Db\Schema\Schema;
26
use Yiisoft\Db\Schema\SchemaInterface;
27
use Yiisoft\Db\Sqlite\Condition\InConditionBuilder;
28
use Yiisoft\Db\Sqlite\Condition\LikeConditionBuilder;
29
use Yiisoft\Db\Sqlite\DDLQueryBuilder;
30
use Yiisoft\Db\Sqlite\DMLQueryBuilder;
31
use Yiisoft\Strings\NumericHelper;
32
33
use function array_filter;
34
use function array_merge;
35
use function implode;
36
use function is_float;
37
use function is_string;
38
use function ltrim;
39
use function reset;
40
use function strrpos;
41
use function trim;
42
use function version_compare;
43
44
final class QueryBuilderPDOSqlite extends QueryBuilder
45
{
46
    /**
47
     * @var array mapping from abstract column types (keys) to physical column types (values).
48
     *
49
     * @psalm-var array<string, string>
50
     */
51
    protected array $typeMap = [
52
        Schema::TYPE_PK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
53
        Schema::TYPE_UPK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
54
        Schema::TYPE_BIGPK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
55
        Schema::TYPE_UBIGPK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
56
        Schema::TYPE_CHAR => 'char(1)',
57
        Schema::TYPE_STRING => 'varchar(255)',
58
        Schema::TYPE_TEXT => 'text',
59
        Schema::TYPE_TINYINT => 'tinyint',
60
        Schema::TYPE_SMALLINT => 'smallint',
61
        Schema::TYPE_INTEGER => 'integer',
62
        Schema::TYPE_BIGINT => 'bigint',
63
        Schema::TYPE_FLOAT => 'float',
64
        Schema::TYPE_DOUBLE => 'double',
65
        Schema::TYPE_DECIMAL => 'decimal(10,0)',
66
        Schema::TYPE_DATETIME => 'datetime',
67
        Schema::TYPE_TIMESTAMP => 'timestamp',
68
        Schema::TYPE_TIME => 'time',
69
        Schema::TYPE_DATE => 'date',
70
        Schema::TYPE_BINARY => 'blob',
71
        Schema::TYPE_BOOLEAN => 'boolean',
72
        Schema::TYPE_MONEY => 'decimal(19,4)',
73
    ];
74
75
    public function __construct(
76
        private CommandInterface $command,
77
        private QuoterInterface $quoter,
78
        private SchemaInterface $schema
79
    ) {
80
        $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...
81
        $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...
82
        parent::__construct($quoter, $schema);
0 ignored issues
show
Unused Code introduced by
The call to Yiisoft\Db\Query\QueryBuilder::__construct() has too many arguments starting with $schema. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

82
        parent::/** @scrutinizer ignore-call */ 
83
                __construct($quoter, $schema);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
83
    }
84
85
    public function addForeignKey(
86
        string $name,
87
        string $table,
88
        array|string $columns,
89
        string $refTable,
90
        array|string $refColumns,
91
        ?string $delete = null,
92
        ?string $update = null
93
    ): string {
94
        return $this->ddlBuilder->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update);
95
    }
96
97
    public function addPrimaryKey(string $name, string $table, array|string $columns): string
98
    {
99
        return $this->ddlBuilder->addPrimaryKey($name, $table, $columns);
100
    }
101
102
    public function addUnique(string $name, string $table, array|string $columns): string
103
    {
104
        return $this->ddlBuilder->addUnique($name, $table, $columns);
105
    }
106
107
    public function alterColumn(string $table, string $column, string $type): string
108
    {
109
        return $this->ddlBuilder->alterColumn($table, $column, $type);
110
    }
111
112
    public function batchInsert(string $table, array $columns, iterable|Generator $rows, array &$params = []): string
113
    {
114
        return $this->dmlBuilder->batchInsert($table, $columns, $rows, $params);
115
    }
116
117
    public function build(Query $query, array $params = []): array
118
    {
119
        $query = $query->prepare($this);
120
121
        $params = empty($params) ? $query->getParams() : array_merge($params, $query->getParams());
122
123
        $clauses = [
124
            $this->buildSelect($query->getSelect(), $params, $query->getDistinct(), $query->getSelectOption()),
125
            $this->buildFrom($query->getFrom(), $params),
126
            $this->buildJoin($query->getJoin(), $params),
127
            $this->buildWhere($query->getWhere(), $params),
128
            $this->buildGroupBy($query->getGroupBy()),
129
            $this->buildHaving($query->getHaving(), $params),
130
        ];
131
132
        $sql = implode($this->separator, array_filter($clauses));
133
        $sql = $this->buildOrderByAndLimit($sql, $query->getOrderBy(), $query->getLimit(), $query->getOffset());
134
135
        if (!empty($query->getOrderBy())) {
136
            foreach ($query->getOrderBy() as $expression) {
137
                if ($expression instanceof ExpressionInterface) {
138
                    $this->buildExpression($expression, $params);
139
                }
140
            }
141
        }
142
143
        if (!empty($query->getGroupBy())) {
144
            foreach ($query->getGroupBy() as $expression) {
145
                if ($expression instanceof ExpressionInterface) {
146
                    $this->buildExpression($expression, $params);
147
                }
148
            }
149
        }
150
151
        $union = $this->buildUnion($query->getUnion(), $params);
152
153
        if ($union !== '') {
154
            $sql = "$sql$this->separator$union";
155
        }
156
157
        $with = $this->buildWithQueries($query->getWithQueries(), $params);
158
159
        if ($with !== '') {
160
            $sql = "$with$this->separator$sql";
161
        }
162
163
        return [$sql, $params];
164
    }
165
166
    public function buildLimit(Expression|int|null $limit, Expression|int|null $offset): string
167
    {
168
        $sql = '';
169
170
        if ($this->hasLimit($limit)) {
171
            $sql = "LIMIT $limit";
172
            if ($this->hasOffset($offset)) {
173
                $sql .= " OFFSET $offset";
174
            }
175
        } elseif ($this->hasOffset($offset)) {
176
            /**
177
             * limit is not optional in SQLite.
178
             *
179
             * {@see http://www.sqlite.org/syntaxdiagrams.html#select-stmt}
180
             */
181
            $sql = "LIMIT 9223372036854775807 OFFSET $offset"; // 2^63-1
182
        }
183
184
        return $sql;
185
    }
186
187
    public function buildUnion(array $unions, array &$params = []): string
188
    {
189
        if (empty($unions)) {
190
            return '';
191
        }
192
193
        $result = '';
194
195
        foreach ($unions as $i => $union) {
196
            $query = $union['query'];
197
            if ($query instanceof Query) {
198
                [$unions[$i]['query'], $params] = $this->build($query, $params);
199
            }
200
201
            $result .= ' UNION ' . ($union['all'] ? 'ALL ' : '') . ' ' . $unions[$i]['query'];
202
        }
203
204
        return trim($result);
205
    }
206
207
    public function checkIntegrity(string $schema = '', string $table = '', bool $check = true): string
208
    {
209
        return $this->ddlBuilder->checkIntegrity($schema, $table, $check);
210
    }
211
212
    public function createIndex(string $name, string $table, $columns, bool $unique = false): string
213
    {
214
        return $this->ddlBuilder->createIndex($name, $table, $columns, $unique);
215
    }
216
217
    public function command(): CommandInterface
218
    {
219
        return $this->command;
220
    }
221
222
    public function dropColumn(string $table, string $column): string
223
    {
224
        return $this->ddlBuilder->dropColumn($table, $column);
225
    }
226
227
    public function dropForeignKey(string $name, string $table): string
228
    {
229
        return $this->ddlBuilder->dropForeignKey($name, $table);
230
    }
231
232
    public function dropIndex(string $name, string $table): string
233
    {
234
        return $this->ddlBuilder->dropIndex($name, $table);
235
    }
236
237
    public function dropPrimaryKey(string $name, string $table): string
238
    {
239
        return $this->ddlBuilder->dropPrimaryKey($name, $table);
240
    }
241
242
    public function dropUnique(string $name, string $table): string
243
    {
244
        return $this->ddlBuilder->dropUnique($name, $table);
245
    }
246
247
    public function quoter(): QuoterInterface
248
    {
249
        return $this->quoter;
250
    }
251
252
    public function schema(): SchemaInterface
253
    {
254
        return $this->schema;
255
    }
256
257
    public function renameColumn(string $table, string $oldName, string $newName): string
258
    {
259
        return $this->ddlBuilder->renameColumn($table, $oldName, $newName);
260
    }
261
262
    public function renameTable(string $oldName, string $newName): string
263
    {
264
        return $this->ddlBuilder->renameTable($oldName, $newName);
265
    }
266
267
    public function truncateTable(string $table): string
268
    {
269
        return $this->ddlBuilder->truncateTable($table);
270
    }
271
272
    /**
273
     * Contains array of default expression builders. Extend this method and override it, if you want to change default
274
     * expression builders for this query builder.
275
     *
276
     * @return array
277
     *
278
     * See {@see ExpressionBuilder} docs for details.
279
     */
280
    protected function defaultExpressionBuilders(): array
281
    {
282
        return array_merge(parent::defaultExpressionBuilders(), [
283
            LikeCondition::class => LikeConditionBuilder::class,
284
            InCondition::class => InConditionBuilder::class,
285
        ]);
286
    }
287
}
288