Test Failed
Pull Request — master (#188)
by
unknown
07:04
created

Analyzer::filterConditions()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 6
c 0
b 0
f 0
ccs 3
cts 3
cp 1
rs 10
cc 2
nc 1
nop 0
crap 2
1
<?php
2
3
namespace BaoPham\DynamoDb\ConditionAnalyzer;
4
5
use BaoPham\DynamoDb\ComparisonOperator;
6
use BaoPham\DynamoDb\DynamoDbModel;
7
use BaoPham\DynamoDb\H;
8
9
/**
10
 * Class ConditionAnalyzer
11
 * @package BaoPham\DynamoDb\ConditionAnalyzer
12
 *
13
 * Usage:
14
 *
15
 * $analyzer = with(new Analyzer)
16
 *  ->on($model)
17
 *  ->withIndex($index)
18
 *  ->analyze($conditions);
19
 *
20
 * $analyzer->isExactSearch();
21
 * $analyzer->keyConditions();
22
 * $analyzer->filterConditions();
23
 * $analyzer->index();
24
 */
25
class Analyzer
26
{
27
    /**
28
     * @var DynamoDbModel
29
     */
30
    private $model;
31
32
    /**
33
     * @var array
34
     */
35
    private $conditions = [];
36
37
    /**
38
     * @var string
39
     */
40
    private $indexName;
41
42 97
    public function on(DynamoDbModel $model)
43
    {
44 97
        $this->model = $model;
45
46 97
        return $this;
47
    }
48
49 97
    public function withIndex($index)
50
    {
51 97
        $this->indexName = $index;
52
53 97
        return $this;
54
    }
55
56 97
    public function analyze($conditions)
57
    {
58 97
        $this->conditions = $conditions;
59
60 97
        return $this;
61
    }
62
63 91
    public function isExactSearch()
64
    {
65 91
        if (empty($this->conditions)) {
66 27
            return false;
67
        }
68
69 71
        if (empty($this->identifierConditions())) {
70 55
            return false;
71
        }
72
73 16
        foreach ($this->conditions as $condition) {
74 16
            if (array_get($condition, 'type') !== ComparisonOperator::EQ) {
75 5
                return false;
76
            }
77
        }
78
79 11
        return true;
80
    }
81
82
    /**
83
     * @return Index|null
84
     */
85 90
    public function index()
86
    {
87 90
        return $this->getIndex();
88
    }
89
90 70
    public function keyConditions()
91
    {
92 70
        $index = $this->getIndex();
93
94 70
        if ($index) {
95 13
            return $this->getConditions($index->columns());
96
        }
97
98 58
        return $this->identifierConditions();
99
    }
100
101 70
    public function filterConditions()
102
    {
103 70
        $keyConditions = $this->keyConditions() ?: [];
104
105
        return array_filter($this->conditions, function ($condition) use ($keyConditions) {
106 70
            return array_search($condition, $keyConditions) === false;
107 70
        });
108
    }
109
110 76
    public function identifierConditions()
111
    {
112 76
        $keyNames = $this->model->getKeyNames();
113
114 76
        $conditions = $this->getConditions($keyNames);
115
116 76
        if (!$this->hasValidQueryOperator(...$keyNames)) {
117 60
            return null;
118
        }
119
120 16
        return $conditions;
121
    }
122
123 11
    public function identifierConditionValues()
124
    {
125 11
        $idConditions = $this->identifierConditions();
126
127 11
        if (!$idConditions) {
128
            return [];
129
        }
130
131 11
        $values = [];
132
133 11
        foreach ($idConditions as $condition) {
134 11
            $values[$condition['column']] = $condition['value'];
135
        }
136
137 11
        return $values;
138
    }
139
140
    /**
141
     * @param $column
142
     *
143
     * @return array
144
     */
145 78
    private function getCondition($column)
146
    {
147
        return H::array_first($this->conditions, function ($condition) use ($column) {
148 78
            return $condition['column'] === $column;
149 78
        });
150
    }
151
152
    /**
153
     * @param $columns
154
     *
155
     * @return array
156
     */
157 78
    private function getConditions($columns)
158
    {
159
        return array_filter($this->conditions, function ($condition) use ($columns) {
160 78
            return in_array($condition['column'], $columns);
161 78
        });
162
    }
163
164
    /**
165
     * @return Index|null
166
     */
167 90
    private function getIndex()
168
    {
169 90
        if (empty($this->conditions)) {
170 27
            return null;
171
        }
172
173 70
        $index = null;
174 70
        $keyIntersectionCount = 0;
175
176 70
        foreach ($this->model->getDynamoDbIndexKeys() as $name => $keysInfo) {
177 68
            $conditionKeys = array_pluck($this->conditions, 'column');
178 68
            $keys = array_values($keysInfo);
179 68
            $keyIntersectionCount = count(array_intersect($conditionKeys, $keys));
180
181 68
            if ($keyIntersectionCount === 1 || $keyIntersectionCount === 2) {
182 35
                if (!isset($this->indexName) || $this->indexName === $name) {
183 35
                    $index = new Index(
184 35
                        $name,
185 35
                        array_get($keysInfo, 'hash'),
186 35
                        array_get($keysInfo, 'range')
187
                    );
188
189 35
                    break;
190
                }
191
            }
192
        }
193
194 70
        if ($index && !$this->hasValidQueryOperator($index->hash, $keyIntersectionCount === 2 ? $index->range : null)) {
0 ignored issues
show
introduced by
$index is of type BaoPham\DynamoDb\ConditionAnalyzer\Index|null, thus it always evaluated to false.
Loading history...
195 23
            $index = null;
196
        }
197
198 70
        return $index;
199
    }
200
201 78
    private function hasValidQueryOperator($hash, $range = null)
202
    {
203 78
        $hashCondition = $this->getCondition($hash);
204
205 78
        $validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator($hashCondition['type']);
206
207 78
        if ($validQueryOp && $range) {
208 12
            $rangeCondition = $this->getCondition($range);
209
210 12
            $validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator(
211 12
                $rangeCondition['type'],
212 12
                true
213
            );
214
        }
215
216 78
        return $validQueryOp;
217
    }
218
}
219