Passed
Pull Request — master (#226)
by
unknown
05:58
created

Analyzer::analyze()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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