Passed
Push — develop ( a3aa5d...84fa8b )
by nguereza
06:38
created

QueryStatement::getDistinct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * Platine Database
5
 *
6
 * Platine Database is the abstraction layer using PDO with support of query and schema builder
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine Database
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a copy
13
 * of this software and associated documentation files (the "Software"), to deal
14
 * in the Software without restriction, including without limitation the rights
15
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 * copies of the Software, and to permit persons to whom the Software is
17
 * furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in all
20
 * copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
 * SOFTWARE.
29
 */
30
31
/**
32
 *  @file QueryStatement.php
33
 *
34
 *  The Base class for SQL query statement
35
 *
36
 *  @package    Platine\Database\Query
37
 *  @author Platine Developers Team
38
 *  @copyright  Copyright (c) 2020
39
 *  @license    http://opensource.org/licenses/MIT  MIT License
40
 *  @link   http://www.iacademy.cf
41
 *  @version 1.0.0
42
 *  @filesource
43
 */
44
45
declare(strict_types=1);
46
47
namespace Platine\Database\Query;
48
49
use Closure;
50
51
/**
52
 * Class QueryStatement
53
 *
54
 * @package Platine\Database\Query
55
 */
56
class QueryStatement
57
{
58
59
    /**
60
     * The where SQL parts
61
     * @var array<int, mixed>
62
     */
63
    protected array $wheres = [];
64
65
    /**
66
     * The having SQL parts
67
     * @var array<int, mixed>
68
     */
69
    protected array $having = [];
70
71
    /**
72
     * The join SQL parts
73
     * @var array<int, mixed>
74
     */
75
    protected array $joins = [];
76
77
    /**
78
     * The table SQL parts
79
     * @var array<int, mixed>
80
     */
81
    protected array $tables = [];
82
83
    /**
84
     * The columns SQL parts
85
     * @var array<int, mixed>
86
     */
87
    protected array $columns = [];
88
89
    /**
90
     * The order SQL parts
91
     * @var array<int, mixed>
92
     */
93
    protected array $order = [];
94
95
    /**
96
     * The group SQL parts
97
     * @var string[]|Expression[]
98
     */
99
    protected array $group = [];
100
101
    /**
102
     * The from SQL parts
103
     * @var array<int, string>
104
     */
105
    protected array $from = [];
106
107
    /**
108
     * The query placeholders values
109
     * @var array<int, mixed>
110
     */
111
    protected array $values = [];
112
113
    /**
114
     * Whether need use distinct
115
     * @var bool
116
     */
117
    protected bool $distinct = false;
118
119
    /**
120
     * The limit value
121
     * @var int
122
     */
123
    protected int $limit = 0;
124
125
    /**
126
     * The offset value
127
     * @var int
128
     */
129
    protected int $offset = -1;
130
131
    /**
132
     * The insert table
133
     * @var string|null
134
     */
135
    protected ?string $intoTable = null;
136
137
    /**
138
     * @param Closure $callback
139
     * @param string $separator
140
     */
141
    public function addWhereGroup(Closure $callback, string $separator): void
142
    {
143
        $where = new WhereStatement();
144
        $callback($where);
145
146
        $this->wheres[] = [
147
            'type' => 'whereNested',
148
            'clause' => $where->getQueryStatement()->getWheres(),
149
            'separator' => $separator
150
        ];
151
    }
152
153
    /**
154
     * @param string|Closure|Expression $column
155
     * @param mixed $value
156
     * @param string $operator
157
     * @param string $separator
158
     */
159
    public function addWhere($column, $value, string $operator, string $separator): void
160
    {
161
        $this->wheres[] = [
162
            'type' => 'whereColumn',
163
            'column' => $this->closureToExpression($column),
164
            'value' => $this->closureToExpression($value),
165
            'operator' => $operator,
166
            'separator' => $separator
167
        ];
168
    }
169
170
    /**
171
     * @param string|Closure|Expression $column
172
     * @param string $pattern
173
     * @param string $separator
174
     * @param bool $not
175
     */
176
    public function addWhereLike($column, string $pattern, string $separator, bool $not): void
177
    {
178
        $this->wheres[] = [
179
            'type' => 'whereLike',
180
            'column' => $this->closureToExpression($column),
181
            'pattern' => $pattern,
182
            'separator' => $separator,
183
            'not' => $not
184
        ];
185
    }
186
187
    /**
188
     * @param string|Closure|Expression $column
189
     * @param mixed $value1
190
     * @param mixed $value2
191
     * @param string $separator
192
     * @param bool $not
193
     */
194
    public function addWhereBetween($column, $value1, $value2, string $separator, bool $not): void
195
    {
196
        $this->wheres[] = [
197
            'type' => 'whereBetween',
198
            'column' => $this->closureToExpression($column),
199
            'value1' => $this->closureToExpression($value1),
200
            'value2' => $this->closureToExpression($value2),
201
            'separator' => $separator,
202
            'not' => $not
203
        ];
204
    }
205
206
    /**
207
     * @param string|Closure|Expression $column
208
     * @param mixed $value
209
     * @param string $separator
210
     * @param bool $not
211
     */
212
    public function addWhereIn($column, $value, string $separator, bool $not): void
213
    {
214
        $column = $this->closureToExpression($column);
215
216
        if ($value instanceof Closure) {
217
            $select = new SubQuery();
218
            $value($select);
219
220
            $this->wheres[] = [
221
                'type' => 'whereInSelect',
222
                'column' => $column,
223
                'subquery' => $select,
224
                'separator' => $separator,
225
                'not' => $not
226
            ];
227
        } else {
228
            $this->wheres[] = [
229
                'type' => 'whereIn',
230
                'column' => $column,
231
                'value' => $value,
232
                'separator' => $separator,
233
                'not' => $not
234
            ];
235
        }
236
    }
237
238
    /**
239
     * @param string|Closure|Expression $column
240
     * @param string $separator
241
     * @param bool $not
242
     */
243
    public function addWhereNull($column, string $separator, bool $not): void
244
    {
245
        $this->wheres[] = [
246
            'type' => 'whereNull',
247
            'column' => $this->closureToExpression($column),
248
            'separator' => $separator,
249
            'not' => $not
250
        ];
251
    }
252
253
    /**
254
     * @param string|Closure|Expression $column
255
     * @param string $separator
256
     */
257
    public function addWhereNop($column, string $separator): void
258
    {
259
        $this->wheres[] = [
260
            'type' => 'whereNop',
261
            'column' => $column,
262
            'separator' => $separator
263
        ];
264
    }
265
266
    /**
267
     * @param Closure $closure
268
     * @param string $separator
269
     * @param bool $not
270
     */
271
    public function addWhereExists(Closure $closure, string $separator, bool $not): void
272
    {
273
        $select = new SubQuery();
274
        $closure($select);
275
276
        $this->wheres[] = [
277
            'type' => 'whereExists',
278
            'subquery' => $select,
279
            'separator' => $separator,
280
            'not' => $not
281
        ];
282
    }
283
284
    /**
285
     * @param string $type
286
     * @param string|array<int, string>|Closure $table
287
     * @param Closure|null $closure
288
     */
289
    public function addJoinClause(string $type, $table, Closure $closure = null): void
290
    {
291
        $join = null;
292
        if ($closure !== null) {
293
            $join = new Join();
294
            $closure($join);
295
        }
296
297
        if ($table instanceof Closure) {
298
            $table = Expression::fromClosure($table);
299
        }
300
301
        if (!is_array($table)) {
302
            $table = [$table];
303
        }
304
305
        $this->joins[] = [
306
            'type' => $type,
307
            'table' => $table,
308
            'join' => $join
309
        ];
310
    }
311
312
    /**
313
     * @param Closure $closure
314
     * @param string $separator
315
     */
316
    public function addHavingGroup(Closure $closure, string $separator): void
317
    {
318
        $having = new HavingStatement();
319
        $closure($having);
320
321
        $this->having[] = [
322
            'type' => 'havingNested',
323
            'conditions' => $having->getQueryStatement()->getHaving(),
324
            'separator' => $separator
325
        ];
326
    }
327
328
    /**
329
     * @param string|Closure|Expression $aggregate
330
     * @param mixed $value
331
     * @param string $operator
332
     * @param string $separator
333
     */
334
    public function addHaving($aggregate, $value, string $operator, string $separator): void
335
    {
336
        $this->having[] = [
337
            'type' => 'havingCondition',
338
            'aggregate' => $this->closureToExpression($aggregate),
339
            'value' => $this->closureToExpression($value),
340
            'operator' => $operator,
341
            'separator' => $separator
342
        ];
343
    }
344
345
    /**
346
     * @param string|Closure|Expression $aggregate
347
     * @param mixed $value
348
     * @param string $separator
349
     * @param bool $not
350
     * @return mixed
351
     */
352
    public function addHavingIn($aggregate, $value, string $separator, bool $not)
353
    {
354
        $aggregate = $this->closureToExpression($aggregate);
355
356
        if ($value instanceof Closure) {
357
            $select = new SubQuery();
358
            $value($select);
359
360
            $this->having[] = [
361
                'type' => 'havingInSelect',
362
                'aggregate' => $aggregate,
363
                'subquery' => $select,
364
                'separator' => $separator,
365
                'not' => $not
366
            ];
367
        } else {
368
            $this->having[] = [
369
                'type' => 'havingIn',
370
                'aggregate' => $aggregate,
371
                'value' => $value,
372
                'separator' => $separator,
373
                'not' => $not
374
            ];
375
        }
376
    }
377
378
    /**
379
     * @param string|Closure|Expression $aggregate
380
     * @param mixed $value1
381
     * @param mixed $value2
382
     * @param string $separator
383
     * @param bool $not
384
     */
385
    public function addHavingBetween($aggregate, $value1, $value2, string $separator, bool $not): void
386
    {
387
        $this->having[] = [
388
            'type' => 'havingBetween',
389
            'aggregate' => $this->closureToExpression($aggregate),
390
            'value1' => $this->closureToExpression($value1),
391
            'value2' => $this->closureToExpression($value2),
392
            'separator' => $separator,
393
            'not' => $not
394
        ];
395
    }
396
397
    /**
398
     * @param array<int, string> $tables
399
     */
400
    public function addTables(array $tables): void
401
    {
402
        $this->tables = $tables;
403
    }
404
405
    /**
406
     * @param array<int|string, mixed> $columns
407
     */
408
    public function addUpdateColumns(array $columns): void
409
    {
410
        foreach ($columns as $column => $value) {
411
            $this->columns[] = [
412
                'column' => $column,
413
                'value' => $this->closureToExpression($value)
414
            ];
415
        }
416
    }
417
418
    /**
419
     * @param string[]|Expression[]|Closure[] $columns
420
     * @param string $order
421
     */
422
    public function addOrder(array $columns, string $order): void
423
    {
424
        foreach ($columns as &$column) {
425
            $column = $this->closureToExpression($column);
426
        }
427
        $order = strtoupper($order);
428
429
        if ($order !== 'ASC' && $order !== 'DESC') {
430
            $order = 'ASC';
431
        }
432
433
        $this->order[] = [
434
            'columns' => $columns,
435
            'order' => $order
436
        ];
437
    }
438
439
    /**
440
     * @param string[]|Expression[]|Closure[] $columns
441
     */
442
    public function addGroupBy(array $columns): void
443
    {
444
        $cols = [];
445
        foreach ($columns as &$column) {
446
            $cols[] = $this->closureToExpression($column);
447
        }
448
449
        $this->group = $cols;
450
    }
451
452
    /**
453
     * @param string|Expression|Closure $column
454
     * @param string|null $alias
455
     */
456
    public function addColumn($column, ?string $alias = null): void
457
    {
458
        $this->columns[] = [
459
            'name' => $this->closureToExpression($column),
460
            'alias' => $alias
461
        ];
462
    }
463
464
    /**
465
     * @param bool $value
466
     */
467
    public function setDistinct(bool $value): void
468
    {
469
        $this->distinct = $value;
470
    }
471
472
    /**
473
     * @param int $value
474
     */
475
    public function setLimit(int $value): void
476
    {
477
        $this->limit = $value;
478
    }
479
480
    /**
481
     * @param int $value
482
     */
483
    public function setOffset(int $value): void
484
    {
485
        $this->offset = $value;
486
    }
487
488
    /**
489
     * @param string $table
490
     */
491
    public function setInto(string $table): void
492
    {
493
        $this->intoTable = $table;
494
    }
495
496
    /**
497
     * @param array<int, string> $from
498
     */
499
    public function setFrom(array $from): void
500
    {
501
        $this->from = $from;
502
    }
503
504
    /**
505
     * @param mixed $value
506
     */
507
    public function addValue($value): void
508
    {
509
        $this->values[] = $this->closureToExpression($value);
510
    }
511
512
    /**
513
     * @return array<int, mixed>
514
     */
515
    public function getWheres(): array
516
    {
517
        return $this->wheres;
518
    }
519
520
    /**
521
     * @return array<int, mixed>
522
     */
523
    public function getHaving(): array
524
    {
525
        return $this->having;
526
    }
527
528
    /**
529
     * @return array<int, mixed>
530
     */
531
    public function getJoins(): array
532
    {
533
        return $this->joins;
534
    }
535
536
    /**
537
     * @return bool
538
     */
539
    public function hasDistinct(): bool
540
    {
541
        return $this->distinct;
542
    }
543
544
    /**
545
     * @return array<int, string>
546
     */
547
    public function getTables(): array
548
    {
549
        return $this->tables;
550
    }
551
552
    /**
553
     * @return array<int, array<string, mixed>>
554
     */
555
    public function getColumns(): array
556
    {
557
        return $this->columns;
558
    }
559
560
    /**
561
     * @return array<int, array<string, mixed>>
562
     */
563
    public function getOrder(): array
564
    {
565
        return $this->order;
566
    }
567
568
    /**
569
     * @return string[]|Expression[]
570
     */
571
    public function getGroupBy(): array
572
    {
573
        return $this->group;
574
    }
575
576
    /**
577
     * @return int
578
     */
579
    public function getLimit(): int
580
    {
581
        return $this->limit;
582
    }
583
584
    /**
585
     * @return int
586
     */
587
    public function getOffset(): int
588
    {
589
        return $this->offset;
590
    }
591
592
    /**
593
     * @return string|null
594
     */
595
    public function getIntoTable(): ?string
596
    {
597
        return $this->intoTable;
598
    }
599
600
    /**
601
     * @return array<int, string>
602
     */
603
    public function getFrom(): array
604
    {
605
        return $this->from;
606
    }
607
608
    /**
609
     * @return array<int, mixed>
610
     */
611
    public function getValues(): array
612
    {
613
        return $this->values;
614
    }
615
616
    /**
617
     * @param mixed $value
618
     *
619
     * @return mixed|Expression
620
     */
621
    protected function closureToExpression($value)
622
    {
623
        if ($value instanceof Closure) {
624
            return Expression::fromClosure($value);
625
        }
626
627
        return $value;
628
    }
629
}
630