Analyzer   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 196
Duplicated Lines 0 %

Test Coverage

Coverage 98.73%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 34
eloc 70
c 4
b 0
f 0
dl 0
loc 196
ccs 78
cts 79
cp 0.9873
rs 9.68

13 Methods

Rating   Name   Duplication   Size   Complexity  
A withIndex() 0 5 1
A analyze() 0 5 1
A on() 0 5 1
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 getCondition() 0 4 1
A identifierConditionValues() 0 15 3
B getIndex() 0 30 8
A hasValidQueryOperator() 0 14 4
B isExactSearch() 0 25 7
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 4
                return false;
81
            }
82
83 15
            if (array_search(Arr::get($condition, 'column'), $this->model->getKeyNames()) === false) {
84 15
                return false;
85
            }
86
        }
87
88 11
        return true;
89
    }
90
91
    /**
92
     * @return Index|null
93
     */
94 90
    public function index()
95
    {
96 90
        return $this->getIndex();
97
    }
98
99 70
    public function keyConditions()
100
    {
101 70
        $index = $this->getIndex();
102
103 70
        if ($index) {
104 8
            return $this->getConditions($index->columns());
105
        }
106
107 64
        return $this->identifierConditions();
108
    }
109
110 70
    public function filterConditions()
111
    {
112 70
        $keyConditions = $this->keyConditions() ?: [];
113
114
        return array_filter($this->conditions, function ($condition) use ($keyConditions) {
115 70
            return array_search($condition, $keyConditions) === false;
116 70
        });
117
    }
118
119 77
    public function identifierConditions()
120
    {
121 77
        $keyNames = $this->model->getKeyNames();
122
123 77
        $conditions = $this->getConditions($keyNames);
124
125 77
        if (!$this->hasValidQueryOperator(...$keyNames)) {
126 58
            return null;
127
        }
128
129 20
        return $conditions;
130
    }
131
132 11
    public function identifierConditionValues()
133
    {
134 11
        $idConditions = $this->identifierConditions();
135
136 11
        if (!$idConditions) {
137
            return [];
138
        }
139
140 11
        $values = [];
141
142 11
        foreach ($idConditions as $condition) {
143 11
            $values[$condition['column']] = $condition['value'];
144
        }
145
146 11
        return $values;
147
    }
148
149
    /**
150
     * @param $column
151
     *
152
     * @return array
153
     */
154 78
    private function getCondition($column)
155
    {
156
        return H::array_first($this->conditions, function ($condition) use ($column) {
157 78
            return $condition['column'] === $column;
158 78
        });
159
    }
160
161
    /**
162
     * @param $columns
163
     *
164
     * @return array
165
     */
166 78
    private function getConditions($columns)
167
    {
168
        return array_filter($this->conditions, function ($condition) use ($columns) {
169 78
            return in_array($condition['column'], $columns);
170 78
        });
171
    }
172
173
    /**
174
     * @return Index|null
175
     */
176 90
    private function getIndex()
177
    {
178 90
        if (empty($this->conditions)) {
179 27
            return null;
180
        }
181
182 70
        $index = null;
183
184 70
        foreach ($this->model->getDynamoDbIndexKeys() as $name => $keysInfo) {
185 68
            $conditionKeys = Arr::pluck($this->conditions, 'column');
186 68
            $keys = array_values($keysInfo);
187
188 68
            if (count(array_intersect($conditionKeys, $keys)) === count($keys)) {
189 27
                if (!isset($this->indexName) || $this->indexName === $name) {
190 27
                    $index = new Index(
191 27
                        $name,
192 27
                        Arr::get($keysInfo, 'hash'),
193 27
                        Arr::get($keysInfo, 'range')
194
                    );
195
196 68
                    break;
197
                }
198
            }
199
        }
200
201 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...
202 20
            $index = null;
203
        }
204
205 70
        return $index;
206
    }
207
208 78
    private function hasValidQueryOperator($hash, $range = null)
209
    {
210 78
        $hashConditionType = $this->getCondition($hash)['type'] ?? null;
211 78
        $validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator($hashConditionType);
212
213 78
        if ($validQueryOp && $range && $this->getCondition($range) !== null) {
214 12
            $rangeConditionType = $this->getCondition($range)['type'];
215 12
            $validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator(
216 12
                $rangeConditionType,
217 12
                true
218
            );
219
        }
220
221 78
        return $validQueryOp;
222
    }
223
}
224