Passed
Push — master ( 651f47...1b6630 )
by Edward
03:03
created

Evaluator::isEqual()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
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