Test Failed
Pull Request — master (#272)
by Manabu
06:33
created

Analyzer::isExactSearch()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 8.4275

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 12
c 2
b 0
f 0
dl 0
loc 25
ccs 9
cts 13
cp 0.6923
rs 8.8333
cc 7
nc 7
nop 0
crap 8.4275
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 5
    public function on(DynamoDbModel $model)
44
    {
45 5
        $this->model = $model;
46
47 5
        return $this;
48
    }
49
50 5
    public function withIndex($index)
51
    {
52 5
        $this->indexName = $index;
53
54 5
        return $this;
55
    }
56
57 5
    public function analyze($conditions)
58
    {
59 5
        $this->conditions = $conditions;
60
61 5
        return $this;
62
    }
63
64 2
    public function isExactSearch()
65
    {
66 2
        if (empty($this->conditions)) {
67
            return false;
68
        }
69
70 2
        if (empty($this->identifierConditions())) {
71
            return false;
72
        }
73
74 2
        if (count($this->conditions) !== count($this->model->getKeyNames())) {
75
            return false;
76
        }
77
78 2
        foreach ($this->conditions as $condition) {
79 2
            if (Arr::get($condition, 'type') !== ComparisonOperator::EQ) {
80
                return false;
81
            }
82
83 2
            if (array_search(Arr::get($condition, 'column'), $this->model->getKeyNames()) === false) {
84 2
                return false;
85
            }
86
        }
87
88 2
        return true;
89
    }
90
91
    /**
92
     * @return Index|null
93
     */
94 3
    public function index()
95
    {
96 3
        return $this->getIndex();
97
    }
98
99 3
    public function keyConditions()
100
    {
101 3
        $index = $this->getIndex();
102
103 3
        if ($index) {
104 1
            return $this->getConditions($index->columns());
105
        }
106
107 2
        return $this->identifierConditions();
108
    }
109
110 3
    public function filterConditions()
111
    {
112 3
        $keyConditions = $this->keyConditions() ?: [];
113
114
        return array_filter($this->conditions, function ($condition) use ($keyConditions) {
115 3
            return array_search($condition, $keyConditions) === false;
116 3
        });
117
    }
118
119 4
    public function identifierConditions()
120
    {
121 4
        $keyNames = $this->model->getKeyNames();
122
123 4
        $conditions = $this->getConditions($keyNames);
124
125 4
        if (!$this->hasValidQueryOperator(...$keyNames)) {
126 2
            return null;
127
        }
128
129 2
        return $conditions;
130
    }
131
132 2
    public function identifierConditionValues()
133
    {
134 2
        $idConditions = $this->identifierConditions();
135
136 2
        if (!$idConditions) {
137
            return [];
138
        }
139
140 2
        $values = [];
141
142 2
        foreach ($idConditions as $condition) {
143 2
            $values[$condition['column']] = $condition['value'];
144
        }
145
146 2
        return $values;
147
    }
148
149
    /**
150
     * @param $column
151
     *
152
     * @return array
153
     */
154 5
    private function getCondition($column)
155
    {
156
        return H::array_first($this->conditions, function ($condition) use ($column) {
157 5
            return $condition['column'] === $column;
158 5
        });
159
    }
160
161
    /**
162
     * @param $columns
163
     *
164
     * @return array
165
     */
166 5
    private function getConditions($columns)
167
    {
168
        return array_filter($this->conditions, function ($condition) use ($columns) {
169 5
            return in_array($condition['column'], $columns);
170 5
        });
171
    }
172
173
    /**
174
     * @return Index|null
175
     */
176 3
    private function getIndex()
177
    {
178 3
        if (empty($this->conditions)) {
179
            return null;
180
        }
181
182 3
        $index = null;
183
184 3
        foreach ($this->model->getDynamoDbIndexKeys() as $name => $keysInfo) {
185 3
            $conditionKeys = Arr::pluck($this->conditions, 'column');
186 3
            $keys = array_values($keysInfo);
187
188 3
            if (count(array_intersect($conditionKeys, $keys)) === count($keys)) {
189 1
                if (!isset($this->indexName) || $this->indexName === $name) {
190 1
                    $index = new Index(
191 1
                        $name,
192 1
                        Arr::get($keysInfo, 'hash'),
193 1
                        Arr::get($keysInfo, 'range')
194
                    );
195
196 3
                    break;
197
                }
198
            }
199
        }
200
201 3
        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
            $index = null;
203
        }
204
205 3
        return $index;
206
    }
207
208 5
    private function hasValidQueryOperator($hash, $range = null)
209
    {
210 5
        $hashConditionType = $this->getCondition($hash)['type'] ?? null;
211 5
        $validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator($hashConditionType);
212
213 5
        if ($validQueryOp && $range && $this->getCondition($range) !== null) {
214 2
            $rangeConditionType = $this->getCondition($range)['type'];
215 2
            $validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator(
216 2
                $rangeConditionType,
217 2
                true
218
            );
219
        }
220
221 5
        return $validQueryOp;
222
    }
223
}
224