Passed
Push — master ( af4849...ba71ff )
by y
01:17
created

SQL::marks()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Helix\DB;
4
5
use Countable;
6
7
/**
8
 * Static helper for building SQL.
9
 *
10
 * The methods here are driver agnostic, and do not quote values.
11
 */
12
class SQL {
13
14
    /**
15
     * `(... AND ...)`
16
     *
17
     * @param string[] $conditions
18
     * @return string
19
     */
20
    public static function all (array $conditions): string {
21
        if (count($conditions) === 1) {
22
            return reset($conditions);
23
        }
24
        return '(' . implode(' AND ', $conditions) . ')';
25
    }
26
27
    /**
28
     * `(... OR ...)`
29
     *
30
     * @param string[] $conditions
31
     * @return string
32
     */
33
    public static function any (array $conditions): string {
34
        if (count($conditions) === 1) {
35
            return reset($conditions);
36
        }
37
        return '(' . implode(' OR ', $conditions) . ')';
38
    }
39
40
    /**
41
     * Used to generate a comparison.
42
     *
43
     * `"$a $operator $b"`
44
     *
45
     * If `$a` is an array, the keys and values are used for `$a` and `$b`.
46
     *
47
     * `["$k $operator $v", ...]`
48
     *
49
     * If `$b` is an array, all items are listed within parenthesis.
50
     *
51
     * `"$a $listOperator (...$b)"`
52
     *
53
     * As well as if `$a` is a two-dimensional array.
54
     *
55
     * `["$k $listOperator (...$v)", ...]`
56
     *
57
     * If `$b` is a `{@link Select}, it's used as a subquery.
58
     *
59
     * `"$a $operator $subqueryOperator $b->toSubquery()"`
60
     *
61
     * As well as if `$a` is an array of {@link Select}.
62
     *
63
     * `["$k $operator $subqueryOperator $v->toSubquery()", ...]`
64
     *
65
     * @param mixed $a
66
     * @param string $operator
67
     * @param mixed $b
68
     * @param string $subqueryOperator
69
     * @param string $listOperator
70
     * @return string|array
71
     */
72
    public static function compare ($a, $operator, $b = null, $subqueryOperator = null, $listOperator = null) {
73
        if (is_array($a)) {
74
            $cmp = [];
75
            foreach ($a as $k => $v) {
76
                $cmp[$k] = static::compare($k, $operator, $v, $subqueryOperator, $listOperator);
77
            }
78
            return $cmp;
79
        }
80
        elseif (is_array($b)) {
81
            return "{$a} {$listOperator} (" . implode(',', $b) . ")";
82
        }
83
        elseif ($b instanceof Select) {
84
            return "{$a} {$operator} {$subqueryOperator} ({$b->toSql()})";
85
        }
86
        return "{$a} {$operator} {$b}";
87
    }
88
89
    /**
90
     * `$a = $b`, or `$a IN (...$b)`, or `$a = ANY ($b)`
91
     *
92
     * @param string|array $a
93
     * @param string|array|Select $b
94
     * @return string|array
95
     */
96
    public static function isEqual ($a, $b = null) {
97
        return static::compare($a, '=', $b, 'ANY', 'IN');
98
    }
99
100
    /**
101
     * `$a > $b`, or `$a > ALL ($b)`
102
     *
103
     * @param string|array $a
104
     * @param string|Select $b
105
     * @return string|array
106
     */
107
    public static function isGreater ($a, $b = null) {
108
        return static::compare($a, '>', $b, 'ALL');
109
    }
110
111
    /**
112
     * `$a >= $b`, or `$a >= ALL ($b)`
113
     *
114
     * @param string|array $a
115
     * @param string|Select $b
116
     * @return string|array
117
     */
118
    public static function isGreaterOrEqual ($a, $b = null) {
119
        return static::compare($a, '>=', $b, 'ALL');
120
    }
121
122
    /**
123
     * `$a < $b`, or `$a < ALL ($b)`
124
     *
125
     * @param string|array $a
126
     * @param string|Select $b
127
     * @return string|array
128
     */
129
    public static function isLess ($a, $b = null) {
130
        return static::compare($a, '<', $b, 'ALL');
131
    }
132
133
    /**
134
     * `$a <= $b`, or `$a <= ALL ($b)`
135
     *
136
     * @param string|array $a
137
     * @param string|Select $b
138
     * @return string|array
139
     */
140
    public static function isLessOrEqual ($a, $b = null) {
141
        return static::compare($a, '<=', $b, 'ALL');
142
    }
143
144
    /**
145
     * `$x LIKE $pattern`
146
     *
147
     * @param string|array $x
148
     * @param string $pattern
149
     * @return string|array
150
     */
151
    public static function isLike ($x, string $pattern = null) {
152
        return static::compare($x, 'LIKE', $pattern);
153
    }
154
155
    /**
156
     * `$a IS NOT UNKNOWN|TRUE|FALSE`
157
     *
158
     * @param string|array $x
159
     * @param null|bool $identity
160
     * @return string|array
161
     */
162
    public static function isNot ($x, $identity) {
163
        return static::compare($x, 'IS NOT', ['' => 'UNKNOWN', 1 => 'TRUE', 0 => 'FALSE'][$identity]);
164
    }
165
166
    /**
167
     * `$a <> $b`, or `$a NOT IN (...$b)`, or `$a <> ALL ($b)`
168
     *
169
     * @param string|array $a
170
     * @param string|array|Select $b
171
     * @return string|array
172
     */
173
    public static function isNotEqual ($a, $b = null) {
174
        return static::compare($a, '<>', $b, 'ALL', 'NOT IN');
175
    }
176
177
    /**
178
     * `$a NOT LIKE $pattern`
179
     *
180
     * @param string|array $x
181
     * @param string $pattern
182
     * @return string|array
183
     */
184
    public static function isNotLike ($x, string $pattern = null) {
185
        return static::compare($x, 'NOT LIKE', $pattern);
186
    }
187
188
    /**
189
     * `$x IS NOT NULL`
190
     *
191
     * @param string|array $x
192
     * @return string|array
193
     */
194
    public static function isNotNull ($x) {
195
        if (is_array($x)) {
196
            return array_map(__METHOD__, $x);
197
        }
198
        return "{$x} IS NOT NULL";
199
    }
200
201
    /**
202
     * `$x NOT REGEXP $pattern`
203
     *
204
     * @param string|array $x
205
     * @param string $pattern
206
     * @return string|array
207
     */
208
    public static function isNotRegExp ($x, string $pattern = null) {
209
        return static::compare($x, 'NOT REGEXP', $pattern);
210
    }
211
212
    /**
213
     * `$x REGEXP $pattern`
214
     *
215
     * @param string|array $x
216
     * @param string $pattern
217
     * @return string|array
218
     */
219
    public static function isRegExp ($x, string $pattern = null) {
220
        return static::compare($x, 'REGEXP', $pattern);
221
    }
222
223
    /**
224
     * Returns an array of `?` placeholders.
225
     *
226
     * @param int|array|Countable $count
227
     * @return string[]
228
     */
229
    public static function marks ($count): array {
230
        if (is_array($count) or $count instanceof Countable) {
231
            $count = count($count);
232
        }
233
        return array_fill(0, $count, '?');
234
    }
235
236
    /**
237
     * `NOT($x)`
238
     *
239
     * @param string|array $x
240
     * @return string|array
241
     */
242
    public static function not ($x) {
243
        if (is_array($x)) {
244
            return array_map(__METHOD__, $x);
245
        }
246
        return "NOT({$x})";
247
    }
248
249
    /**
250
     * Converts an array of columns to `:named` placeholders for prepared queries.
251
     *
252
     * Qualified columns are slotted as `qualifier__column` (two underscores).
253
     *
254
     * @param string[] $columns
255
     * @return string[] `[column => :column]`
256
     */
257
    public static function slots (array $columns): array {
258
        $slots = [];
259
        foreach ($columns as $column) {
260
            $slots[(string)$column] = ':' . str_replace('.', '__', $column);
261
        }
262
        return $slots;
263
    }
264
265
    final private function __construct () { }
266
267
}