Completed
Pull Request — master (#212)
by Alexandru
45:00 queued 03:00
created

Analyzer::withIndex()   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 0
Metric Value
eloc 2
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Rennokki\DynamoDb\ConditionAnalyzer;
4
5
use Illuminate\Support\Arr;
6
use Rennokki\DynamoDb\ComparisonOperator;
7
use Rennokki\DynamoDb\DynamoDbModel;
8
use Rennokki\DynamoDb\H;
9
10
/**
11
 * Class ConditionAnalyzer
12
 * @package Rennokki\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
        foreach ($this->conditions as $condition) {
75 2
            if (Arr::get($condition, 'type') !== ComparisonOperator::EQ) {
76 2
                return false;
77
            }
78
        }
79
80 2
        return true;
81
    }
82
83
    /**
84
     * @return Index|null
85
     */
86 3
    public function index()
87
    {
88 3
        return $this->getIndex();
89
    }
90
91 3
    public function keyConditions()
92
    {
93 3
        $index = $this->getIndex();
94
95 3
        if ($index) {
96 1
            return $this->getConditions($index->columns());
97
        }
98
99 2
        return $this->identifierConditions();
100
    }
101
102 3
    public function filterConditions()
103
    {
104 3
        $keyConditions = $this->keyConditions() ?: [];
105
106
        return array_filter($this->conditions, function ($condition) use ($keyConditions) {
107 3
            return array_search($condition, $keyConditions) === false;
108 3
        });
109
    }
110
111 4
    public function identifierConditions()
112
    {
113 4
        $keyNames = $this->model->getKeyNames();
114
115 4
        $conditions = $this->getConditions($keyNames);
116
117 4
        if (!$this->hasValidQueryOperator(...$keyNames)) {
0 ignored issues
show
Bug introduced by
$keyNames is expanded, but the parameter $hash of Rennokki\DynamoDb\Condit...hasValidQueryOperator() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

117
        if (!$this->hasValidQueryOperator(/** @scrutinizer ignore-type */ ...$keyNames)) {
Loading history...
118 2
            return null;
119
        }
120
121 2
        return $conditions;
122
    }
123
124 2
    public function identifierConditionValues()
125
    {
126 2
        $idConditions = $this->identifierConditions();
127
128 2
        if (!$idConditions) {
129
            return [];
130
        }
131
132 2
        $values = [];
133
134 2
        foreach ($idConditions as $condition) {
135 2
            $values[$condition['column']] = $condition['value'];
136
        }
137
138 2
        return $values;
139
    }
140
141
    /**
142
     * @param $column
143
     *
144
     * @return array
145
     */
146 5
    private function getCondition($column)
147
    {
148
        return H::array_first($this->conditions, function ($condition) use ($column) {
149 5
            return $condition['column'] === $column;
150 5
        });
151
    }
152
153
    /**
154
     * @param $columns
155
     *
156
     * @return array
157
     */
158 5
    private function getConditions($columns)
159
    {
160
        return array_filter($this->conditions, function ($condition) use ($columns) {
161 5
            return in_array($condition['column'], $columns);
162 5
        });
163
    }
164
165
    /**
166
     * @return Index|null
167
     */
168 3
    private function getIndex()
169
    {
170 3
        if (empty($this->conditions)) {
171
            return null;
172
        }
173
174 3
        $index = null;
175
176 3
        foreach ($this->model->getDynamoDbIndexKeys() as $name => $keysInfo) {
177 3
            $conditionKeys = Arr::pluck($this->conditions, 'column');
178 3
            $keys = array_values($keysInfo);
179
180 3
            if (count(array_intersect($conditionKeys, $keys)) === count($keys)) {
181 1
                if (!isset($this->indexName) || $this->indexName === $name) {
182 1
                    $index = new Index(
183 1
                        $name,
184 1
                        Arr::get($keysInfo, 'hash'),
185 1
                        Arr::get($keysInfo, 'range')
186
                    );
187
188 3
                    break;
189
                }
190
            }
191
        }
192
193 3
        if ($index && !$this->hasValidQueryOperator($index->hash, $index->range)) {
0 ignored issues
show
introduced by
$index is of type Rennokki\DynamoDb\ConditionAnalyzer\Index|null, thus it always evaluated to false.
Loading history...
194
            $index = null;
195
        }
196
197 3
        return $index;
198
    }
199
200 5
    private function hasValidQueryOperator($hash, $range = null)
201
    {
202 5
        $hashCondition = $this->getCondition($hash);
203
204 5
        $validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator($hashCondition['type']);
205
206 5
        if ($validQueryOp && $range) {
207 2
            $rangeCondition = $this->getCondition($range);
208
209 2
            $validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator(
210 2
                $rangeCondition['type'],
211 2
                true
212
            );
213
        }
214
215 5
        return $validQueryOp;
216
    }
217
}
218