Skip to content

Commit 1c990c5

Browse files
committed
Further optimisations
Added benchmarking action
1 parent d4a4e11 commit 1c990c5

File tree

4 files changed

+41
-19
lines changed

4 files changed

+41
-19
lines changed

src/Sql/AbstractExpression.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,12 @@ public function getSpecification(): ?string
4343
{
4444
return $this->specification;
4545
}
46+
47+
/**
48+
* Whether this predicate needs parentheses when nested in a predicate set
49+
*/
50+
public function hasParentheses(): bool
51+
{
52+
return false;
53+
}
4654
}

src/Sql/Predicate/Literal.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,10 @@ public function getCombination(): string
3333
{
3434
return $this->combination;
3535
}
36+
37+
#[Override]
38+
public function hasParentheses(): bool
39+
{
40+
return false;
41+
}
3642
}

src/Sql/Predicate/PredicateInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@ public function setCombination(string $combination): static;
1818
* Get the combination operator
1919
*/
2020
public function getCombination(): string;
21+
22+
public function hasParentheses(): bool;
2123
}

src/Sql/Predicate/PredicateSet.php

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
use function is_array;
1919
use function is_scalar;
2020
use function is_string;
21+
use function next;
22+
use function reset;
2123
use function str_contains;
2224

2325
class PredicateSet extends AbstractExpression implements PredicateInterface, Countable
@@ -55,6 +57,9 @@ class PredicateSet extends AbstractExpression implements PredicateInterface, Cou
5557
/** SQL clause prefix (e.g., 'WHERE', 'HAVING') - override in subclasses */
5658
protected string $prefix = '';
5759

60+
/** Whether this predicate set needs parentheses when nested (cached for performance) */
61+
protected bool $hasParentheses = false;
62+
5863
/**
5964
* Constructor
6065
*/
@@ -75,7 +80,8 @@ public function __construct(?array $predicates = null, string $defaultCombinatio
7580
public function addPredicate(PredicateInterface $predicate, ?string $combination = null): static
7681
{
7782
$predicate->setCombination($combination ?? $this->defaultCombination);
78-
$this->predicates[] = $predicate;
83+
$this->predicates[] = $predicate;
84+
$this->hasParentheses = $this->hasParentheses || count($this->predicates) > 1;
7985

8086
return $this;
8187
}
@@ -124,26 +130,30 @@ public function addPredicates(
124130
$this->predicates[] = $predicate;
125131
}
126132

133+
$this->hasParentheses = $this->hasParentheses || count($this->predicates) > 1;
127134
return $this;
128135
}
129136

130137
if ($predicates instanceof PredicateInterface) {
131138
$predicates->setCombination($combination);
132-
$this->predicates[] = $predicates;
139+
$this->predicates[] = $predicates;
140+
$this->hasParentheses = $this->hasParentheses || count($this->predicates) > 1;
133141

134142
return $this;
135143
}
136144

137145
if ($predicates instanceof Closure) {
138146
$predicates($this);
147+
$this->hasParentheses = $this->hasParentheses || count($this->predicates) > 1;
139148

140149
return $this;
141150
}
142151

143152
$predicate = str_contains($predicates, Expression::PLACEHOLDER)
144153
? new PredicateExpression($predicates) : new Literal($predicates);
145154
$predicate->setCombination($combination);
146-
$this->predicates[] = $predicate;
155+
$this->predicates[] = $predicate;
156+
$this->hasParentheses = $this->hasParentheses || count($this->predicates) > 1;
147157

148158
return $this;
149159
}
@@ -218,6 +228,12 @@ public function count(): int
218228
return count($this->predicates);
219229
}
220230

231+
#[Override]
232+
public function hasParentheses(): bool
233+
{
234+
return $this->hasParentheses;
235+
}
236+
221237
/** @inheritDoc */
222238
#[Override]
223239
public function prepareSqlString(PreparableSqlBuilder $builder): string
@@ -226,23 +242,13 @@ public function prepareSqlString(PreparableSqlBuilder $builder): string
226242
return '';
227243
}
228244

229-
$result = '';
230-
$first = true;
245+
$predicate = reset($this->predicates);
246+
$sql = $predicate->prepareSqlString($builder);
247+
$result = $predicate->hasParentheses() ? "($sql)" : $sql;
231248

232-
foreach ($this->predicates as $predicate) {
233-
$sql = $predicate->prepareSqlString($builder);
234-
235-
// Nested predicate sets with multiple predicates need parentheses
236-
if ($predicate instanceof self && $predicate->count() > 1) {
237-
$sql = '(' . $sql . ')';
238-
}
239-
240-
if ($first) {
241-
$result = $sql;
242-
$first = false;
243-
} else {
244-
$result .= ' ' . $predicate->combination . ' ' . $sql;
245-
}
249+
while ($predicate = next($this->predicates)) {
250+
$sql = $predicate->prepareSqlString($builder);
251+
$result .= " $predicate->combination " . ($predicate->hasParentheses() ? "($sql)" : $sql);
246252
}
247253

248254
return $this->prefix === '' ? $result : ' ' . $this->prefix . ' ' . $result;

0 commit comments

Comments
 (0)