Passed
Push — 2.x ( 749fd6...811329 )
by Aleksei
20:07
created

SQLiteColumn   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 230
Duplicated Lines 0 %

Test Coverage

Coverage 98%

Importance

Changes 0
Metric Value
eloc 110
dl 0
loc 230
ccs 49
cts 50
cp 0.98
rs 10
c 0
b 0
f 0
wmc 21

5 Methods

Rating   Name   Duplication   Size   Complexity  
A quoteEnum() 0 3 1
C createInstance() 0 83 13
A getAbstractType() 0 7 3
A sqlStatement() 0 15 3
A isEnum() 0 3 1
1
<?php
2
3
/**
4
 * This file is part of Cycle ORM package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Database\Driver\SQLite\Schema;
13
14
use Cycle\Database\Driver\DriverInterface;
15
use Cycle\Database\Schema\AbstractColumn;
0 ignored issues
show
Bug introduced by
The type Cycle\Database\Schema\AbstractColumn 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...
16
17
class SQLiteColumn extends AbstractColumn
18
{
19
    /**
20
     * Default timestamp expression (driver specific).
21
     */
22
    public const DATETIME_NOW = 'CURRENT_TIMESTAMP';
23
24
    /**
25
     * Private state related values.
26
     */
27
    public const EXCLUDE_FROM_COMPARE = [
28
        'userType',
29
        'timezone',
30
        'size',
31
        'attributes',
32
    ];
33
34
    protected array $mapping = [
35
        //Primary sequences
36
        'primary'     => [
37
            'type'       => 'integer',
38
            'primaryKey' => true,
39
            'nullable'   => false,
40
        ],
41
        'bigPrimary'  => [
42
            'type'       => 'integer',
43
            'primaryKey' => true,
44
            'nullable'   => false,
45
        ],
46
47
        //Enum type (mapped via method)
48
        'enum'        => 'enum',
49
50
        //Logical types
51
        'boolean'     => 'integer',
52
53
        //Integer types (size can always be changed with size method), longInteger has method alias
54
        //bigInteger
55
        'integer'     => 'integer',
56
        'tinyInteger' => 'tinyint',
57
        'smallInteger'=> 'smallint',
58
        'bigInteger'  => 'bigint',
59
60
        //String with specified length (mapped via method)
61
        'string'      => 'text',
62
63
        //Generic types
64
        'text'        => 'text',
65
        'tinyText'    => 'text',
66
        'longText'    => 'text',
67
68
        //Real types
69
        'double'      => 'double',
70
        'float'       => 'real',
71
72
        //Decimal type (mapped via method)
73
        'decimal'     => 'numeric',
74
75
        //Date and Time types
76
        'datetime'    => 'datetime',
77
        'date'        => 'date',
78
        'time'        => 'time',
79
        'timestamp'   => 'timestamp',
80
81
        //Binary types
82
        'binary'      => 'blob',
83
        'tinyBinary'  => 'blob',
84
        'longBinary'  => 'blob',
85
86
        //Additional types
87
        'json'        => 'text',
88
        'uuid'        => ['type' => 'varchar', 'size' => 36],
89
    ];
90
91
    protected array $reverseMapping = [
92
        'primary'     => [['type' => 'integer', 'primaryKey' => true]],
93
        'enum'        => ['enum'],
94
        'boolean'     => ['boolean'],
95
        'integer'     => ['int', 'integer', 'mediumint'],
96
        'tinyInteger' => ['tinyint'],
97
        'smallInteger'=> ['smallint'],
98
        'bigInteger'  => ['bigint'],
99
        'text'        => ['text', 'string'],
100
        'double'      => ['double'],
101
        'float'       => ['real'],
102
        'decimal'     => ['numeric'],
103
        'datetime'    => ['datetime'],
104
        'date'        => ['date'],
105
        'time'        => ['time'],
106
        'timestamp'   => ['timestamp'],
107
        'binary'      => ['blob'],
108
        'string'      => ['varchar'],
109
    ];
110
111
    /**
112
     * Indication that column is primary key.
113
     */
114
    protected bool $primaryKey = false;
115
116
    /**
117
     * DBMS specific reverse mapping must map database specific type into limited set of abstract
118
     * types.
119 476
     *
120
     * @psalm-return non-empty-string
121 476
     */
122 332
    public function getAbstractType(): string
123
    {
124
        if ($this->primaryKey && $this->type === 'integer') {
125 460
            return 'primary';
126
        }
127
128
        return parent::getAbstractType();
129
    }
