Passed
Pull Request — master (#254)
by Claudio
21:56
created

Analyzer   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 192
Duplicated Lines 0 %

Test Coverage

Coverage 98.7%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 33
eloc 68
c 4
b 0
f 0
dl 0
loc 192
ccs 76
cts 77
cp 0.987
rs 9.76

13 Methods

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