DQLQueryBuilder   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 23
eloc 51
c 3
b 0
f 0
dl 0
loc 113
ccs 56
cts 56
cp 1
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
B build() 0 50 10
A defaultExpressionBuilders() 0 7 1
B buildLimit() 0 21 7
A buildUnion() 0 18 5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Sqlite;
6
7
use Yiisoft\Db\Expression\Expression;
8
use Yiisoft\Db\Expression\ExpressionBuilderInterface;
9
use Yiisoft\Db\Expression\ExpressionInterface;
10
use Yiisoft\Db\Expression\JsonExpression;
11
use Yiisoft\Db\Query\Query;
12
use Yiisoft\Db\Query\QueryInterface;
13
use Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder;
14
use Yiisoft\Db\QueryBuilder\Condition\InCondition;
15
use Yiisoft\Db\QueryBuilder\Condition\LikeCondition;
16
use Yiisoft\Db\Sqlite\Builder\ExpressionBuilder;
17
use Yiisoft\Db\Sqlite\Builder\InConditionBuilder;
18
use Yiisoft\Db\Sqlite\Builder\JsonExpressionBuilder;
19
use Yiisoft\Db\Sqlite\Builder\LikeConditionBuilder;
20
21
use function array_filter;
22
use function array_merge;
23
use function implode;
24
use function trim;
25
26
/**
27
 * Implements a DQL (Data Query Language) SQL statements for SQLite Server.
28
 */
29 247
final class DQLQueryBuilder extends AbstractDQLQueryBuilder
30
{
31 247
    public function build(QueryInterface $query, array $params = []): array
32
    {
33 247
        $query = $query->prepare($this->queryBuilder);
34
35 247
        $params = empty($params) ? $query->getParams() : array_merge($params, $query->getParams());
36 247
37 247
        $clauses = [
38 247
            $this->buildSelect($query->getSelect(), $params, $query->getDistinct(), $query->getSelectOption()),
39 247
            $this->buildFrom($query->getFrom(), $params),
40 247
            $this->buildJoin($query->getJoins(), $params),
41 247
            $this->buildWhere($query->getWhere(), $params),
42 247
            $this->buildGroupBy($query->getGroupBy()),
43
            $this->buildHaving($query->getHaving(), $params),
44 247
        ];
45 247
46 247
        $orderBy = $query->getOrderBy();
47
        $sql = implode($this->separator, array_filter($clauses));
48 247
        $sql = $this->buildOrderByAndLimit($sql, $orderBy, $query->getLimit(), $query->getOffset());
49 6
50 6
        if (!empty($orderBy)) {
51 1
            foreach ($orderBy as $expression) {
52
                if ($expression instanceof ExpressionInterface) {
53
                    $this->buildExpression($expression, $params);
54
                }
55
            }
56 247
        }
57
58 247
        $groupBy = $query->getGroupBy();
59 2
60 2
        if (!empty($groupBy)) {
61 1
            foreach ($groupBy as $expression) {
62
                if ($expression instanceof ExpressionInterface) {
63
                    $this->buildExpression($expression, $params);
64
                }
65
            }
66 247
        }
67
68 247
        $union = $this->buildUnion($query->getUnions(), $params);
69 4
70
        if ($union !== '') {
71
            $sql = "$sql$this->separator$union";
72 247
        }
73
74 247
        $with = $this->buildWithQueries($query->getWithQueries(), $params);
75 8
76
        if ($with !== '') {
77
            $sql = "$with$this->separator$sql";
78 247
        }
79
80
        return [$sql, $params];
81 250
    }
82
83 250
    public function buildLimit(ExpressionInterface|int|null $limit, ExpressionInterface|int|null $offset): string
84
    {
85 250
        $sql = '';
86 17
87 17
        if ($this->hasLimit($limit)) {
88 17
            $sql = 'LIMIT ' . ($limit instanceof ExpressionInterface ? $this->buildExpression($limit) : (string)$limit);
89 17
            if ($this->hasOffset($offset)) {
90
                $sql .= ' OFFSET ' .
91 239
                    ($offset instanceof ExpressionInterface ? $this->buildExpression($offset) : (string)$offset);
92
            }
93
        } elseif ($this->hasOffset($offset)) {
94
            /**
95
             * Limit isn't optional in SQLite.
96
             *
97 1
             * {@see https://www.sqlite.org/syntaxdiagrams.html#select-stmt}
98 1
             */
99
            $sql = 'LIMIT 9223372036854775807 OFFSET ' . // 2^63-1
100
                ($offset instanceof ExpressionInterface ? $this->buildExpression($offset) : (string)$offset);
101 250
        }
102
103
        return $sql;
104 247
    }
105
106 247
    public function buildUnion(array $unions, array &$params = []): string
107 247
    {
108
        if (empty($unions)) {
109
            return '';
110 5
        }
111
112
        $result = '';
113 5
114 5
        /** @psalm-var array<array-key, array{query: Query|null, all: bool}> $unions */
115 5
        foreach ($unions as $union) {
116
            if ($union['query'] instanceof QueryInterface) {
117
                [$union['query'], $params] = $this->build($union['query'], $params);
118 5
            }
119
120
            $result .= ' UNION ' . ($union['all'] ? 'ALL ' : '') . ' ' . (string) $union['query'];
121 5
        }
122
123
        return trim($result);
124
    }
125
126
    /**
127
     * Has an array of default expression builders.
128
     *
129
     * Extend this method and override it if you want to change default expression builders for this query builder.
130
     *
131
     * {@see ExpressionBuilder} docs for details.
132
     *
133 547
     * @psalm-return array<string, class-string<ExpressionBuilderInterface>>
134
     */
135 547
    protected function defaultExpressionBuilders(): array
136 547
    {
137 547
        return array_merge(parent::defaultExpressionBuilders(), [
138 547
            LikeCondition::class => LikeConditionBuilder::class,
139 547
            InCondition::class => InConditionBuilder::class,
140
            JsonExpression::class => JsonExpressionBuilder::class,
141
            Expression::class => ExpressionBuilder::class,
142
        ]);
143
    }
144
}
145