Passed
Push — main ( 7d9f09...bbfba8 )
by Peter
02:36
created

Select::setLock()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 5
rs 10
ccs 3
cts 3
cp 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace QB\PostgreSQL\Statement;
6
7
use QB\Generic\Statement\Select as GenericSelect;
8
use QB\PostgreSQL\Clause\Lock;
9
10
class Select extends GenericSelect
11
{
12
    protected const UNION     = 'union';
13
    protected const INTERSECT = 'intersect';
14
    protected const EXCEPT    = 'except';
15
16
    protected array $unionLikes = [];
17
18
    protected ?Lock $lock = null;
19
20
    protected ?string $lockTable = null;
21
22
    protected ?int $outerOffset = null;
23
24
    protected ?int $outerLimit = null;
25
26
    /** @var array<string,string> */
27
    protected array $outerOrderByParts = [];
28
29
    /**
30
     * @param int|null $offset
31
     *
32
     * @return $this
33
     */
34
    public function setOuterOffset(?int $offset): static
35
    {
36
        $this->outerOffset = $offset;
37
38
        return $this;
39
    }
40
41
    /**
42
     * @param int|null $limit
43
     *
44
     * @return $this
45
     */
46 1
    public function setOuterLimit(?int $limit): static
47
    {
48 1
        $this->outerLimit = $limit;
49
50 1
        return $this;
51
    }
52
53
    /**
54
     * @param string $column
55
     * @param string $direction
56
     *
57
     * @return Select
58
     */
59
    public function addOuterOrderBy(string $column, string $direction = 'ASC'): static
60
    {
61
        $this->outerOrderByParts[$column] = $direction;
62
63
        return $this;
64
    }
65
66
    /**
67
     * @param Lock $lock
68
     *
69
     * @return $this
70
     */
71 3
    public function setLock(Lock $lock): static
72
    {
73 3
        $this->lock = $lock;
74
75 3
        return $this;
76
    }
77
78
    /**
79
     * @param Select $select
80
     * @param string $modifier
81
     *
82
     * @return $this
83
     */
84 3
    public function addUnion(Select $select, string $modifier = ''): static
85
    {
86 3
        return $this->addUnionLike(static::UNION, $select, $modifier);
87
    }
88
89
    /**
90
     * @param Select $select
91
     * @param string $modifier
92
     *
93
     * @return $this
94
     */
95 1
    public function addIntersect(Select $select, string $modifier = ''): static
96
    {
97 1
        return $this->addUnionLike(static::INTERSECT, $select, $modifier);
98
    }
99
100
    /**
101
     * @param Select $select
102
     * @param string $modifier
103
     *
104
     * @return $this
105
     */
106 1
    public function addExcept(Select $select, string $modifier = ''): static
107
    {
108 1
        return $this->addUnionLike(static::EXCEPT, $select, $modifier);
109
    }
110
111
    /**
112
     * @param string $type
113
     * @param Select $select
114
     * @param string $modifier
115
     *
116
     * @return $this
117
     */
118 4
    protected function addUnionLike(string $type, Select $select, string $modifier = ''): static
119
    {
120 4
        if ($type !== static::INTERSECT && $type !== static::EXCEPT) {
121 3
            $type = static::UNION;
122
        }
123
124 4
        if ($modifier !== static::ALL && $modifier !== static::DISTINCT) {
125 4
            $modifier = '';
126
        }
127
128 4
        $this->unionLikes[] = [$type, $select, $modifier];
129
130 4
        return $this;
131
    }
132
133 18
    public function __toString(): string
134
    {
135 18
        $parts = array_merge(
136 18
            [parent::__toString()],
137 17
            $this->getLock(),
138 17
            $this->getUnionLikes()
139
        );
140
141 17
        $parts = array_filter($parts);
142
143 17
        $sql = implode(PHP_EOL, $parts);
144
145 17
        if ($this->outerLimit === null && $this->outerOffset === null && count($this->outerOrderByParts) === 0) {
146 17
            return $sql;
147
        }
148
149 1
        $parts = array_merge(
150 1
            ['(' . $sql . ')'],
151 1
            $this->getOuterOrderBy(),
152 1
            $this->getOuterLimit()
153
        );
154
155 1
        $parts = array_filter($parts);
156
157 1
        return implode(PHP_EOL, $parts);
158
    }
159
160
    /**
161
     * @return string[]
162
     */
163 17
    protected function getLock(): array
164
    {
165 17
        if ($this->lock === null) {
166 17
            return [];
167
        }
168
169 3
        return [(string)$this->lock];
170
    }
171
172
    /**
173
     * @return string[]
174
     */
175 17
    public function getUnionLikes(): array
176
    {
177 17
        $parts = [];
178 17
        foreach ($this->unionLikes as $unionLike) {
179 4
            $unionType = $unionLike[0];
180 4
            $select    = $unionLike[1];
181 4
            $modifier  = '';
182 4
            if ($unionLike[2]) {
183
                $modifier = ' ' . $unionLike[2];
184
            }
185
186
            switch ($unionType) {
187 4
                case static::UNION:
188 3
                    $parts[] = 'UNION' . $modifier . PHP_EOL . $select;
189 3
                    break;
190 2
                case static::INTERSECT:
191 1
                    $parts[] = 'INTERSECT' . $modifier . PHP_EOL . $select;
192 1
                    break;
193 1
                case static::EXCEPT:
194 1
                    $parts[] = 'EXCEPT' . $modifier . PHP_EOL . $select;
195 1
                    break;
196
            }
197
        }
198
199 17
        return $parts;
200
    }
201
202
    /**
203
     * @return string[]
204
     */
205 1
    protected function getOuterOrderBy(): array
206
    {
207 1
        if (count($this->outerOrderByParts) === 0) {
208 1
            return [];
209
        }
210
211
        $parts = [];
212
        foreach ($this->outerOrderByParts as $column => $direction) {
213
            $parts[] = "$column $direction";
214
        }
215
216
        return ['ORDER BY ' . implode(', ', $parts)];
217
    }
218
219
    /**
220
     * @return string[]
221
     */
222 1
    protected function getOuterLimit(): array
223
    {
224 1
        $parts = [];
225 1
        if ($this->outerLimit !== null && $this->outerOffset !== null) {
226
            $parts[] = 'LIMIT ' . $this->outerOffset . ', ' . $this->outerLimit;
227 1
        } elseif ($this->outerLimit !== null) {
228 1
            $parts[] = 'LIMIT ' . $this->outerLimit;
229
        }
230
231 1
        return $parts;
232
    }
233
}
234