1
|
|
|
<?php |
2
|
|
|
declare(strict_types=1); |
3
|
|
|
|
4
|
|
|
namespace Remorhaz\JSON\Path\Runtime; |
5
|
|
|
|
6
|
|
|
use Remorhaz\JSON\Path\Value\EvaluatedValueListBuilder; |
7
|
|
|
use function array_fill; |
8
|
|
|
use function count; |
9
|
|
|
use function is_bool; |
10
|
|
|
use function preg_match; |
11
|
|
|
use Remorhaz\JSON\Path\Value\EvaluatedValueList; |
12
|
|
|
use Remorhaz\JSON\Path\Value\EvaluatedValueListInterface; |
13
|
|
|
use Remorhaz\JSON\Path\Value\IndexMapInterface; |
14
|
|
|
use Remorhaz\JSON\Path\Value\ValueListBuilder; |
15
|
|
|
use Remorhaz\JSON\Path\Value\LiteralValueListInterface; |
16
|
|
|
use Remorhaz\JSON\Data\Value\ScalarValueInterface; |
17
|
|
|
use Remorhaz\JSON\Path\Value\ValueListInterface; |
18
|
|
|
|
19
|
|
|
final class Evaluator implements EvaluatorInterface |
20
|
|
|
{ |
21
|
|
|
|
22
|
|
|
private $comparators; |
23
|
|
|
|
24
|
|
|
private $aggregators; |
25
|
|
|
|
26
|
52 |
|
public function __construct( |
27
|
|
|
Comparator\ComparatorCollectionInterface $comparators, |
28
|
|
|
Aggregator\AggregatorCollectionInterface $aggregators |
29
|
|
|
) { |
30
|
52 |
|
$this->comparators = $comparators; |
31
|
52 |
|
$this->aggregators = $aggregators; |
32
|
52 |
|
} |
33
|
|
|
|
34
|
6 |
|
public function logicalOr( |
35
|
|
|
EvaluatedValueListInterface $leftValues, |
36
|
|
|
EvaluatedValueListInterface $rightValues |
37
|
|
|
): EvaluatedValueListInterface { |
38
|
6 |
|
$results = []; |
39
|
6 |
|
foreach ($leftValues->getResults() as $index => $leftResult) { |
40
|
4 |
|
$results[] = $leftResult || $rightValues->getResult($index); |
41
|
|
|
} |
42
|
|
|
|
43
|
6 |
|
return new EvaluatedValueList( |
44
|
6 |
|
$this->getEqualIndexMap($leftValues, $rightValues), |
45
|
5 |
|
...$results |
46
|
|
|
); |
47
|
|
|
} |
48
|
|
|
|
49
|
6 |
|
public function logicalAnd( |
50
|
|
|
EvaluatedValueListInterface $leftValues, |
51
|
|
|
EvaluatedValueListInterface $rightValues |
52
|
|
|
): EvaluatedValueListInterface { |
53
|
6 |
|
$results = []; |
54
|
6 |
|
foreach ($leftValues->getResults() as $index => $leftResult) { |
55
|
4 |
|
$results[] = $leftResult && $rightValues->getResult($index); |
56
|
|
|
} |
57
|
|
|
|
58
|
6 |
|
return new EvaluatedValueList( |
59
|
6 |
|
$this->getEqualIndexMap($leftValues, $rightValues), |
60
|
5 |
|
...$results |
61
|
|
|
); |
62
|
|
|
} |
63
|
|
|
|
64
|
4 |
|
public function logicalNot(EvaluatedValueListInterface $values): EvaluatedValueListInterface |
65
|
|
|
{ |
66
|
4 |
|
$results = []; |
67
|
4 |
|
foreach ($values->getResults() as $leftResult) { |
68
|
2 |
|
$results[] = !$leftResult; |
69
|
|
|
} |
70
|
|
|
|
71
|
4 |
|
return new EvaluatedValueList($values->getIndexMap(), ...$results); |
72
|
|
|
} |
73
|
|
|
|
74
|
9 |
|
public function isEqual( |
75
|
|
|
ValueListInterface $leftValues, |
76
|
|
|
ValueListInterface $rightValues |
77
|
|
|
): EvaluatedValueListInterface { |
78
|
9 |
|
return $this->compare( |
79
|
9 |
|
$leftValues, |
80
|
|
|
$rightValues, |
81
|
9 |
|
$this->comparators->equal() |
82
|
|
|
); |
83
|
|
|
} |
84
|
|
|
|
85
|
5 |
|
public function isGreater( |
86
|
|
|
ValueListInterface $leftValues, |
87
|
|
|
ValueListInterface $rightValues |
88
|
|
|
): EvaluatedValueListInterface { |
89
|
5 |
|
return $this->compare( |
90
|
5 |
|
$leftValues, |
91
|
|
|
$rightValues, |
92
|
5 |
|
$this->comparators->greater() |
93
|
|
|
); |
94
|
|
|
} |
95
|
|
|
|
96
|
14 |
|
private function compare( |
97
|
|
|
ValueListInterface $leftValues, |
98
|
|
|
ValueListInterface $rightValues, |
99
|
|
|
Comparator\ComparatorInterface $comparator |
100
|
|
|
): EvaluatedValueListInterface { |
101
|
14 |
|
$valueListBuilder = new EvaluatedValueListBuilder; |
102
|
14 |
|
foreach ($leftValues->getIndexMap()->getOuterIndexes() as $leftInnerIndex => $leftOuterIndex) { |
103
|
13 |
|
foreach ($rightValues->getIndexMap()->getOuterIndexes() as $rightInnerIndex => $rightOuterIndex) { |
104
|
13 |
|
if (!isset($leftOuterIndex, $rightOuterIndex)) { |
105
|
3 |
|
continue; |
106
|
|
|
} |
107
|
10 |
|
if ($leftOuterIndex != $rightOuterIndex) { |
108
|
2 |
|
continue; |
109
|
|
|
} |
110
|
|
|
|
111
|
8 |
|
$valueListBuilder->addResult( |
112
|
8 |
|
$comparator->compare( |
113
|
8 |
|
$leftValues->getValue($leftInnerIndex), |
114
|
8 |
|
$rightValues->getValue($rightInnerIndex) |
115
|
|
|
), |
116
|
|
|
$leftOuterIndex |
117
|
|
|
); |
118
|
|
|
} |
119
|
|
|
} |
120
|
|
|
|
121
|
14 |
|
return $valueListBuilder->build(); |
122
|
|
|
} |
123
|
|
|
|
124
|
7 |
|
public function isRegExp(string $regExp, ValueListInterface $values): EvaluatedValueListInterface |
125
|
|
|
{ |
126
|
7 |
|
$results = []; |
127
|
|
|
|
128
|
7 |
|
foreach ($values->getValues() as $value) { |
129
|
5 |
|
if (!$value instanceof ScalarValueInterface) { |
130
|
1 |
|
$results[] = false; |
131
|
1 |
|
continue; |
132
|
|
|
} |
133
|
4 |
|
$data = $value->getData(); |
134
|
4 |
|
if (!is_string($data)) { |
135
|
1 |
|
$results[] = false; |
136
|
1 |
|
continue; |
137
|
|
|
} |
138
|
3 |
|
$match = @preg_match($regExp, $data); |
139
|
3 |
|
if (false === $match) { |
140
|
1 |
|
throw new Exception\InvalidRegExpException($regExp); |
141
|
|
|
} |
142
|
2 |
|
$results[] = 1 === $match; |
143
|
|
|
} |
144
|
|
|
|
145
|
6 |
|
return new EvaluatedValueList($values->getIndexMap(), ...$results); |
146
|
|
|
} |
147
|
|
|
|
148
|
9 |
|
public function evaluate( |
149
|
|
|
ValueListInterface $sourceValues, |
150
|
|
|
ValueListInterface $resultValues |
151
|
|
|
): EvaluatedValueListInterface { |
152
|
9 |
|
if ($resultValues instanceof EvaluatedValueListInterface) { |
153
|
1 |
|
return $resultValues; |
154
|
|
|
} |
155
|
|
|
|
156
|
8 |
|
if ($resultValues instanceof LiteralValueListInterface) { |
157
|
4 |
|
return $this->evaluateLiteralValues($sourceValues, $resultValues); |
158
|
|
|
} |
159
|
|
|
|
160
|
4 |
|
$results = []; |
161
|
4 |
|
foreach ($sourceValues->getIndexMap()->getOuterIndexes() as $outerIndex) { |
162
|
3 |
|
$results[] = isset($outerIndex) |
163
|
2 |
|
? $resultValues->getIndexMap()->outerIndexExists($outerIndex) |
164
|
1 |
|
: false; |
165
|
|
|
} |
166
|
|
|
|
167
|
4 |
|
return new EvaluatedValueList($sourceValues->getIndexMap(), ...$results); |
168
|
|
|
} |
169
|
|
|
|
170
|
4 |
|
private function evaluateLiteralValues( |
171
|
|
|
ValueListInterface $sourceValues, |
172
|
|
|
LiteralValueListInterface $resultValues |
173
|
|
|
): EvaluatedValueListInterface { |
174
|
4 |
|
$indexMap = $this->getEqualIndexMap($sourceValues, $resultValues); |
175
|
4 |
|
$literal = $resultValues->getLiteral(); |
176
|
4 |
|
if ($literal instanceof ScalarValueInterface) { |
177
|
3 |
|
$data = $literal->getData(); |
178
|
3 |
|
if (is_bool($data)) { |
179
|
2 |
|
return new EvaluatedValueList( |
180
|
2 |
|
$indexMap, |
181
|
2 |
|
...array_fill(0, count($indexMap), $data) |
182
|
|
|
); |
183
|
|
|
} |
184
|
|
|
} |
185
|
|
|
|
186
|
2 |
|
throw new Exception\LiteralEvaluationFailedException($literal); |
187
|
|
|
} |
188
|
|
|
|
189
|
16 |
|
private function getEqualIndexMap( |
190
|
|
|
ValueListInterface $leftValues, |
191
|
|
|
ValueListInterface $rightValues |
192
|
|
|
): IndexMapInterface { |
193
|
16 |
|
$indexMap = $leftValues->getIndexMap(); |
194
|
16 |
|
if ($indexMap->equals($rightValues->getIndexMap())) { |
195
|
14 |
|
return $indexMap; |
196
|
|
|
} |
197
|
|
|
|
198
|
2 |
|
throw new Exception\IndexMapMatchFailedException($leftValues, $rightValues); |
199
|
|
|
} |
200
|
|
|
|
201
|
6 |
|
public function aggregate(string $functionName, ValueListInterface $values): ValueListInterface |
202
|
|
|
{ |
203
|
6 |
|
$aggregator = $this->aggregators->byName($functionName); |
204
|
6 |
|
$valuesBuilder = new ValueListBuilder; |
205
|
6 |
|
foreach ($values->getValues() as $innerIndex => $value) { |
206
|
4 |
|
$aggregatedValue = $aggregator->tryAggregate($value); |
207
|
4 |
|
if (isset($aggregatedValue)) { |
208
|
2 |
|
$valuesBuilder->addValue( |
209
|
2 |
|
$aggregatedValue, |
210
|
2 |
|
$values->getIndexMap()->getOuterIndex($innerIndex) |
211
|
|
|
); |
212
|
|
|
} |
213
|
|
|
} |
214
|
|
|
|
215
|
6 |
|
return $valuesBuilder->build(); |
216
|
|
|
} |
217
|
|
|
} |
218
|
|
|
|