Issues (10)

src/Parsers/ConditionExpression.php (2 issues)

Labels
Severity
1
<?php
2
3
namespace BaoPham\DynamoDb\Parsers;
4
5
use BaoPham\DynamoDb\ComparisonOperator;
6
use BaoPham\DynamoDb\NotSupportedException;
7
use BaoPham\DynamoDb\Facades\DynamoDb;
8
use Illuminate\Support\Arr;
9
10
class ConditionExpression
11
{
12
    const OPERATORS = [
13
        ComparisonOperator::EQ => '%s = :%s',
14
        ComparisonOperator::LE => '%s <= :%s',
15
        ComparisonOperator::LT => '%s < :%s',
16
        ComparisonOperator::GE => '%s >= :%s',
17
        ComparisonOperator::GT => '%s > :%s',
18
        ComparisonOperator::BEGINS_WITH => 'begins_with(%s, :%s)',
19
        ComparisonOperator::BETWEEN => '(%s BETWEEN :%s AND :%s)',
20
        ComparisonOperator::CONTAINS => 'contains(%s, :%s)',
21
        ComparisonOperator::NOT_CONTAINS => 'NOT contains(%s, :%s)',
22
        ComparisonOperator::NULL => 'attribute_not_exists(%s)',
23
        ComparisonOperator::NOT_NULL => 'attribute_exists(%s)',
24
        ComparisonOperator::NE => '%s <> :%s',
25
        ComparisonOperator::IN => '%s IN (%s)',
26
    ];
27
28
    /**
29
     * @var ExpressionAttributeValues
30
     */
31
    protected $values;
32
33
    /**
34
     * @var ExpressionAttributeNames
35
     */
36
    protected $names;
37
38
    /**
39
     * @var Placeholder
40
     */
41
    protected $placeholder;
42
43 133
    public function __construct(
44
        Placeholder $placeholder,
45
        ExpressionAttributeValues $values,
46
        ExpressionAttributeNames $names
47
    ) {
48 133
        $this->placeholder = $placeholder;
49 133
        $this->values = $values;
50 133
        $this->names = $names;
51 133
    }
52
53
    /**
54
     * @param array $where
55
     *   [
56
     *     'column' => 'name',
57
     *     'type' => 'EQ',
58
     *     'value' => 'foo',
59
     *     'boolean' => 'and',
60
     *   ]
61
     *
62
     * @return string
63
     * @throws NotSupportedException
64
     */
65 72
    public function parse($where)
66
    {
67 72
        if (empty($where)) {
68
            return '';
69
        }
70
71 72
        $parsed = [];
72
73 72
        foreach ($where as $condition) {
74 72
            $boolean = Arr::get($condition, 'boolean');
75 72
            $value = Arr::get($condition, 'value');
76 72
            $type = Arr::get($condition, 'type');
77
78 72
            $prefix = '';
79
80 72
            if (count($parsed) > 0) {
81 45
                $prefix = strtoupper($boolean) . ' ';
0 ignored issues
show
It seems like $boolean can also be of type null; however, parameter $string of strtoupper() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

81
                $prefix = strtoupper(/** @scrutinizer ignore-type */ $boolean) . ' ';
Loading history...
82
            }
83
84 72
            if ($type === 'Nested') {
85 3
                $parsed[] = $prefix . $this->parseNestedCondition($value);
0 ignored issues
show
It seems like $value can also be of type null; however, parameter $conditions of BaoPham\DynamoDb\Parsers...:parseNestedCondition() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

85
                $parsed[] = $prefix . $this->parseNestedCondition(/** @scrutinizer ignore-type */ $value);
Loading history...
86 3
                continue;
87
            }
88
89 72
            $parsed[] = $prefix . $this->parseCondition(
90 72
                Arr::get($condition, 'column'),
91 72
                $type,
92 72
                $value
93
            );
94
        }
95
96 72
        return implode(' ', $parsed);
97
    }
98
99 124
    public function reset()
100
    {
101 124
        $this->placeholder->reset();
102 124
        $this->names->reset();
103 124
        $this->values->reset();
104 124
    }
105
106 62
    protected function getSupportedOperators()
107
    {
108 62
        return static::OPERATORS;
109
    }
110
111 3
    protected function parseNestedCondition(array $conditions)
112
    {
113 3
        return '(' . $this->parse($conditions) . ')';
114
    }
115
116 72
    protected function parseCondition($name, $operator, $value)
117
    {
118 72
        $operators = $this->getSupportedOperators();
119
120 72
        if (empty($operators[$operator])) {
121
            throw new NotSupportedException("$operator is not supported");
122
        }
123
124 72
        $template = $operators[$operator];
125
126 72
        $this->names->set($name);
127
128 72
        if ($operator === ComparisonOperator::BETWEEN) {
129 3
            return $this->parseBetweenCondition($name, $value, $template);
130
        }
131
132 70
        if ($operator === ComparisonOperator::IN) {
133 3
            return $this->parseInCondition($name, $value, $template);
134
        }
135
136 68
        if ($operator === ComparisonOperator::NULL || $operator === ComparisonOperator::NOT_NULL) {
137 5
            return $this->parseNullCondition($name, $template);
138
        }
139
140 64
        $placeholder = $this->placeholder->next();
141
142 64
        $this->values->set($placeholder, DynamoDb::marshalValue($value));
143
144 64
        return sprintf($template, $this->names->placeholder($name), $placeholder);
145
    }
146
147 3
    protected function parseBetweenCondition($name, $value, $template)
148
    {
149 3
        $first = $this->placeholder->next();
150
151 3
        $second = $this->placeholder->next();
152
153 3
        $this->values->set($first, DynamoDb::marshalValue($value[0]));
154
155 3
        $this->values->set($second, DynamoDb::marshalValue($value[1]));
156
157 3
        return sprintf($template, $this->names->placeholder($name), $first, $second);
158
    }
159
160 3
    protected function parseInCondition($name, $value, $template)
161
    {
162 3
        $valuePlaceholders = [];
163
164 3
        foreach ($value as $item) {
165 3
            $placeholder = $this->placeholder->next();
166
167 3
            $valuePlaceholders[] = ":" . $placeholder;
168
169 3
            $this->values->set($placeholder, DynamoDb::marshalValue($item));
170
        }
171
172 3
        return sprintf($template, $this->names->placeholder($name), implode(', ', $valuePlaceholders));
173
    }
174
175 5
    protected function parseNullCondition($name, $template)
176
    {
177 5
        return sprintf($template, $this->names->placeholder($name));
178
    }
179
}
180