Test Failed
Push — master ( 27a7bf...bd3e29 )
by Sergei
04:23
created

DQLQueryBuilder::buildWithQueries()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 8
ccs 0
cts 0
cp 0
crap 6
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Mssql;
6
7
use Yiisoft\Db\Exception\Exception;
8
use Yiisoft\Db\Exception\InvalidArgumentException;
9
use Yiisoft\Db\Expression\ExpressionInterface;
10
use Yiisoft\Db\Mssql\Builder\InConditionBuilder;
11
use Yiisoft\Db\Mssql\Builder\LikeConditionBuilder;
12
use Yiisoft\Db\Query\Query;
13
use Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder;
14
use Yiisoft\Db\QueryBuilder\Condition\InCondition;
15
use Yiisoft\Db\QueryBuilder\Condition\LikeCondition;
16
17
use function array_merge;
18
use function preg_match;
19
20
/**
21
 * Implements a DQL (Data Query Language) SQL statements for MSSQL Server.
22
 */
23
final class DQLQueryBuilder extends AbstractDQLQueryBuilder
24 223
{
25
    public function buildOrderByAndLimit(
26
        string $sql,
27
        array $orderBy,
28
        ExpressionInterface|int|null $limit,
29
        ExpressionInterface|int|null $offset,
30
        array &$params = []
31 223
    ): string {
32 214
        if (!$this->hasOffset($offset) && !$this->hasLimit($limit)) {
33
            $orderByString = $this->buildOrderBy($orderBy, $params);
34 214
35
            return $orderByString === '' ? $sql : $sql . $this->separator . $orderByString;
36
        }
37 16
38
        return $this->newBuildOrderByAndLimit($sql, $orderBy, $limit, $offset, $params);
39
    }
40 1
41
    public function selectExists(string $rawSql): string
42 1
    {
43
        return 'SELECT CASE WHEN EXISTS(' . $rawSql . ') THEN 1 ELSE 0 END';
44
    }
45 881
46
    protected function defaultExpressionBuilders(): array
47 881
    {
48 881
        return array_merge(parent::defaultExpressionBuilders(), [
49 881
            InCondition::class => InConditionBuilder::class,
50 881
            LikeCondition::class => LikeConditionBuilder::class,
51
        ]);
52
    }
53
54
    /**
55
     * Builds the `ORDER BY`/`LIMIT`/`OFFSET` clauses for SQL SERVER 2012 or newer.
56
     *
57
     * @param string $sql The existing SQL (without `ORDER BY`/`LIMIT`/`OFFSET`).
58
     * @param array $orderBy The order by columns. See {@see Query::orderBy} for more details on how to specify
59
     * this parameter.
60
     * @param ExpressionInterface|int|null $limit The limit number. See {@see Query::limit} for more details.
61
     * @param ExpressionInterface|int|null $offset The offset number. See {@see Query::offset} for more details.
62
     * @param array $params The binding parameters to populate.
63
     *
64
     * @throws Exception
65
     * @throws InvalidArgumentException
66
     *
67
     * @return string The SQL completed with `ORDER BY`/`LIMIT`/`OFFSET` (if any).
68 16
     */
69
    protected function newBuildOrderByAndLimit(
70
        string $sql,
71
        array $orderBy,
72
        ExpressionInterface|int|null $limit,
73
        ExpressionInterface|int|null $offset,
74
        array &$params = []
75 16
    ): string {
76
        $orderByString = $this->buildOrderBy($orderBy, $params);
77 16
78
        if ($orderByString === '') {
79 12
            /** `ORDER BY` clause is required when `FETCH` and `OFFSET` are in the SQL */
80
            $orderByString = 'ORDER BY (SELECT NULL)';
81
        }
82 16
83
        $sql .= $this->separator . $orderByString;
84
85
        /**
86
         * @link http://technet.microsoft.com/en-us/library/gg699618.aspx
87 16
         */
88 16
        $offsetString = $this->hasOffset($offset) ?
89 16
            ($offset instanceof ExpressionInterface ? $this->buildExpression($offset) : (string)$offset) : '0';
90
        $sql .= $this->separator . 'OFFSET ' . $offsetString . ' ROWS';
91 16
92 15
        if ($this->hasLimit($limit)) {
93 15
            $sql .= $this->separator . 'FETCH NEXT ' .
94
                ($limit instanceof ExpressionInterface ? $this->buildExpression($limit) : (string)$limit) . ' ROWS ONLY';
95
        }
96 16
97
        return $sql;
98
    }
99
100
    /**
101
     * Extracts table alias if there is one or returns `false`.
102
     *
103
     * @psalm-return string[]|bool
104 89
     */
105
    protected function extractAlias(string $table): array|bool
106 89
    {
107 1
        if (preg_match('/^\[.*]$/', $table)) {
108
            return false;
109
        }
110 89
111
        return parent::extractAlias($table);
112
    }
113
114
    public function buildWithQueries(array $withs, array &$params): string
115
    {
116
        /** @psalm-var array{query:string|Query, alias:ExpressionInterface|string, recursive:bool}[] $withs */
117
        foreach ($withs as &$with) {
118
            $with['recursive'] = false;
119
        }
120
121
        return parent::buildWithQueries($withs, $params);
122
    }
123
}
124