PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.0.13
Kirki – Freeform Page Builder, Website Builder & Customizer v6.0.13
6.1.1 6.1.0 6.0.14 6.0.13 6.0.12 6.0.11 6.0.10 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.19 4.0.20 4.0.21 4.0.22 4.0.23 4.0.24 4.1 4.2.0 5.0.0 5.1.0 5.1.1 5.2.0 5.2.1 5.2.2 5.2.3 6.0.0 trunk 3.0.40 3.0.41 3.0.42 3.0.43 3.0.44 3.0.45 3.1.0 3.1.1 3.1.2
kirki / libraries / framework / Database / Query / QueryCompiler.php
kirki / libraries / framework / Database / Query Last commit date
Relations 3 weeks ago Collection.php 3 weeks ago EagerLoader.php 3 weeks ago Expression.php 3 weeks ago JoinClause.php 3 weeks ago Model.php 3 weeks ago Paginator.php 3 weeks ago QueryBuilder.php 3 weeks ago QueryCompiler.php 3 weeks ago
QueryCompiler.php
1146 lines
1 <?php
2
3 /**
4 * Translates a QueryBuilder state array into parameterized SQL strings.
5 * Compiles selects, joins, wheres, aggregates, and pagination clauses for the WordPress database layer.
6 * The SQL generation engine behind the fluent query builder.
7 *
8 * @package Framework
9 * @subpackage Database\Query
10 * @since 1.0.0
11 */
12 namespace Kirki\Framework\Database\Query;
13
14 \defined('ABSPATH') || exit;
15 use Kirki\Framework\Collections\Collection;
16 use Kirki\Framework\Database\Connection\Connection;
17 use Kirki\Framework\Supports\Arr;
18 use function Kirki\Framework\collection;
19 use function Kirki\Framework\Polyfill\array_first;
20 use function Kirki\Framework\Polyfill\array_last;
21 class QueryCompiler
22 {
23 /**
24 * The database connection instance used to execute queries.
25 *
26 * @var \Framework\Database\Connection\Connection
27 *
28 * @since 1.0.0
29 */
30 protected $connection;
31 /**
32 * Initialize a new QueryCompiler instance with a database connection.
33 *
34 * @param Connection $connection The database connection instance.
35 *
36 * @return void
37 *
38 * @since 1.0.0
39 */
40 public function __construct(Connection $connection)
41 {
42 $this->connection = $connection;
43 }
44 /**
45 * The components of the query to compile.
46 *
47 * @var array
48 *
49 * @since 1.0.0
50 */
51 protected $components = ['aggregate', 'columns', 'from', 'joins', 'wheres', 'groups', 'havings', 'orders', 'limit', 'offset'];
52 /**
53 * Get the mysql safe datetime format string.
54 *
55 * @return string
56 *
57 * @since 1.0.0
58 */
59 public function get_date_format()
60 {
61 return 'Y-m-d H:i:s';
62 }
63 /**
64 * Compile the insert query.
65 *
66 * @param QueryBuilder $query The query builder instance.
67 * @param array $values The values to insert.
68 *
69 * @return string The compiled insert query.
70 *
71 * @since 1.0.0
72 */
73 public function compile_insert(QueryBuilder $query, array $values)
74 {
75 $table = $this->wrap_table($query->from);
76 if (empty($values)) {
77 return \sprintf('insert into %s default values', $table);
78 }
79 if (!\is_array(array_first($values))) {
80 $values = [$values];
81 }
82 $columns = $this->columnize(\array_keys(array_first($values)));
83 $parameters = collection($values)->map(function ($record) {
84 return \sprintf('(%s)', $this->parameterize($record));
85 })->join(', ');
86 return \sprintf('insert into %s (%s) values %s', $table, $columns, $parameters);
87 }
88 /**
89 * Compile the update query.
90 *
91 * @param QueryBuilder $query The query builder instance.
92 * @param array $values The values to update.
93 *
94 * @return string The compiled update query.
95 *
96 * @since 1.0.0
97 */
98 public function compile_update(QueryBuilder $query, array $values)
99 {
100 $table = $this->wrap_table($query->from);
101 $columns = $this->compile_update_columns($query, $values);
102 $where = $this->compile_wheres($query);
103 return \trim(isset($query->joins) ? $this->compile_update_with_joins($query, $table, $columns, $where) : $this->compile_update_without_joins($query, $table, $columns, $where));
104 }
105 /**
106 * Compile the update columns query.
107 *
108 * @param QueryBuilder $query The query builder instance.
109 * @param array $values The values to update.
110 *
111 * @return string The compiled update columns query.
112 *
113 * @since 1.0.0
114 */
115 protected function compile_update_columns(QueryBuilder $query, array $values)
116 {
117 return collection($values)->map(function ($value, $key) {
118 return $this->wrap($key) . ' = ' . $this->parameter($value);
119 })->join(', ');
120 }
121 /**
122 * Compile the update with joins query.
123 *
124 * @param QueryBuilder $query The query builder instance.
125 * @param string $table The table name.
126 * @param string $columns The columns to update.
127 * @param string $where The where clause.
128 *
129 * @return string The compiled update with joins query.
130 *
131 * @since 1.0.0
132 */
133 protected function compile_update_with_joins(QueryBuilder $query, $table, $columns, $where)
134 {
135 $joins = $this->compile_joins($query, $query->joins);
136 return \sprintf('update %s %s set %s %s', $table, $joins, $columns, $where);
137 }
138 /**
139 * Compile the update without joins query.
140 *
141 * @param QueryBuilder $query The query builder instance.
142 * @param string $table The table name.
143 * @param string $columns The columns to update.
144 * @param string $where The where clause.
145 *
146 * @return string The compiled update without joins query.
147 *
148 * @since 1.0.0
149 */
150 protected function compile_update_without_joins(QueryBuilder $query, $table, $columns, $where)
151 {
152 $sql = \sprintf('update %s set %s %s', $table, $columns, $where);
153 if (!empty($query->orders)) {
154 $sql .= ' ' . $this->compile_orders($query, $query->orders);
155 }
156 if (!empty($query->limit)) {
157 $sql .= ' ' . $this->compile_limit($query, $query->limit);
158 }
159 return $sql;
160 }
161 /**
162 * Compile the delete query.
163 *
164 * @param QueryBuilder $query The query builder instance.
165 *
166 * @return string The compiled delete query.
167 *
168 * @since 1.0.0
169 */
170 public function compile_delete(QueryBuilder $query)
171 {
172 $table = $this->wrap_table($query->from);
173 $where = $this->compile_wheres($query);
174 return \trim(isset($query->joins) ? $this->compile_delete_with_joins($query, $table, $where) : $this->compile_delete_without_joins($query, $table, $where));
175 }
176 /**
177 * Compile the delete with joins query.
178 *
179 * @param QueryBuilder $query The query builder instance.
180 * @param string $table The table name.
181 * @param string $where The where clause.
182 *
183 * @return string The compiled delete with joins query.
184 *
185 * @since 1.0.0
186 */
187 protected function compile_delete_with_joins(QueryBuilder $query, $table, $where)
188 {
189 $parts = \explode(' as ', $table);
190 $alias = array_last($parts);
191 $joins = $this->compile_joins($query, $query->joins);
192 return \sprintf('delete %s from %s %s %s', $alias, $table, $joins, $where);
193 }
194 /**
195 * Compile the delete without joins query.
196 *
197 * @param QueryBuilder $query The query builder instance.
198 * @param string $table The table name.
199 * @param string $where The where clause.
200 *
201 * @return string The compiled delete without joins query.
202 *
203 * @since 1.0.0
204 */
205 protected function compile_delete_without_joins(QueryBuilder $query, $table, $where)
206 {
207 return \sprintf('delete from %s %s', $table, $where);
208 }
209 /**
210 * Compile the select query.
211 *
212 * @param QueryBuilder $query The query builder instance.
213 *
214 * @return string The compiled select query.
215 *
216 * @since 1.0.0
217 */
218 public function compile_select(QueryBuilder $query)
219 {
220 $original = $query->columns;
221 if (\is_null($query->columns)) {
222 $query->columns = ['*'];
223 }
224 $sql = \trim($this->concatenate($this->compile_components($query)));
225 $query->columns = $original;
226 return $sql;
227 }
228 /**
229 * Compile the components of the query.
230 *
231 * @param QueryBuilder $query The query builder instance.
232 *
233 * @return array The compiled components.
234 *
235 * @since 1.0.0
236 */
237 protected function compile_components(QueryBuilder $query)
238 {
239 $sql = [];
240 foreach ($this->components as $component) {
241 if (isset($query->{$component})) {
242 $method = 'compile_' . $component;
243 $sql[$component] = $this->{$method}($query, $query->{$component});
244 }
245 }
246 return $sql;
247 }
248 /**
249 * Concatenate the segments.
250 *
251 * @param array $segments The segments to concatenate.
252 *
253 * @return string The concatenated segments.
254 *
255 * @since 1.0.0
256 */
257 protected function concatenate($segments)
258 {
259 return \implode(' ', \array_filter($segments, function ($value) {
260 return (string) $value !== '';
261 }));
262 }
263 /**
264 * Compile the aggregate query.
265 *
266 * @param QueryBuilder $query The query builder instance.
267 * @param array $aggregate The aggregate query.
268 *
269 * @return string The compiled aggregate query.
270 *
271 * @since 1.0.0
272 */
273 protected function compile_aggregate(QueryBuilder $query, $aggregate)
274 {
275 $column = $this->columnize($aggregate['columns']);
276 if (\is_array($query->distinct)) {
277 $column = 'distinct ' . $this->columnize($query->distinct);
278 } elseif ($query->distinct && $column !== '*') {
279 $column = 'distinct ' . $column;
280 }
281 return \sprintf('select %s(%s) as aggregate', $aggregate['function'], $column);
282 }
283 /**
284 * Compile the columns query.
285 *
286 * @param QueryBuilder $query The query builder instance.
287 * @param array $columns The columns query.
288 *
289 * @return string|null The compiled columns query.
290 *
291 * @since 1.0.0
292 */
293 protected function compile_columns(QueryBuilder $query, $columns)
294 {
295 if (!\is_null($query->aggregate)) {
296 return;
297 }
298 $select = '';
299 if ($query->distinct) {
300 $select = 'select distinct ';
301 } else {
302 $select = 'select ';
303 }
304 return $select . $this->columnize($columns);
305 }
306 /**
307 * Compile the from query.
308 *
309 * @param QueryBuilder $query The query builder instance.
310 * @param array $table The table query.
311 *
312 * @return string The compiled from query.
313 *
314 * @since 1.0.0
315 */
316 protected function compile_from(QueryBuilder $query, $table)
317 {
318 return 'from ' . $this->wrap_table($table);
319 }
320 /**
321 * Compile the joins query.
322 *
323 * @param QueryBuilder $query The query builder instance.
324 * @param array $joins The joins query.
325 *
326 * @return string The compiled joins query.
327 *
328 * @since 1.0.0
329 */
330 protected function compile_joins(QueryBuilder $query, $joins)
331 {
332 return collection($joins)->map(function ($join) use($query) {
333 $table = $this->wrap_table($join->table);
334 $nested_joins = \is_null($join->joins) ? '' : ' ' . $this->compile_joins($query, $join->joins);
335 $table_and_nested_joins = \is_null($join->joins) ? $table : \sprintf('(%s%s)', $table, $nested_joins);
336 return \trim(\sprintf('%s join %s %s', $join->type, $table_and_nested_joins, $this->compile_wheres($join)));
337 })->join(' ');
338 }
339 /**
340 * Compile the wheres query.
341 *
342 * @param QueryBuilder $query The query builder instance.
343 *
344 * @return string The compiled wheres query.
345 *
346 * @since 1.0.0
347 */
348 protected function compile_wheres(QueryBuilder $query)
349 {
350 if (\is_null($query->wheres)) {
351 return '';
352 }
353 $sql = $this->compile_wheres_to_array($query);
354 if (\count($sql) > 0) {
355 return $this->concatenate_where_clauses($query, $sql);
356 }
357 return '';
358 }
359 /**
360 * Compile the wheres to array query.
361 *
362 * @param QueryBuilder $query The query builder instance.
363 *
364 * @return array The compiled wheres to array query.
365 *
366 * @since 1.0.0
367 */
368 protected function compile_wheres_to_array(QueryBuilder $query)
369 {
370 return \array_map(function ($where) use($query) {
371 $boolean = $where['boolean'];
372 $method = 'where_' . $where['type'];
373 return \sprintf('%s %s', $boolean, $this->{$method}($query, $where));
374 }, $query->wheres);
375 }
376 /**
377 * Concatenate the where clauses.
378 *
379 * @param QueryBuilder $query The query builder instance.
380 * @param array $sql The where clauses.
381 *
382 * @return string The concatenated where clauses.
383 *
384 * @since 1.0.0
385 */
386 protected function concatenate_where_clauses($query, $sql)
387 {
388 $conjunction = $query instanceof JoinClause ? 'on' : 'where';
389 return \sprintf('%s %s', $conjunction, $this->remove_leading_boolean(\implode(' ', $sql)));
390 }
391 /**
392 * Remove the leading boolean.
393 *
394 * @param string $value The value to remove the leading boolean from.
395 *
396 * @return string The value with the leading boolean removed.
397 *
398 * @since 1.0.0
399 */
400 protected function remove_leading_boolean($value)
401 {
402 return \preg_replace('/and |or /i', '', $value, 1);
403 }
404 /**
405 * Compile the groups query.
406 *
407 * @param QueryBuilder $query The query builder instance.
408 * @param array $groups The groups query.
409 *
410 * @return string The compiled groups query.
411 *
412 * @since 1.0.0
413 */
414 protected function compile_groups(QueryBuilder $query, $groups)
415 {
416 return 'group by ' . $this->columnize($groups);
417 }
418 /**
419 * Compile the havings query.
420 *
421 * @param QueryBuilder $query The query builder instance.
422 *
423 * @return string The compiled havings query.
424 *
425 * @since 1.0.0
426 */
427 protected function compile_havings(QueryBuilder $query)
428 {
429 $sql = $this->remove_leading_boolean(collection($query->havings)->map(function ($having) {
430 return $having['boolean'] . ' ' . $this->compile_having($having);
431 })->join(' '));
432 return 'having ' . $sql;
433 }
434 /**
435 * Compile the having query.
436 *
437 * @param array $having The having query.
438 *
439 * @return string The compiled having query.
440 *
441 * @since 1.0.0
442 */
443 protected function compile_having($having)
444 {
445 switch ($having['type']) {
446 case 'raw':
447 return $having['sql'];
448 case 'between':
449 return $this->compile_having_between($having);
450 case 'null':
451 return $this->compile_having_null($having);
452 case 'not_null':
453 return $this->compile_having_not_null($having);
454 case 'expression':
455 return $this->compile_having_expression($having);
456 case 'nested':
457 return $this->compile_nested_havings($having);
458 default:
459 return $this->compile_having_basic($having);
460 }
461 }
462 /**
463 * Compile the having basic query.
464 *
465 * @param array $having The having query.
466 *
467 * @return string The compiled having basic query.
468 *
469 * @since 1.0.0
470 */
471 protected function compile_having_basic($having)
472 {
473 return \sprintf('%s %s %s', $this->wrap($having['column']), $having['operator'], $this->parameter($having['value']));
474 }
475 /**
476 * Compile the nested havings query.
477 *
478 * @param array $having The having query.
479 *
480 * @return string The compiled nested havings query.
481 *
482 * @since 1.0.0
483 */
484 protected function compile_nested_havings($having)
485 {
486 return \sprintf('(%s)', \substr($this->compile_havings($having['query']), 7));
487 }
488 /**
489 * Compile the having between query.
490 *
491 * @param array $having The having query.
492 *
493 * @return string The compiled having between query.
494 *
495 * @since 1.0.0
496 */
497 protected function compile_having_between($having)
498 {
499 $between = $having['not'] ? 'not between' : 'between';
500 $min = $this->parameter($having['values'][0]);
501 $max = $this->parameter($having['values'][1]);
502 return \sprintf('%s %s %s and %s', $this->wrap($having['column']), $between, $min, $max);
503 }
504 /**
505 * Compile the having null query.
506 *
507 * @param array $having The having query.
508 *
509 * @return string The compiled having null query.
510 *
511 * @since 1.0.0
512 */
513 protected function compile_having_null($having)
514 {
515 return $this->wrap($having['column']) . ' is null';
516 }
517 /**
518 * Compile the having not null query.
519 *
520 * @param array $having The having query.
521 *
522 * @return string The compiled having not null query.
523 *
524 * @since 1.0.0
525 */
526 protected function compile_having_not_null($having)
527 {
528 return $this->wrap($having['column']) . ' is not null';
529 }
530 /**
531 * Compile the having expression query.
532 *
533 * @param array $having The having query.
534 *
535 * @return string The compiled having expression query.
536 *
537 * @since 1.0.0
538 */
539 protected function compile_having_expression($having)
540 {
541 return $having['column']->get_value($this);
542 }
543 /**
544 * Compile the orders query.
545 *
546 * @param QueryBuilder $query The query builder instance.
547 * @param array|null $orders The orders query.
548 *
549 * @return string The compiled orders query.
550 *
551 * @since 1.0.0
552 */
553 protected function compile_orders(QueryBuilder $query, $orders)
554 {
555 if (empty($orders)) {
556 return '';
557 }
558 return 'order by ' . \implode(', ', $this->compile_orders_to_array($query, $orders));
559 }
560 /**
561 * Compile the orders to array query.
562 *
563 * @param QueryBuilder $query The query builder instance.
564 * @param array $orders The orders query.
565 *
566 * @return array The compiled orders to array query.
567 *
568 * @since 1.0.0
569 */
570 protected function compile_orders_to_array(QueryBuilder $query, $orders)
571 {
572 return \array_map(function ($order) {
573 return $order['sql'] ?? \sprintf('%s %s', $this->wrap($order['column']), $order['direction']);
574 }, $orders);
575 }
576 /**
577 * Compile the limit query.
578 *
579 * @param QueryBuilder $query The query builder instance.
580 * @param int $limit The limit query.
581 *
582 * @return string The compiled limit query.
583 *
584 * @since 1.0.0
585 */
586 protected function compile_limit(QueryBuilder $query, $limit)
587 {
588 return 'limit ' . (int) $limit;
589 }
590 /**
591 * Compile the offset query.
592 *
593 * @param QueryBuilder $query The query builder instance.
594 * @param array $offset The offset query.
595 *
596 * @return string The compiled offset query.
597 *
598 * @since 1.0.0
599 */
600 protected function compile_offset(QueryBuilder $query, $offset)
601 {
602 return 'offset ' . (int) $offset;
603 }
604 /**
605 * Compile the exists query.
606 *
607 * @param QueryBuilder $query The query builder instance.
608 *
609 * @return string The compiled exists query.
610 *
611 * @since 1.0.0
612 */
613 public function compile_exists(QueryBuilder $query)
614 {
615 $select = $this->compile_select($query);
616 return \sprintf('select exists(%s) as %s', $select, $this->wrap('exists'));
617 }
618 /**
619 * Compile the truncate query.
620 *
621 * @param QueryBuilder $query The query builder instance.
622 *
623 * @return string The compiled truncate query.
624 *
625 * @since 1.0.0
626 */
627 public function compile_truncate(QueryBuilder $query)
628 {
629 return \sprintf('truncate table %s', $this->wrap_table($query->from));
630 }
631 /**
632 * Compile the upsert query.
633 *
634 * @param QueryBuilder $query The query builder instance.
635 * @param array $values The values to upsert.
636 * @param array $update The columns to update.
637 *
638 * @return string The compiled upsert query.
639 *
640 * @since 1.0.0
641 */
642 public function compile_upsert(QueryBuilder $query, array $values, array $update)
643 {
644 $sql = $this->compile_insert($query, $values);
645 $sql .= ' on duplicate key update ';
646 $columns = (new Collection($update))->map(function ($value, $key) {
647 if (!\is_numeric($key)) {
648 return $this->wrap($key) . ' = ' . $this->parameter($value);
649 }
650 return $this->wrap($value) . ' = values(' . $this->wrap($value) . ')';
651 })->join(', ');
652 return $sql . $columns;
653 }
654 /**
655 * Compile the columnize query.
656 *
657 * @param array $columns The columns query.
658 *
659 * @return string The compiled columnize query.
660 *
661 * @since 1.0.0
662 */
663 public function columnize(array $columns)
664 {
665 return \implode(', ', \array_map([$this, 'wrap'], $columns));
666 }
667 /**
668 * Compile the wrap query.
669 *
670 * @param string|Expression $value The value query.
671 *
672 * @return string The compiled wrap query.
673 *
674 * @since 1.0.0
675 */
676 public function wrap($value)
677 {
678 if ($this->is_expression($value)) {
679 return $this->get_value($value);
680 }
681 if (\stripos($value, ' as ') !== \false) {
682 return $this->wrap_aliased_value($value);
683 }
684 return $this->wrap_segments(\explode('.', $value));
685 }
686 /**
687 * Compile the is expression query.
688 *
689 * @param array $value The value query.
690 *
691 * @return string The compiled is expression query.
692 *
693 * @since 1.0.0
694 */
695 public function is_expression($value)
696 {
697 return $value instanceof Expression;
698 }
699 /**
700 * Compile the get value query.
701 *
702 * @param string|Expression $expression The expression query.
703 *
704 * @return string The compiled get value query.
705 *
706 * @since 1.0.0
707 */
708 public function get_value($expression)
709 {
710 if ($this->is_expression($expression)) {
711 return $this->get_value($expression->get_value());
712 }
713 return $expression;
714 }
715 /**
716 * Compile the wrap value query.
717 *
718 * @param string $value The value query.
719 *
720 * @return string The compiled wrap value query.
721 *
722 * @since 1.0.0
723 */
724 public function wrap_value($value)
725 {
726 return $value === '*' ? $value : '`' . \str_replace('`', '``', $value) . '`';
727 }
728 /**
729 * Compile the wrap table query.
730 *
731 * @param string $table The table query.
732 * @param string|null $prefix The prefix to use for the table.
733 *
734 * @return string The compiled wrap table query.
735 *
736 * @since 1.0.0
737 */
738 public function wrap_table($table, $prefix = null)
739 {
740 if ($this->is_expression($table)) {
741 return $this->get_value($table);
742 }
743 $prefix ??= $this->connection->get_table_prefix();
744 if (\stripos($table, ' as ') !== \false) {
745 return $this->wrap_aliased_table($table, $prefix);
746 }
747 return $this->wrap_value($this->connection->get_table_prefix() . $table);
748 }
749 /**
750 * Compile the wrap segments query.
751 *
752 * @param array $segments The segments query.
753 *
754 * @return string The compiled wrap segments query.
755 *
756 * @since 1.0.0
757 */
758 protected function wrap_segments($segments)
759 {
760 return collection($segments)->map(function ($segment, $key) use($segments) {
761 return $key == 0 && \count($segments) > 1 ? $this->wrap_table($segment) : $this->wrap_value($segment);
762 })->join('.');
763 }
764 /**
765 * Compile the wrap aliased value query.
766 *
767 * @param string $value The value query.
768 *
769 * @return string The compiled wrap aliased value query.
770 *
771 * @since 1.0.0
772 */
773 protected function wrap_aliased_value($value)
774 {
775 $segments = \preg_split('/\\s+as\\s+/i', $value);
776 return $this->wrap($segments[0]) . ' as ' . $this->wrap_value($segments[1]);
777 }
778 /**
779 * Compile the wrap aliased table query.
780 *
781 * @param string $table The table query.
782 * @param mixed $prefix The prefix.
783 *
784 * @return string The compiled wrap aliased table query.
785 *
786 * @since 1.0.0
787 */
788 protected function wrap_aliased_table($table, $prefix = null)
789 {
790 $segments = \preg_split('/\\s+as\\s+/i', $table);
791 $prefix ??= $this->connection->get_table_prefix();
792 return \sprintf('%s as %s', $this->wrap_table($segments[0], $prefix), $this->wrap_value($prefix . $segments[1]));
793 }
794 /**
795 * Compile the parameter query.
796 *
797 * @param string|Expression $value The value query.
798 *
799 * @return string The compiled parameter query.
800 *
801 * @since 1.0.0
802 */
803 public function parameter($value)
804 {
805 return $this->is_expression($value) ? $this->get_value($value) : $this->connection->placeholder($value);
806 }
807 /**
808 * Compile the parameterize query.
809 *
810 * @param array $values The values query.
811 *
812 * @return string The compiled parameterize query.
813 *
814 * @since 1.0.0
815 */
816 protected function parameterize(array $values)
817 {
818 return \implode(', ', \array_map([$this, 'parameter'], $values));
819 }
820 /**
821 * Compile the where raw query.
822 *
823 * @param QueryBuilder $builder The query builder instance.
824 * @param array $where The where query.
825 *
826 * @return string The compiled where raw query.
827 *
828 * @since 1.0.0
829 */
830 protected function where_raw(QueryBuilder $builder, $where)
831 {
832 return $where['sql'] instanceof Expression ? $where['sql']->get_value($this) : $where['sql'];
833 }
834 /**
835 * Compile the where basic query.
836 *
837 * @param QueryBuilder $builder The query builder instance.
838 * @param array $where The where query.
839 *
840 * @return string The compiled where basic query.
841 *
842 * @since 1.0.0
843 */
844 protected function where_basic(QueryBuilder $builder, $where)
845 {
846 $value = $this->parameter($where['value']);
847 $operator = $where['operator'];
848 return \sprintf('%s %s %s', $this->wrap($where['column']), $operator, $value);
849 }
850 /**
851 * Compile the where like query.
852 *
853 * @param QueryBuilder $query The query builder instance.
854 * @param array $where The where query.
855 *
856 * @return string The compiled where like query.
857 *
858 * @since 1.0.0
859 */
860 protected function where_like(QueryBuilder $query, $where)
861 {
862 $where['operator'] = $where['not'] ? 'not like' : 'like';
863 return $this->where_basic($query, $where);
864 }
865 /**
866 * Compile the where in query.
867 *
868 * @param QueryBuilder $query The query builder instance.
869 * @param array $where The where query.
870 *
871 * @return string The compiled where in query.
872 *
873 * @since 1.0.0
874 */
875 protected function where_in(QueryBuilder $query, $where)
876 {
877 if (empty($where['values'])) {
878 return '0 = 1';
879 }
880 return \sprintf('%s in (%s)', $this->wrap($where['column']), $this->parameterize($where['values']));
881 }
882 /**
883 * Compile the where not in query.
884 *
885 * @param QueryBuilder $query The query builder instance.
886 * @param mixed $where The where.
887 *
888 * @return string The compiled where not in query.
889 *
890 * @since 1.0.0
891 */
892 protected function where_not_in(QueryBuilder $query, $where)
893 {
894 if (empty($where['values'])) {
895 return '1 = 1';
896 }
897 return \sprintf('%s not in (%s)', $this->wrap($where['column']), $this->parameterize($where['values']));
898 }
899 /**
900 * Compile the where in raw query.
901 *
902 * @param QueryBuilder $query The query builder instance.
903 * @param mixed $where The where.
904 *
905 * @return string The compiled where in raw query.
906 *
907 * @since 1.0.0
908 */
909 protected function where_in_raw(QueryBuilder $query, $where)
910 {
911 if (empty($where['values'])) {
912 return '0 = 1';
913 }
914 return \sprintf('%s in (%s)', $this->wrap($where['column']), \implode(', ', $where['values']));
915 }
916 /**
917 * Compile the where not in raw query.
918 *
919 * @param QueryBuilder $query The query builder instance.
920 * @param mixed $where The where.
921 *
922 * @return string The compiled where not in raw query.
923 *
924 * @since 1.0.0
925 */
926 protected function where_not_in_raw(QueryBuilder $query, $where)
927 {
928 if (empty($where['values'])) {
929 return '1 = 1';
930 }
931 return \sprintf('%s not in (%s)', $this->wrap($where['column']), \implode(', ', $where['values']));
932 }
933 /**
934 * Compile the where null query.
935 *
936 * @param QueryBuilder $query The query builder instance.
937 * @param mixed $where The where.
938 *
939 * @return string The compiled where null query.
940 *
941 * @since 1.0.0
942 */
943 protected function where_null(QueryBuilder $query, $where)
944 {
945 return $this->wrap($where['column']) . ' is null';
946 }
947 /**
948 * Compile the where not null query.
949 *
950 * @param QueryBuilder $query The query builder instance.
951 * @param mixed $where The where.
952 *
953 * @return string The compiled where not null query.
954 *
955 * @since 1.0.0
956 */
957 protected function where_not_null(QueryBuilder $query, $where)
958 {
959 return $this->wrap($where['column']) . ' is not null';
960 }
961 /**
962 * Compile the where between query.
963 *
964 * @param QueryBuilder $query The query builder instance.
965 * @param mixed $where The where.
966 *
967 * @return string The compiled where between query.
968 *
969 * @since 1.0.0
970 */
971 protected function where_between(QueryBuilder $query, $where)
972 {
973 $between = $where['not'] ? 'not between' : 'between';
974 $min = $this->parameter($where['values'][0]);
975 $max = $this->parameter($where['values'][1]);
976 return \sprintf('%s %s %s and %s', $this->wrap($where['column']), $between, $min, $max);
977 }
978 /**
979 * Compile the where date query.
980 *
981 * @param QueryBuilder $query The query builder instance.
982 * @param mixed $where The where.
983 *
984 * @return string The compiled where date query.
985 *
986 * @since 1.0.0
987 */
988 protected function where_date(QueryBuilder $query, $where)
989 {
990 return $this->date_based_where('date', $query, $where);
991 }
992 /**
993 * Compile the where time query.
994 *
995 * @param QueryBuilder $query The query builder instance.
996 * @param mixed $where The where.
997 *
998 * @return string The compiled where time query.
999 *
1000 * @since 1.0.0
1001 */
1002 protected function where_time(QueryBuilder $query, $where)
1003 {
1004 return $this->date_based_where('time', $query, $where);
1005 }
1006 /**
1007 * Compile the date based where query.
1008 *
1009 * @param mixed $type The type.
1010 * @param QueryBuilder $query The query builder instance.
1011 * @param mixed $where The where.
1012 *
1013 * @return string The compiled date based where query.
1014 *
1015 * @since 1.0.0
1016 */
1017 protected function date_based_where($type, QueryBuilder $query, $where)
1018 {
1019 $value = $this->parameter($where['value']);
1020 return \sprintf('%s (%s) %s %s', $type, $this->wrap($where['column']), $where['operator'], $value);
1021 }
1022 /**
1023 * Compile the where column query.
1024 *
1025 * @param QueryBuilder $query The query builder instance.
1026 * @param mixed $where The where.
1027 *
1028 * @return string The compiled where column query.
1029 *
1030 * @since 1.0.0
1031 */
1032 protected function where_column(QueryBuilder $query, $where)
1033 {
1034 return \sprintf('%s %s %s', $this->wrap($where['first']), $where['operator'], $this->wrap($where['second']));
1035 }
1036 /**
1037 * Compile the where nested query.
1038 *
1039 * @param QueryBuilder $query The query builder instance.
1040 * @param mixed $where The where.
1041 *
1042 * @return string The compiled where nested query.
1043 *
1044 * @since 1.0.0
1045 */
1046 protected function where_nested(QueryBuilder $query, $where)
1047 {
1048 $offset = $where['query'] instanceof JoinClause ? 3 : 6;
1049 return \sprintf('(%s)', \substr($this->compile_wheres($where['query']), $offset));
1050 }
1051 /**
1052 * Compile the where subquery query.
1053 *
1054 * @param QueryBuilder $query The query builder instance.
1055 * @param mixed $where The where.
1056 *
1057 * @return string The compiled where subquery query.
1058 *
1059 * @since 1.0.0
1060 */
1061 protected function where_subquery(QueryBuilder $query, $where)
1062 {
1063 $select = $this->compile_select($where['query']);
1064 return \sprintf('%s %s (%s)', $this->wrap($where['column']), $where['operator'], $select);
1065 }
1066 /**
1067 * Compile the where exists query.
1068 *
1069 * @param QueryBuilder $query The query builder instance.
1070 * @param mixed $where The where.
1071 *
1072 * @return string The compiled where exists query.
1073 *
1074 * @since 1.0.0
1075 */
1076 protected function where_exists(QueryBuilder $query, $where)
1077 {
1078 return \sprintf('exists (%s)', $this->compile_select($where['query']));
1079 }
1080 /**
1081 * Compile the where not exists query.
1082 *
1083 * @param QueryBuilder $query The query builder instance.
1084 * @param mixed $where The where.
1085 *
1086 * @return string The compiled where not exists query.
1087 *
1088 * @since 1.0.0
1089 */
1090 protected function where_not_exists(QueryBuilder $query, $where)
1091 {
1092 return \sprintf('not exists (%s)', $this->compile_select($where['query']));
1093 }
1094 /**
1095 * Prepare the bindings for the update query.
1096 *
1097 * @param array $bindings The bindings for the query.
1098 * @param array $values The values to update.
1099 *
1100 * @return array The prepared bindings.
1101 *
1102 * @since 1.0.0
1103 */
1104 public function prepare_bindings_for_update($bindings, $values)
1105 {
1106 $clean_bindings = collection($bindings)->filter(function ($value, $key) {
1107 return !\in_array($key, ['select', 'join'], \true);
1108 });
1109 $values = Arr::flatten($values);
1110 return \array_values(\array_merge($bindings['join'], $values, Arr::flatten($clean_bindings->all())));
1111 }
1112 /**
1113 * Prepare the bindings for the delete query.
1114 *
1115 * @param array $bindings The bindings for the query.
1116 *
1117 * @return array The prepared bindings.
1118 *
1119 * @since 1.0.0
1120 */
1121 public function prepare_bindings_for_delete($bindings)
1122 {
1123 $clean_bindings = collection($bindings)->filter(function ($value, $key) {
1124 return !\in_array($key, ['select'], \true);
1125 });
1126 return Arr::flatten($clean_bindings->all());
1127 }
1128 /**
1129 * Substitute the bindings into the raw SQL.
1130 *
1131 * @param string $sql The raw SQL to substitute the bindings into.
1132 * @param array $bindings The bindings to substitute into the raw SQL.
1133 *
1134 * @return string The substituted raw SQL.
1135 *
1136 * @since 1.0.0
1137 */
1138 public function substitute_bindings_into_raw_sql($sql, array $bindings = [])
1139 {
1140 if (empty($bindings)) {
1141 return $sql;
1142 }
1143 return $this->connection->get_db()->prepare($sql, $bindings);
1144 }
1145 }
1146