Completed
Branch feature/pre-split (76ded7)
by Anton
03:22
created

ColumnSchema::sqlStatement()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 1
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\Database\Drivers\SQLite\Schemas;
8
9
use Spiral\Database\Entities\Driver;
10
use Spiral\Database\Schemas\Prototypes\AbstractColumn;
11
12
class ColumnSchema extends AbstractColumn
13
{
14
    /**
15
     * {@inheritdoc}
16
     */
17
    protected $mapping = [
18
        //Primary sequences
19
        'primary'     => [
20
            'type'       => 'integer',
21
            'primaryKey' => true,
22
            'nullable'   => false,
23
        ],
24
        'bigPrimary'  => [
25
            'type'       => 'integer',
26
            'primaryKey' => true,
27
            'nullable'   => false,
28
        ],
29
30
        //Enum type (mapped via method)
31
        'enum'        => 'enum',
32
33
        //Logical types
34
        'boolean'     => 'boolean',
35
36
        //Integer types (size can always be changed with size method), longInteger has method alias
37
        //bigInteger
38
        'integer'     => 'integer',
39
        'tinyInteger' => 'tinyint',
40
        'bigInteger'  => 'bigint',
41
42
        //String with specified length (mapped via method)
43
        'string'      => 'text',
44
45
        //Generic types
46
        'text'        => 'text',
47
        'tinyText'    => 'text',
48
        'longText'    => 'text',
49
50
        //Real types
51
        'double'      => 'double',
52
        'float'       => 'real',
53
54
        //Decimal type (mapped via method)
55
        'decimal'     => 'numeric',
56
57
        //Date and Time types
58
        'datetime'    => 'datetime',
59
        'date'        => 'date',
60
        'time'        => 'time',
61
        'timestamp'   => 'timestamp',
62
63
        //Binary types
64
        'binary'      => 'blob',
65
        'tinyBinary'  => 'blob',
66
        'longBinary'  => 'blob',
67
68
        //Additional types
69
        'json'        => 'text',
70
    ];
71
72
    /**
73
     * {@inheritdoc}
74
     */
75
    protected $reverseMapping = [
76
        'primary'     => [['type' => 'integer', 'primaryKey' => true]],
77
        'enum'        => ['enum'],
78
        'boolean'     => ['boolean'],
79
        'integer'     => ['int', 'integer', 'smallint', 'mediumint'],
80
        'tinyInteger' => ['tinyint'],
81
        'bigInteger'  => ['bigint'],
82
        'text'        => ['text', 'string'],
83
        'double'      => ['double'],
84
        'float'       => ['real'],
85
        'decimal'     => ['numeric'],
86
        'datetime'    => ['datetime'],
87
        'date'        => ['date'],
88
        'time'        => ['time'],
89
        'timestamp'   => ['timestamp'],
90
        'binary'      => ['blob'],
91
    ];
92
93
    /**
94
     * Indication that column is primary key.
95
     *
96
     * @var bool
97
     */
98
    private $primaryKey = false;
99
100
101
    /**
102
     * DBMS specific reverse mapping must map database specific type into limited set of abstract
103
     * types.
104
     *
105
     * @return string
106
     */
107
    public function abstractType(): string
108
    {
109
        if ($this->primaryKey) {
110
            return 'primary';
111
        }
112
113
        return parent::abstractType();
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function sqlStatement(Driver $driver): string
120
    {
121
        $statement = parent::sqlStatement($driver);
122
        if ($this->abstractType() != 'enum') {
123
            return $statement;
124
        }
125
126
        $enumValues = [];
127
        foreach ($this->enumValues as $value) {
128
            $enumValues[] = $driver->getPDO()->quote($value);
129
        }
130
131
        $quoted = $driver->getPDO()->quote($this->name);
132
133
        return "$statement CHECK ({$quoted} IN (" . implode(', ', $enumValues) . '))';
134
    }
135
136
    /**
137
     * Driver specific column initialization.s
138
     *
139
     * @param string $table Table name.
140
     * @param array  $schema
141
     *
142
     * @return self
143
     */
144
    public static function createInstance(string $table, array $schema): self
145
    {
146
        $column = new self($table, $schema['name']);
147
148
        $column->nullable = !$schema['notnull'];
149
        $column->type = $schema['type'];
150
        $column->primaryKey = (bool)$schema['pk'];
151
152
        /*
153
         * Normalizing default value.
154
         */
155
        $column->defaultValue = $schema['dflt_value'];
156
157
        if (preg_match('/^[\'""].*?[\'"]$/', $column->defaultValue)) {
158
            $column->defaultValue = substr($column->defaultValue, 1, -1);
159
        }
160
161
        if (!preg_match(
162
            '/^(?P<type>[a-z]+) *(?:\((?P<options>[^\)]+)\))?/',
163
            $schema['type'],
164
            $matches
165
        )
166
        ) {
167
            //No type definition included
168
            return $column;
169
        }
170
171
        //Reformatted type value
172
        $column->type = $matches['type'];
173
174
        //Fetching size options
175 View Code Duplication
        if (!empty($matches['options'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
176
            $options = explode(',', $matches['options']);
177
178
            if (count($options) > 1) {
179
                $column->precision = (int)$options[0];
180
                $column->scale = (int)$options[1];
181
            } else {
182
                $column->size = (int)$options[0];
183
            }
184
        }
185
186
        if ($column->type == 'enum') {
187
            //Quoted column name
188
            $quoted = $schema['quoted'];
189
190
            foreach ($schema['tableStatement'] as $column) {
191
                //Looking for enum values in column definition code
192
                if (preg_match(
193
                    "/{$quoted} +enum.*?CHECK *\\({$quoted} in \\((.*?)\\)\\)/i",
194
                    trim($column),
195
                    $matches
196
                )) {
197
                    $enumValues = explode(',', $matches[1]);
198
                    foreach ($enumValues as &$value) {
199
                        //Trimming values
200
                        if (preg_match("/^'?(.*?)'?$/", trim($value), $matches)) {
201
                            //In database: 'value'
202
                            $value = $matches[1];
203
                        }
204
205
                        unset($value);
206
                    }
207
208
                    $column->enumValues = $enumValues;
209
                }
210
            }
211
        }
212
213
        return $column;
214
    }
215
216
    /**
217
     * {@inheritdoc}
218
     */
219
    protected function prepareEnum(Driver $driver): string
220
    {
221
        return '';
222
    }
223
}