Passed
Pull Request — master (#29)
by Wilmer
26:23 queued 11:19
created

ArrayExpressionBuilder::getTypeHint()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 10
ccs 1
cts 1
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Pgsql\Expression;
6
7
use Traversable;
8
use Yiisoft\Db\Exception\Exception;
9
use Yiisoft\Db\Exception\InvalidArgumentException;
10
use Yiisoft\Db\Exception\InvalidConfigException;
11
use Yiisoft\Db\Exception\NotSupportedException;
12
use Yiisoft\Db\Expression\ArrayExpression;
13
use Yiisoft\Db\Expression\ExpressionBuilderInterface;
14
use Yiisoft\Db\Expression\ExpressionBuilderTrait;
15
use Yiisoft\Db\Expression\ExpressionInterface;
16
use Yiisoft\Db\Expression\JsonExpression;
17
use Yiisoft\Db\Pgsql\Schema\Schema;
18
use Yiisoft\Db\Query\Query;
19
20
use function get_class;
21
use function implode;
22
use function in_array;
23
use function is_array;
24
use function str_repeat;
25
26
class ArrayExpressionBuilder implements ExpressionBuilderInterface
27
{
28
    use ExpressionBuilderTrait;
29
30
    /**
31
     * Method builds the raw SQL from the $expression that will not be additionally escaped or quoted.
32
     *
33
     * @param ExpressionInterface $expression the expression to be built.
34
     * @param array $params the binding parameters.
35
     *
36 26
     * @throws Exception
37
     * @throws InvalidArgumentException
38 26
     * @throws InvalidConfigException
39 26
     * @throws NotSupportedException
40
     *
41
     * @return string the raw SQL that will not be additionally escaped or quoted.
42
     */
43 26
    public function build(ExpressionInterface $expression, array &$params = []): string
44 1
    {
45 1
        $value = $expression->getValue();
0 ignored issues
show
Bug introduced by
The method getValue() does not exist on Yiisoft\Db\Expression\ExpressionInterface. It seems like you code against a sub-type of Yiisoft\Db\Expression\ExpressionInterface such as Yiisoft\Db\Pdo\PdoValue or Yiisoft\Db\Expression\ArrayExpression or Yiisoft\Db\Expression\JsonExpression or Yiisoft\Db\Query\Conditions\SimpleCondition or Yiisoft\Db\Query\Conditi...BetweenColumnsCondition. ( Ignorable by Annotation )

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

45
        /** @scrutinizer ignore-call */ 
46
        $value = $expression->getValue();
Loading history...
46
        if ($value === null) {
47
            return 'NULL';
48 25
        }
49
50 25
        if ($value instanceof Query) {
51
            [$sql, $params] = $this->queryBuilder->build($value, $params);
52
            return $this->buildSubqueryArray($sql, $expression);
53
        }
54
55
        $placeholders = $this->buildPlaceholders($expression, $params);
56
57
        return 'ARRAY[' . implode(', ', $placeholders) . ']' . $this->getTypehint($expression);
58
    }
59
60
    /**
61
     * Builds placeholders array out of $expression values.
62
     *
63
     * @param ExpressionInterface $expression
64
     * @param array $params the binding parameters.
65
     *
66 25
     * @throws Exception
67
     * @throws InvalidArgumentException
68 25
     * @throws InvalidConfigException
69
     * @throws NotSupportedException
70 25
     *
71 25
     * @return array
72 2
     */
73
    protected function buildPlaceholders(ExpressionInterface $expression, &$params): array
74
    {
75 23
        $value = $expression->getValue();
76 3
77 3
        $placeholders = [];
78
        if ($value === null || (!is_array($value) && !$value instanceof Traversable)) {
79 3
            return $placeholders;
80
        }
81
82 23
        if ($expression->getDimension() > 1) {
0 ignored issues
show
Bug introduced by
The method getDimension() does not exist on Yiisoft\Db\Expression\ExpressionInterface. It seems like you code against a sub-type of Yiisoft\Db\Expression\ExpressionInterface such as Yiisoft\Db\Expression\ArrayExpression. ( Ignorable by Annotation )

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

82
        if ($expression->/** @scrutinizer ignore-call */ getDimension() > 1) {
Loading history...
83 22
            foreach ($value as $item) {
84 1
                $placeholders[] = $this->build($this->unnestArrayExpression($expression, $item), $params);
85 1
            }
86 1
            return $placeholders;
87
        }
88
89 21
        foreach ($value as $item) {
90 21
            if ($item instanceof Query) {
91 3
                [$sql, $params] = $this->queryBuilder->build($item, $params);
92 3
                $placeholders[] = $this->buildSubqueryArray($sql, $expression);
93
                continue;
94
            }
95 18
96
            $item = $this->typecastValue($expression, $item);
97
98 23
            if ($item instanceof ExpressionInterface) {
99
                $placeholders[] = $this->queryBuilder->buildExpression($item, $params);
100
                continue;
101 3
            }
102
103 3
            $placeholders[] = $this->queryBuilder->bindParam($item, $params);
104
        }
105 3
106
        return $placeholders;
107
    }
108 26
109
    private function unnestArrayExpression(ArrayExpression $expression, $value): ArrayExpression
110 26
    {
111 19
        $expressionClass = get_class($expression);
112
113
        return new $expressionClass($value, $expression->getType(), $expression->getDimension() - 1);
114 7
    }
115 7
116
    protected function getTypeHint(ArrayExpression $expression): string
117 7
    {
118
        if ($expression->getType() === null) {
119
            return '';
120
        }
121
122
        $result = '::' . $expression->getType();
123
        $result .= str_repeat('[]', $expression->getDimension());
124
125
        return $result;
126
    }
127
128 2
    /**
129
     * Build an array expression from a subquery SQL.
130 2
     *
131
     * @param string $sql the subquery SQL.
132
     * @param ArrayExpression $expression
133
     *
134
     * @return string the subquery array expression.
135
     */
136
    protected function buildSubqueryArray(string $sql, ArrayExpression $expression): string
137
    {
138
        return 'ARRAY(' . $sql . ')' . $this->getTypeHint($expression);
139
    }
140
141 21
    /**
142
     * Casts $value to use in $expression.
143 21
     *
144 2
     * @param ArrayExpression $expression
145
     * @param mixed $value
146
     *
147 19
     * @return int|JsonExpression
148 1
     */
149
    protected function typecastValue(ArrayExpression $expression, $value)
150
    {
151 18
        if ($value instanceof ExpressionInterface) {
152
            return $value;
153
        }
154 1
155
        if (in_array($expression->getType(), [Schema::TYPE_JSON, Schema::TYPE_JSONB], true)) {
156
            return new JsonExpression($value);
157
        }
158
159
        return $value;
160
    }
161
}
162