Passed
Pull Request — master (#483)
by
unknown
03:01
created

PartitionDefinition::parse()   D

Complexity

Conditions 20
Paths 4

Size

Total Lines 107
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 54
CRAP Score 20

Importance

Changes 0
Metric Value
cc 20
eloc 49
nc 4
nop 3
dl 0
loc 107
ccs 54
cts 54
cp 1
crap 20
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\SqlParser\Components;
6
7
use PhpMyAdmin\SqlParser\Component;
8
use PhpMyAdmin\SqlParser\Parser;
9
use PhpMyAdmin\SqlParser\Token;
10
use PhpMyAdmin\SqlParser\TokensList;
11
12
use function implode;
13
use function trim;
14
15
/**
16
 * Parses the create definition of a partition.
17
 *
18
 * Used for parsing `CREATE TABLE` statement.
19
 */
20
final class PartitionDefinition implements Component
21
{
22
    /**
23
     * All field options.
24
     *
25
     * @var array<string, int|array<int, int|string>>
26
     * @psalm-var array<string, (positive-int|array{positive-int, ('var'|'var='|'expr'|'expr=')})>
27
     */
28
    public static $partitionOptions = [
29
        'STORAGE ENGINE' => [
30
            1,
31
            'var',
32
        ],
33
        'ENGINE' => [
34
            1,
35
            'var',
36
        ],
37
        'COMMENT' => [
38
            2,
39
            'var',
40
        ],
41
        'DATA DIRECTORY' => [
42
            3,
43
            'var',
44
        ],
45
        'INDEX DIRECTORY' => [
46
            4,
47
            'var',
48
        ],
49
        'MAX_ROWS' => [
50
            5,
51
            'var',
52
        ],
53
        'MIN_ROWS' => [
54
            6,
55
            'var',
56
        ],
57
        'TABLESPACE' => [
58
            7,
59
            'var',
60
        ],
61
        'NODEGROUP' => [
62
            8,
63
            'var',
64
        ],
65
    ];
66
67
    /**
68
     * Whether this entry is a subpartition or a partition.
69
     *
70
     * @var bool
71
     */
72
    public $isSubpartition;
73
74
    /**
75
     * The name of this partition.
76
     *
77
     * @var string
78
     */
79
    public $name;
80
81
    /**
82
     * The type of this partition (what follows the `VALUES` keyword).
83
     *
84
     * @var string
85
     */
86
    public $type;
87
88
    /**
89
     * The expression used to defined this partition.
90
     *
91
     * @var Expression|string
92
     */
93
    public $expr;
94
95
    /**
96
     * The subpartitions of this partition.
97
     *
98
     * @var PartitionDefinition[]
99
     */
100
    public $subpartitions;
101
102
    /**
103
     * The options of this field.
104
     *
105
     * @var OptionsArray
106
     */
107
    public $options;
108
109
    /**
110
     * @param Parser               $parser  the parser that serves as context
111
     * @param TokensList           $list    the list of tokens that are being parsed
112
     * @param array<string, mixed> $options parameters for parsing
113
     *
114
     * @return PartitionDefinition
115
     */
116 24
    public static function parse(Parser $parser, TokensList $list, array $options = [])
117
    {
118 24
        $ret = new static();
119
120
        /**
121
         * The state of the parser.
122
         *
123
         * Below are the states of the parser.
124
         *
125
         *      0 -------------[ PARTITION | SUBPARTITION ]------------> 1
126
         *
127
         *      1 -----------------------[ name ]----------------------> 2
128
         *
129
         *      2 ----------------------[ VALUES ]---------------------> 3
130
         *
131
         *      3 ---------------------[ LESS THAN ]-------------------> 4
132
         *      3 ------------------------[ IN ]-----------------------> 4
133
         *
134
         *      4 -----------------------[ expr ]----------------------> 5
135
         *
136
         *      5 ----------------------[ options ]--------------------> 6
137
         *
138
         *      6 ------------------[ subpartitions ]------------------> (END)
139
         *
140
         * @var int
141
         */
142 24
        $state = 0;
143
144 24
        for (; $list->idx < $list->count; ++$list->idx) {
145
            /**
146
             * Token parsed at this moment.
147
             */
148 24
            $token = $list->tokens[$list->idx];
149
150
            // End of statement.
151 24
            if ($token->type === Token::TYPE_DELIMITER) {
152 4
                break;
153
            }
154
155
            // Skipping whitespaces and comments.
156 24
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
157 24
                continue;
158
            }
159
160 24
            if ($state === 0) {
161 24
                $ret->isSubpartition = ($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'SUBPARTITION');
162 24
                $state = 1;
163 24
            } elseif ($state === 1) {
164 24
                $ret->name = $token->value;
165
166
                // Looking ahead for a 'VALUES' keyword.
167
                // Loop until the end of the partition name (delimited by a whitespace)
168 24
                while ($nextToken = $list->tokens[++$list->idx]) {
169 24
                    if ($nextToken->type !== Token::TYPE_NONE) {
170 24
                        break;
171
                    }
172
173 2
                    $ret->name .= $nextToken->value;
174
                }
175
176 24
                $idx = $list->idx--;
177
                // Get the first token after the white space.
178 24
                $nextToken = $list->tokens[++$idx];
179
180 24
                $state = ($nextToken->type === Token::TYPE_KEYWORD)
181 24
                    && ($nextToken->value === 'VALUES')
182 24
                    ? 2 : 5;
183 24
            } elseif ($state === 2) {
184 22
                $state = 3;
185 24
            } elseif ($state === 3) {
186 22
                $ret->type = $token->value;
187 22
                $state = 4;
188 24
            } elseif ($state === 4) {
189 22
                if ($token->value === 'MAXVALUE') {
190 14
                    $ret->expr = $token->value;
191
                } else {
192 22
                    $ret->expr = Expression::parse(
193 22
                        $parser,
194 22
                        $list,
195 22
                        [
196 22
                            'parenthesesDelimited' => true,
197 22
                            'breakOnAlias' => true,
198 22
                        ]
199 22
                    );
200
                }
201
202 22
                $state = 5;
203 22
            } elseif ($state === 5) {
204 22
                $ret->options = OptionsArray::parse($parser, $list, static::$partitionOptions);
205 22
                $state = 6;
206 20
            } elseif ($state === 6) {
207 20
                if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
208 10
                    $ret->subpartitions = ArrayObj::parse(
0 ignored issues
show
Documentation Bug introduced by
It seems like PhpMyAdmin\SqlParser\Com...'type' => self::class)) of type PhpMyAdmin\SqlParser\Com...ser\Components\ArrayObj is incompatible with the declared type PhpMyAdmin\SqlParser\Com...s\PartitionDefinition[] of property $subpartitions.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
209 10
                        $parser,
210 10
                        $list,
211 10
                        ['type' => self::class]
212 10
                    );
213 10
                    ++$list->idx;
214
                }
215
216 20
                break;
217
            }
218
        }
219
220 24
        --$list->idx;
221
222 24
        return $ret;
223
    }
224
225
    /**
226
     * @param PartitionDefinition $component the component to be built
227
     */
228 8
    public static function build($component): string
229
    {
230 8
        if ($component->isSubpartition) {
231 4
            return trim('SUBPARTITION ' . $component->name . ' ' . $component->options);
232
        }
233
234 8
        $subpartitions = empty($component->subpartitions) ? '' : ' ' . self::buildAll($component->subpartitions);
235
236 8
        return trim(
237 8
            'PARTITION ' . $component->name
238 8
            . (empty($component->type) ? '' : ' VALUES ' . $component->type . ' ' . $component->expr . ' ')
239 8
            . (! empty($component->options) && ! empty($component->type) ? '' : ' ')
240 8
            . $component->options . $subpartitions
241 8
        );
242
    }
243
244
    /**
245
     * @param PartitionDefinition[] $component the component to be built
246
     */
247 8
    public static function buildAll(array $component): string
248
    {
249 8
        return "(\n" . implode(",\n", $component) . "\n)";
250
    }
251
252 8
    public function __toString(): string
253
    {
254 8
        return static::build($this);
255
    }
256
}
257