Passed
Push — master ( 6c3f09...c54108 )
by William
03:43
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 is_array;
14
use function trim;
15
16
/**
17
 * Parses the create definition of a partition.
18
 *
19
 * Used for parsing `CREATE TABLE` statement.
20
 */
21
final class PartitionDefinition implements Component
22
{
23
    /**
24
     * All field options.
25
     *
26
     * @var array<string, int|array<int, int|string>>
27
     * @psalm-var array<string, (positive-int|array{positive-int, ('var'|'var='|'expr'|'expr=')})>
28
     */
29
    public static $partitionOptions = [
30
        'STORAGE ENGINE' => [
31
            1,
32
            'var',
33
        ],
34
        'ENGINE' => [
35
            1,
36
            'var',
37
        ],
38
        'COMMENT' => [
39
            2,
40
            'var',
41
        ],
42
        'DATA DIRECTORY' => [
43
            3,
44
            'var',
45
        ],
46
        'INDEX DIRECTORY' => [
47
            4,
48
            'var',
49
        ],
50
        'MAX_ROWS' => [
51
            5,
52
            'var',
53
        ],
54
        'MIN_ROWS' => [
55
            6,
56
            'var',
57
        ],
58
        'TABLESPACE' => [
59
            7,
60
            'var',
61
        ],
62
        'NODEGROUP' => [
63
            8,
64
            'var',
65
        ],
66
    ];
67
68
    /**
69
     * Whether this entry is a subpartition or a partition.
70
     *
71
     * @var bool
72
     */
73
    public $isSubpartition;
74
75
    /**
76
     * The name of this partition.
77
     *
78
     * @var string
79
     */
80
    public $name;
81
82
    /**
83
     * The type of this partition (what follows the `VALUES` keyword).
84
     *
85
     * @var string
86
     */
87
    public $type;
88
89
    /**
90
     * The expression used to defined this partition.
91
     *
92
     * @var Expression|string
93
     */
94
    public $expr;
95
96
    /**
97
     * The subpartitions of this partition.
98
     *
99
     * @var PartitionDefinition[]
100
     */
101
    public $subpartitions;
102
103
    /**
104
     * The options of this field.
105
     *
106
     * @var OptionsArray
107
     */
108
    public $options;
109
110
    /**
111
     * @param Parser               $parser  the parser that serves as context
112
     * @param TokensList           $list    the list of tokens that are being parsed
113
     * @param array<string, mixed> $options parameters for parsing
114
     *
115
     * @return PartitionDefinition
116
     */
117 24
    public static function parse(Parser $parser, TokensList $list, array $options = [])
118
    {
119 24
        $ret = new static();
120
121
        /**
122
         * The state of the parser.
123
         *
124
         * Below are the states of the parser.
125
         *
126
         *      0 -------------[ PARTITION | SUBPARTITION ]------------> 1
127
         *
128
         *      1 -----------------------[ name ]----------------------> 2
129
         *
130
         *      2 ----------------------[ VALUES ]---------------------> 3
131
         *
132
         *      3 ---------------------[ LESS THAN ]-------------------> 4
133
         *      3 ------------------------[ IN ]-----------------------> 4
134
         *
135
         *      4 -----------------------[ expr ]----------------------> 5
136
         *
137
         *      5 ----------------------[ options ]--------------------> 6
138
         *
139
         *      6 ------------------[ subpartitions ]------------------> (END)
140
         *
141
         * @var int
142
         */
143 24
        $state = 0;
144
145 24
        for (; $list->idx < $list->count; ++$list->idx) {
146
            /**
147
             * Token parsed at this moment.
148
             */
149 24
            $token = $list->tokens[$list->idx];
150
151
            // End of statement.
152 24
            if ($token->type === Token::TYPE_DELIMITER) {
153 4
                break;
154
            }
155
156
            // Skipping whitespaces and comments.
157 24
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
158 24
                continue;
159
            }
160
161 24
            if ($state === 0) {
162 24
                $ret->isSubpartition = ($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'SUBPARTITION');
163 24
                $state = 1;
164 24
            } elseif ($state === 1) {
165 24
                $ret->name = $token->value;
166
167
                // Looking ahead for a 'VALUES' keyword.
168
                // Loop until the end of the partition name (delimited by a whitespace)
169 24
                while ($nextToken = $list->tokens[++$list->idx]) {
170 24
                    if ($nextToken->type !== Token::TYPE_NONE) {
171 24
                        break;
172
                    }
173
174 2
                    $ret->name .= $nextToken->value;
175
                }
176
177 24
                $idx = $list->idx--;
178
                // Get the first token after the white space.
179 24
                $nextToken = $list->tokens[++$idx];
180
181 24
                $state = ($nextToken->type === Token::TYPE_KEYWORD)
182 24
                    && ($nextToken->value === 'VALUES')
183 24
                    ? 2 : 5;
184 24
            } elseif ($state === 2) {
185 22
                $state = 3;
186 24
            } elseif ($state === 3) {
187 22
                $ret->type = $token->value;
188 22
                $state = 4;
189 24
            } elseif ($state === 4) {
190 22
                if ($token->value === 'MAXVALUE') {
191 14
                    $ret->expr = $token->value;
192
                } else {
193 22
                    $ret->expr = Expression::parse(
194 22
                        $parser,
195 22
                        $list,
196 22
                        [
197 22
                            'parenthesesDelimited' => true,
198 22
                            'breakOnAlias' => true,
199 22
                        ]
200 22
                    );
201
                }
202
203 22
                $state = 5;
204 22
            } elseif ($state === 5) {
205 22
                $ret->options = OptionsArray::parse($parser, $list, static::$partitionOptions);
206 22
                $state = 6;
207 20
            } elseif ($state === 6) {
208 20
                if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
209 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...
210 10
                        $parser,
211 10
                        $list,
212 10
                        ['type' => self::class]
213 10
                    );
214 10
                    ++$list->idx;
215
                }
216
217 20
                break;
218
            }
219
        }
220
221 24
        --$list->idx;
222
223 24
        return $ret;
224
    }
225
226
    /**
227
     * @param PartitionDefinition|PartitionDefinition[] $component the component to be built
228
     * @param array<string, mixed>                      $options   parameters for building
229
     */
230 8
    public static function build($component, array $options = []): string
231
    {
232 8
        if (is_array($component)) {
233 8
            return "(\n" . implode(",\n", $component) . "\n)";
234
        }
235
236 8
        if ($component->isSubpartition) {
237 4
            return trim('SUBPARTITION ' . $component->name . ' ' . $component->options);
238
        }
239
240 8
        $subpartitions = empty($component->subpartitions) ? '' : ' ' . self::build($component->subpartitions);
241
242 8
        return trim(
243 8
            'PARTITION ' . $component->name
244 8
            . (empty($component->type) ? '' : ' VALUES ' . $component->type . ' ' . $component->expr . ' ')
245 8
            . (! empty($component->options) && ! empty($component->type) ? '' : ' ')
246 8
            . $component->options . $subpartitions
247 8
        );
248
    }
249
250 8
    public function __toString(): string
251
    {
252 8
        return static::build($this);
253
    }
254
}
255