Passed
Pull Request — dev (#90)
by Wilmer
06:19 queued 02:38
created

QueryBuilderPDOSqlite::quoter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 1
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Sqlite\PDO;
6
7
use Generator;
8
use Yiisoft\Db\Command\CommandInterface;
9
use Yiisoft\Db\Exception\NotSupportedException;
10
use Yiisoft\Db\Expression\Expression;
11
use Yiisoft\Db\Expression\ExpressionBuilder;
12
use Yiisoft\Db\Expression\ExpressionBuilderInterface;
13
use Yiisoft\Db\Expression\ExpressionInterface;
14
use Yiisoft\Db\Query\Conditions\InCondition;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Query\Conditions\InCondition 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...
15
use Yiisoft\Db\Query\Conditions\LikeCondition;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Query\Conditions\LikeCondition 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...
16
use Yiisoft\Db\Query\Query;
17
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...
18
use Yiisoft\Db\Query\QueryInterface;
19
use Yiisoft\Db\Schema\QuoterInterface;
20
use Yiisoft\Db\Schema\Schema;
21
use Yiisoft\Db\Schema\SchemaInterface;
22
use Yiisoft\Db\Sqlite\Builder\InConditionBuilder;
23
use Yiisoft\Db\Sqlite\Builder\LikeConditionBuilder;
24
use Yiisoft\Db\Sqlite\DDLQueryBuilder;
25
use Yiisoft\Db\Sqlite\DMLQueryBuilder;
26
27
use function array_filter;
28
use function array_merge;
29
use function implode;
30
use function trim;
31
32
final class QueryBuilderPDOSqlite extends QueryBuilder
33
{
34
    /**
35
     * @var array mapping from abstract column types (keys) to physical column types (values).
36
     *
37
     * @psalm-var string[] $typeMap
38
     */
39
    protected array $typeMap = [
40
        Schema::TYPE_PK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
41
        Schema::TYPE_UPK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
42
        Schema::TYPE_BIGPK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
43
        Schema::TYPE_UBIGPK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
44
        Schema::TYPE_CHAR => 'char(1)',
45
        Schema::TYPE_STRING => 'varchar(255)',
46
        Schema::TYPE_TEXT => 'text',
47
        Schema::TYPE_TINYINT => 'tinyint',
48
        Schema::TYPE_SMALLINT => 'smallint',
49
        Schema::TYPE_INTEGER => 'integer',
50
        Schema::TYPE_BIGINT => 'bigint',
51
        Schema::TYPE_FLOAT => 'float',
52
        Schema::TYPE_DOUBLE => 'double',
53
        Schema::TYPE_DECIMAL => 'decimal(10,0)',
54
        Schema::TYPE_DATETIME => 'datetime',
55
        Schema::TYPE_TIMESTAMP => 'timestamp',
56
        Schema::TYPE_TIME => 'time',
57
        Schema::TYPE_DATE => 'date',
58
        Schema::TYPE_BINARY => 'blob',
59
        Schema::TYPE_BOOLEAN => 'boolean',
60
        Schema::TYPE_MONEY => 'decimal(19,4)',
61
    ];
62
    private DDLQueryBuilder $ddlBuilder;
63
    private DMLQueryBuilder $dmlBuilder;
64
65 324
    public function __construct(
66
        private CommandInterface $command,
67
        private QuoterInterface $quoter,
68
        private SchemaInterface $schema
69
    ) {
70 324
        $this->ddlBuilder = new DDLQueryBuilder($this);
71 324
        $this->dmlBuilder = new DMLQueryBuilder($this);
72 324
        parent::__construct($quoter, $schema, $this->ddlBuilder, $this->dmlBuilder);
73
    }
74
75 3
    public function addForeignKey(
76
        string $name,
77
        string $table,
78
        array|string $columns,
79
        string $refTable,
80
        array|string $refColumns,
81
        ?string $delete = null,
82
        ?string $update = null
83
    ): string {
84 3
        return $this->ddlBuilder->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update);
85
    }
86
87
    /**
88
     * @throws NotSupportedException
89
     */
90
    public function addPrimaryKey(string $name, string $table, array|string $columns): string
91
    {
92
        return $this->ddlBuilder->addPrimaryKey($name, $table, $columns);
93
    }
94
95
    /**
96
     * @throws NotSupportedException
97
     */
98 1
    public function addUnique(string $name, string $table, array|string $columns): string
99
    {
100 1
        return $this->ddlBuilder->addUnique($name, $table, $columns);
101
    }
102
103
    /**
104
     * @throws NotSupportedException
105
     */
106
    public function alterColumn(string $table, string $column, string $type): string
107
    {
108
        return $this->ddlBuilder->alterColumn($table, $column, $type);
109
    }
110
111 13
    public function batchInsert(string $table, array $columns, iterable|Generator $rows, array &$params = []): string
112
    {
113 13
        return $this->dmlBuilder->batchInsert($table, $columns, $rows, $params);
114
    }
115
116 163
    public function build(QueryInterface $query, array $params = []): array
117
    {
118 163
        $query = $query->prepare($this);
119
120 163
        $params = empty($params) ? $query->getParams() : array_merge($params, $query->getParams());
121
122 163
        $clauses = [
123 163
            $this->buildSelect($query->getSelect(), $params, $query->getDistinct(), $query->getSelectOption()),
124 163
            $this->buildFrom($query->getFrom(), $params),
125 163
            $this->buildJoin($query->getJoin(), $params),
126 163
            $this->buildWhere($query->getWhere(), $params),
127 163
            $this->buildGroupBy($query->getGroupBy()),
128 163
            $this->buildHaving($query->getHaving(), $params),
129
        ];
130
131 163
        $orderBy = $query->getOrderBy();
132 163
        $sql = implode($this->separator, array_filter($clauses));
133 163
        $sql = $this->buildOrderByAndLimit($sql, $orderBy, $query->getLimit(), $query->getOffset());
134
135 163
        if (!empty($orderBy)) {
136
            /** @psalm-var array<string|ExpressionInterface> $orderBy */
137 6
            foreach ($orderBy as $expression) {
138 6
                if ($expression instanceof ExpressionInterface) {
139 1
                    $this->buildExpression($expression, $params);
140
                }
141
            }
142
        }
143
144 163
        $groupBy = $query->getGroupBy();
145
146 163
        if (!empty($groupBy)) {
147
            /** @psalm-var array<string|ExpressionInterface> $groupBy */
148 2
            foreach ($groupBy as $expression) {
149 2
                if ($expression instanceof ExpressionInterface) {
150 1
                    $this->buildExpression($expression, $params);
151
                }
152
            }
153
        }
154
155 163
        $union = $this->buildUnion($query->getUnion(), $params);
156
157 163
        if ($union !== '') {
158 3
            $sql = "$sql$this->separator$union";
159
        }
160
161 163
        $with = $this->buildWithQueries($query->getWithQueries(), $params);
162
163 163
        if ($with !== '') {
164 2
            $sql = "$with$this->separator$sql";
165
        }
166
167 163
        return [$sql, $params];
168
    }
169
170 163
    public function buildLimit(Expression|int|null $limit, Expression|int|null $offset): string
171
    {
172 163
        $sql = '';
173
174 163
        if ($this->hasLimit($limit)) {
175 9
            $sql = "LIMIT $limit";
176 9
            if ($this->hasOffset($offset)) {
177 9
                $sql .= " OFFSET $offset";
178
            }
179 157
        } elseif ($this->hasOffset($offset)) {
180
            /**
181
             * limit is not optional in SQLite.
182
             *
183
             * {@see http://www.sqlite.org/syntaxdiagrams.html#select-stmt}
184
             */
185
            $sql = "LIMIT 9223372036854775807 OFFSET $offset"; // 2^63-1
186
        }
187
188 163
        return $sql;
189
    }
190
191 163
    public function buildUnion(array $unions, array &$params = []): string
192
    {
193 163
        if (empty($unions)) {
194 163
            return '';
195
        }
196
197 3
        $result = '';
198
199
        /** @psalm-var array<array-key, array{query: Query|null, all: bool}> $unions */
200 3
        foreach ($unions as $i => $union) {
201 3
            $query = $union['query'];
202 3
            if ($query instanceof Query) {
203 3
                [$unions[$i]['query'], $params] = $this->build($query, $params);
204
            }
205
206 3
            $result .= ' UNION ' . ($union['all'] ? 'ALL ' : '') . ' ' . (string) $unions[$i]['query'];
207
        }
208
209 3
        return trim($result);
210
    }
211
212
    public function checkIntegrity(string $schema = '', string $table = '', bool $check = true): string
213
    {
214
        return $this->ddlBuilder->checkIntegrity($schema, $table, $check);
215
    }
216
217 7
    public function createIndex(string $name, string $table, $columns, bool $unique = false): string
218
    {
219 7
        return $this->ddlBuilder->createIndex($name, $table, $columns, $unique);
220
    }
221
222 1
    public function command(): CommandInterface
223
    {
224 1
        return $this->command;
225
    }
226
227
    /**
228
     * @throws NotSupportedException
229
     */
230
    public function dropColumn(string $table, string $column): string
231
    {
232
        return $this->ddlBuilder->dropColumn($table, $column);
233
    }
234
235
    /**
236
     * @throws NotSupportedException
237
     */
238 2
    public function dropForeignKey(string $name, string $table): string
239
    {
240 2
        return $this->ddlBuilder->dropForeignKey($name, $table);
241
    }
242
243 2
    public function dropIndex(string $name, string $table): string
244
    {
245 2
        return $this->ddlBuilder->dropIndex($name, $table);
246
    }
247
248
    /**
249
     * @throws NotSupportedException
250
     */
251
    public function dropPrimaryKey(string $name, string $table): string
252
    {
253
        return $this->ddlBuilder->dropPrimaryKey($name, $table);
254
    }
255
256
    /**
257
     * @throws NotSupportedException
258
     */
259 1
    public function dropUnique(string $name, string $table): string
260
    {
261 1
        return $this->ddlBuilder->dropUnique($name, $table);
262
    }
263
264 257
    public function quoter(): QuoterInterface
265
    {
266 257
        return $this->quoter;
267
    }
268
269 69
    public function schema(): SchemaInterface
270
    {
271 69
        return $this->schema;
272
    }
273
274
    /**
275
     * @throws NotSupportedException
276
     */
277
    public function renameColumn(string $table, string $oldName, string $newName): string
278
    {
279
        return $this->ddlBuilder->renameColumn($table, $oldName, $newName);
280
    }
281
282 3
    public function renameTable(string $oldName, string $newName): string
283
    {
284 3
        return $this->ddlBuilder->renameTable($oldName, $newName);
285
    }
286
287 1
    public function truncateTable(string $table): string
288
    {
289 1
        return $this->ddlBuilder->truncateTable($table);
290
    }
291
292
    /**
293
     * Contains array of default expression builders. Extend this method and override it, if you want to change default
294
     * expression builders for this query builder.
295
     *
296
     * @return array
297
     *
298
     * See {@see ExpressionBuilder} docs for details.
299
     *
300
     * @psalm-return array<string, class-string<ExpressionBuilderInterface>>
301
     */
302 324
    protected function defaultExpressionBuilders(): array
303
    {
304 324
        return array_merge(parent::defaultExpressionBuilders(), [
305
            LikeCondition::class => LikeConditionBuilder::class,
306
            InCondition::class => InConditionBuilder::class,
307
        ]);
308
    }
309
}
310