DQLQueryBuilder::extractAlias()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

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