130
131 476
    /**
132
     * @psalm-return non-empty-string
133 476
     */
134 476
    public function sqlStatement(DriverInterface $driver): string
135 468
    {
136
        $statement = parent::sqlStatement($driver);
137
        if ($this->getAbstractType() !== 'enum') {
138 152
            return $statement;
139 152
        }
140 152
141
        $enumValues = [];
142
        foreach ($this->enumValues as $value) {
143 152
            $enumValues[] = $driver->quote($value);
144
        }
145 152
146
        $quoted = $driver->identifier($this->name);
0 ignored issues
show
Bug introduced by
The method identifier() does not exist on Cycle\Database\Driver\DriverInterface. It seems like you code against a sub-type of Cycle\Database\Driver\DriverInterface such as Cycle\Database\Driver\Driver. ( Ignorable by Annotation )

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

146
        /** @scrutinizer ignore-call */ 
147
        $quoted = $driver->identifier($this->name);
Loading history...
147
148
        return "$statement CHECK ({$quoted} IN (" . implode(', ', $enumValues) . '))';
149
    }
150
151 472
    /**
152
     * @psalm-param non-empty-string $table
153
     */
154
    public static function createInstance(
155
        string $table,
156 472
        array $schema,
157
        \DateTimeZone $timezone = null
158 472
    ): self {
159 472
        $column = new self($table, $schema['name'], $timezone);
160
161 472
        $column->nullable = !$schema['notnull'];
0 ignored issues
show
Bug Best Practice introduced by
The property nullable does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
162 328
        $column->type = \strtolower($schema['type']);
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
163
164
        if ((bool)$schema['pk'] && $column->type === 'integer') {
165
            $column->primaryKey = true;
166
        }
167
168 472
        /*
169
         * Normalizing default value.
170
         */
171 472
        $column->defaultValue = $schema['dflt_value'];
0 ignored issues
show
Bug Best Practice introduced by
The property defaultValue does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
172 472
173
        if (
174 178
            is_string($column->defaultValue)
175
            && preg_match('/^[\'""].*?[\'"]$/', $column->defaultValue)
176
        ) {
177
            $column->defaultValue = substr($column->defaultValue, 1, -1);
178 472
        }
179 472
180 472
        if (
181
            !preg_match(
182
                '/^(?P<type>[a-z]+) *(?:\((?P<options>[^\)]+)\))?/',
183
                $schema['type'],
184
                $matches
185
            )
186
        ) {
187
            //No type definition included
188
            return $column;
189 472
        }
190
191
        // reformatted type value
192 472
        $column->type = $matches['type'];
193 262
194
        //Fetching size options
195 262
        if (!empty($matches['options'])) {
196 14
            $options = explode(',', $matches['options']);
197 14
198
            if (count($options) > 1) {
199 252
                $column->precision = (int)$options[0];
0 ignored issues
show
Bug Best Practice introduced by
The property precision does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
200
                $column->scale = (int)$options[1];
0 ignored issues
show
Bug Best Practice introduced by
The property scale does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
201
            } else {
202
                $column->size = (int)$options[0];
0 ignored issues
show
Bug Best Practice introduced by
The property size does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
203 472
            }
204
        }
205 152
206
        if ($column->type === 'enum') {
207 152
            //Quoted column name
208
            $quoted = $schema['identifier'];
209
210 152
            foreach ($schema['table'] as $columnSchema) {
211 152
                //Looking for enum values in column definition code
212 152
                if (
213
                    preg_match(
214
                        "/{$quoted} +enum.*?CHECK *\\({$quoted} in \\((.*?)\\)\\)/i",
215
                        trim($columnSchema),
216 152
                        $matches
217 152
                    )
218
                ) {
219 152
                    $enumValues = explode(',', $matches[1]);
220
                    foreach ($enumValues as &$value) {
221 152
                        //Trimming values
222
                        if (preg_match("/^'?(.*?)'?$/", trim($value), $matches)) {
223
                            //In database: 'value'
224 152
                            $value = $matches[1];
225
                        }
226 152
227
                        unset($value);
228 152
                    }
229
                    unset($value);
230
231
                    $column->enumValues = $enumValues;
0 ignored issues
show
Bug Best Practice introduced by
The property enumValues does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
232
                }
233 472
            }
234
        }
235
236 152
        return $column;
237
    }
238 152
239
    protected function quoteEnum(DriverInterface $driver): string
240
    {
241
        return '';
242
    }
243
244
    protected static function isEnum(AbstractColumn $column): bool
245
    {
246
        return false;
247
    }
248
}
249