Passed
Push — master ( 8399e4...1d45c6 )
by Wilmer
03:47
created

DQLQueryBuilder   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 24
eloc 51
c 2
b 0
f 0
dl 0
loc 121
ccs 57
cts 57
cp 1
rs 10

5 Methods

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