ReturnVars::addTable()   A
last analyzed

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
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
3
namespace mindplay\sql\model\components;
4
5
use mindplay\sql\model\Driver;
6
use mindplay\sql\model\schema\Column;
7
use mindplay\sql\model\schema\Table;
8
use mindplay\sql\model\schema\Type;
9
use mindplay\sql\model\TypeProvider;
10
use OutOfBoundsException;
11
use UnexpectedValueException;
12
13
/**
14
 * This component implements support for return variable expressions (for use in a SELECT or RETURNING clause)
15
 */
16
class ReturnVars
17
{
18
    /**
19
     * @var string[] list of return variable expressions (for use in a SELECT or RETURNING clause)
20
     */
21
    private array $vars = [];
22
23
    /**
24
     * @var Type[] map where return variable name maps to Type
25
     */
26
    private array $type_map = [];
27
28
    private Table $root;
29
30
    private Driver $driver;
31
32
    private TypeProvider $types;
33
    
34 1
    public function __construct(Table $root, Driver $driver, TypeProvider $types)
35
    {
36 1
        $this->root = $root;
37 1
        $this->driver = $driver;
38 1
        $this->types = $types;
39
    }
40
41
    /**
42
     * Add all the Columns of a full Table to be selected and returned
43
     *
44
     * @param Table $table Table to select and return
45
     */
46 1
    public function addTable(Table $table): void
47
    {
48 1
        $this->vars[] = "{$table}.*";
49
50 1
        $this->type_map = array_merge($this->type_map, $this->createTypeMap($table));
51
    }
52
53
    /**
54
     * Add one or more Columns to select and return
55
     *
56
     * @param Column|Column[] $cols one or more Columns to select and return
57
     */
58 1
    public function addColumns(Column|array $cols): void
59
    {
60
        /**
61
         * @var Column[] $cols
62
         */
63
64 1
        $cols = is_array($cols) ? $cols : [$cols];
0 ignored issues
show
introduced by
The condition is_array($cols) is always true.
Loading history...
65
66 1
        foreach ($cols as $col) {
67 1
            $alias = $col->getAlias();
68
69 1
            $col_name = $alias ?: $col->getName();
70
71 1
            $table = $col->getTable();
72
73 1
            $quoted_table_name = $table->getAlias()
74 1
                ? $this->driver->quoteName($table->getAlias())
75 1
                : $this->driver->quoteTableName($table->getSchema()->getName(), $table->getName());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $table->getSchema()->getName() targeting mindplay\sql\model\schema\Schema::getName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
76
77 1
            $column_expr = $quoted_table_name . '.' . $this->driver->quoteName($col->getName());
78
79 1
            $this->vars[$col_name] = $alias
80 1
                ? "{$column_expr} AS " . $this->driver->quoteName($col_name)
81 1
                : "{$column_expr}";
82
83 1
            $this->type_map[$col_name] = $col->getType();
84
        }
85
    }
86
87
    /**
88
     * Add an SQL expression to select and return
89
     *
90
     * @param $expr return expression
91
     * @param $name return variable name (optional, but usually required)
92
     * @param $type optional Type (or Type class-name)
0 ignored issues
show
Bug introduced by
The type mindplay\sql\model\components\optional was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
93
     */
94 1
    public function addValue(string $expr, string|null $name = null, Type|String|null $type = null): void
95
    {
96 1
        if (isset($this->vars[$name])) {
97
            throw new OutOfBoundsException("duplicate return variable name: {$name}");
98
        }
99
100 1
        if ($name === null) {
101 1
            if ($type !== null) {
102
                throw new UnexpectedValueException("type conversion requires a return-variable name");
103
            }
104
105 1
            $this->vars[] = "{$expr}";
106
        } else {
107 1
            $quoted_name = $this->driver->quoteName($name);
108
109 1
            $this->vars[$name] = "{$expr} AS {$quoted_name}";
110
111 1
            if ($type !== null) {
112 1
                $this->type_map[$name] = is_string($type)
113 1
                    ? $this->types->getType($type)
114
                    : $type; // assumes Type instance
115
            }
116
        }
117
    }
118
119 1
    public function createTypeMapper(): TypeMapper
120
    {
121 1
        $type_map = $this->type_map;
122
123 1
        if (count($this->vars) === 0) {
124
            // no defined return vars - buildReturnVars() will auto-select the root node, so
125
            // we need to add root Column Types to the TypeMapper we're creating here:
126
127 1
            $type_map = array_merge($this->createTypeMap($this->root), $type_map);
128
        }
129
130 1
        return new TypeMapper($type_map);
131
    }
132
133
    /**
134
     * @return bool true, if any return vars have been added
135
     */
136 1
    public function hasReturnVars(): bool
137
    {
138 1
        return count($this->vars) > 0;
139
    }
140
    
141
    /**
142
     * @return string comma-separated return expressions (for use in the SELECT or RETURNING clause of an SQL query)
143
     */
144 1
    public function buildReturnVars(): string
145
    {
146 1
        $vars = $this->vars;
147
148 1
        if (count($vars) === 0) {
149
            // no defined return vars - createTypeMapper() will create a Type-map for the root node,
150
            // so we need to auto-select the root node here:
151
152 1
            $vars[] = "{$this->root}.*";
153
        }
154
155 1
        return implode(",\n  ", $vars);
156
    }
157
158
    /**
159
     * Internally creates a full Type-map for all Columns in a given Table
160
     *
161
     * @param Table $table
162
     *
163
     * @return array<string,Type> map where Column Alias maps to Type
164
     */
165 1
    private function createTypeMap(Table $table): array
166
    {
167 1
        $type_map = [];
168
169 1
        foreach ($table->listColumns() as $column) {
170 1
            $type_map[$column->getAlias() ?: $column->getName()] = $column->getType();
171
        }
172
173 1
        return $type_map;
174
    }
175
}
176