Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
127 / 127
100.00% covered (success)
100.00%
49 / 49
CRAP
100.00% covered (success)
100.00%
1 / 1
AbstractStructure
100.00% covered (success)
100.00%
127 / 127
100.00% covered (success)
100.00%
49 / 49
80
100.00% covered (success)
100.00%
1 / 1
 column
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getColumn
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 constraint
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getConstraint
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addColumn
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
2
 hasColumn
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addColumnAttribute
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 hasIncrement
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getIncrement
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
 hasPrimary
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getPrimary
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
 increment
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 defaultIs
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 nullable
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 notNullable
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 unsigned
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 index
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
7
 unique
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 primary
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 foreignKey
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 references
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 on
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 onDelete
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 integer
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 int
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 bigInt
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 mediumInt
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 smallInt
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 tinyInt
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 float
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 real
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 double
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 decimal
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 numeric
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 date
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 time
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 datetime
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 timestamp
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 year
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 text
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 tinyText
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 mediumText
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 longText
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 blob
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 mediumBlob
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 longBlob
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 char
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 varchar
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getColumnSchema
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Db\Sql\Schema;
15
16/**
17 * Schema abstract design table class for CREATE and ALTER
18 *
19 * @category   Pop
20 * @package    Pop\Db
21 * @author     Nick Sagona, III <dev@nolainteractive.com>
22 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
23 * @license    http://www.popphp.org/license     New BSD License
24 * @version    6.5.0
25 */
26abstract class AbstractStructure extends AbstractTable
27{
28
29    /**
30     * Columns to be added or modified
31     * @var array
32     */
33    protected array $columns = [];
34
35    /**
36     * Indices to be created
37     * @var array
38     */
39    protected array $indices = [];
40
41    /**
42     * Constraints to be added
43     * @var array
44     */
45    protected array $constraints = [];
46
47    /**
48     * Current column
49     * @var ?string
50     */
51    protected ?string $currentColumn = null;
52
53    /**
54     * Current constraint
55     * @var ?string
56     */
57    protected ?string $currentConstraint = null;
58
59    /**
60     * Set the current column
61     *
62     * @param  string $column
63     * @return AbstractStructure
64     */
65    public function column(string $column): AbstractStructure
66    {
67        $this->currentColumn = $column;
68        return $this;
69    }
70
71    /**
72     * Get the current column
73     *
74     * @return ?string
75     */
76    public function getColumn(): ?string
77    {
78        return $this->currentColumn;
79    }
80
81    /**
82     * Set the current constraint
83     *
84     * @param  string $constraint
85     * @return AbstractStructure
86     */
87    public function constraint(string $constraint): AbstractStructure
88    {
89        $this->currentConstraint = $constraint;
90        return $this;
91    }
92
93    /**
94     * Get the current constraint
95     *
96     * @return ?string
97     */
98    public function getConstraint(): ?string
99    {
100        return $this->currentConstraint;
101    }
102
103    /**
104     * Add a column
105     *
106     * @param  string $name
107     * @param  string $type
108     * @param  mixed  $size
109     * @param  mixed  $precision
110     * @param  array  $attributes
111     * @return AbstractStructure
112     */
113    public function addColumn(string $name, string $type, mixed $size = null, mixed $precision = null, array $attributes = []): AbstractStructure
114    {
115        $this->currentColumn  = $name;
116        $this->columns[$name] = [
117            'type'       => $type,
118            'size'       => $size,
119            'precision'  => $precision,
120            'nullable'   => null,
121            'default'    => null,
122            'increment'  => false,
123            'primary'    => false,
124            'unsigned'   => false,
125            'attributes' => (!empty($attributes)) ? $attributes : [],
126            'after'      => null
127        ];
128
129        return $this;
130    }
131
132    /**
133     * Determine if the table has a column
134     *
135     * @param  string $name
136     * @return bool
137     */
138    public function hasColumn(string $name): bool
139    {
140        return (isset($this->columns[$name]));
141    }
142
143    /**
144     * Add a custom column attribute
145     *
146     * @param  string $attribute
147     * @return AbstractStructure
148     */
149    public function addColumnAttribute(string $attribute): AbstractStructure
150    {
151        if ($this->currentColumn !== null) {
152            $this->columns[$this->currentColumn]['attributes'][] = $attribute;
153        }
154
155        return $this;
156    }
157
158    /**
159     * Determine if the table has an increment column
160     *
161     * @return bool
162     */
163    public function hasIncrement(): bool
164    {
165        $result = false;
166        foreach ($this->columns as $name => $column) {
167            if ($column['increment'] !== false) {
168                $result = true;
169            }
170        }
171        return $result;
172    }
173
174    /**
175     * Get the increment column(s)
176     *
177     * @param  bool $quote
178     * @return array
179     */
180    public function getIncrement(bool $quote = false): array
181    {
182        $result = [];
183        foreach ($this->columns as $name => $column) {
184            if ($column['increment'] !== false) {
185                $result[] = ($quote) ? $this->quoteId($name) : $name;
186            }
187        }
188        return $result;
189    }
190
191    /**
192     * Determine if the table has a primary key column
193     *
194     * @return bool
195     */
196    public function hasPrimary(): bool
197    {
198        $result = false;
199        foreach ($this->columns as $name => $column) {
200            if ($column['primary']) {
201                $result = true;
202            }
203        }
204        return $result;
205    }
206
207    /**
208     * Get the primary key column(s)
209     *
210     * @param  bool $quote
211     * @return array
212     */
213    public function getPrimary(bool$quote = false): array
214    {
215        $result = [];
216        foreach ($this->columns as $name => $column) {
217            if ($column['primary']) {
218                $result[] = ($quote) ? $this->quoteId($name) : $name;
219            }
220        }
221        return $result;
222    }
223
224    /**
225     * Set the current column as an increment column
226     *
227     * @param  int $start
228     * @return AbstractStructure
229     */
230    public function increment(int $start = 1): AbstractStructure
231    {
232        if ($this->currentColumn !== null) {
233            $this->columns[$this->currentColumn]['increment'] = $start;
234        }
235
236        return $this;
237    }
238
239    /**
240     * Set the current column's default value
241     *
242     * @param  mixed $value
243     * @return AbstractStructure
244     */
245    public function defaultIs(mixed $value): AbstractStructure
246    {
247        if ($this->currentColumn !== null) {
248            $this->columns[$this->currentColumn]['default'] = $value;
249            if ($value === null) {
250                $this->columns[$this->currentColumn]['nullable'] = true;
251            }
252        }
253
254        return $this;
255    }
256
257    /**
258     * Set the current column as nullable
259     *
260     * @return AbstractStructure
261     */
262    public function nullable(): AbstractStructure
263    {
264        if ($this->currentColumn !== null) {
265            $this->columns[$this->currentColumn]['nullable'] = true;
266        }
267
268        return $this;
269    }
270
271    /**
272     * Set the current column as NOT nullable
273     *
274     * @return AbstractStructure
275     */
276    public function notNullable(): AbstractStructure
277    {
278        if ($this->currentColumn !== null) {
279            $this->columns[$this->currentColumn]['nullable'] = false;
280        }
281
282        return $this;
283    }
284
285    /**
286     * Set the current column as unsigned
287     *
288     * @return AbstractStructure
289     */
290    public function unsigned(): AbstractStructure
291    {
292        if ($this->currentColumn !== null) {
293            $this->columns[$this->currentColumn]['unsigned'] = true;
294        }
295
296        return $this;
297    }
298
299    /**
300     * Create an index
301     *
302     * @param  string|array $column
303     * @param  ?string $name
304     * @param  string $type
305     * @return AbstractStructure
306     */
307    public function index(string|array $column, ?string $name = null, string $type = 'index'): AbstractStructure
308    {
309        if (!is_array($column)) {
310            $column = [$column];
311        }
312
313        foreach ($column as $c) {
314            if (isset($this->columns[$c]) && ($type == 'primary')) {
315                $this->columns[$c]['primary'] = true;
316            }
317        }
318
319        if ($name === null) {
320            $name = 'index';
321            foreach ($column as $c) {
322                $name .= '_' . strtolower((string)$c);
323            }
324        }
325        $this->indices[$name] = [
326            'column' => $column,
327            'type'   => $type
328        ];
329
330        return $this;
331    }
332
333    /**
334     * Create a UNIQUE index
335     *
336     * @param  string|array|null $column
337     * @param  ?string $name
338     * @return AbstractStructure
339     */
340    public function unique(string|array|null $column = null, ?string $name = null): AbstractStructure
341    {
342        if ($column === null) {
343            $column = $this->currentColumn;
344        }
345        return $this->index($column, $name, 'unique');
346    }
347
348    /**
349     * Create a PRIMARY KEY index
350     *
351     * @param  string|array|null $column
352     * @param  ?string $name
353     * @return AbstractStructure
354     */
355    public function primary(string|array|null $column = null, ?string $name = null): AbstractStructure
356    {
357        if ($column === null) {
358            $column = $this->currentColumn;
359        }
360        return $this->index($column, $name, 'primary');
361    }
362
363    /**
364     * Create a FOREIGN KEY constraint
365     *
366     * @param  string  $column
367     * @param  ?string $name
368     * @return AbstractStructure
369     */
370    public function foreignKey(string $column, ?string $name = null): AbstractStructure
371    {
372        if ($name === null) {
373            $name = 'fk_'. strtolower((string)$column);
374        }
375        $this->currentConstraint  = $name;
376        $this->constraints[$name] = [
377            'column'     => $column,
378            'references' => null,
379            'on'         => null,
380            'delete'     => 'SET NULL'
381        ];
382        return $this;
383    }
384
385    /**
386     * Assign FOREIGN KEY reference table
387     *
388     * @param  string $foreignTable
389     * @return AbstractStructure
390     */
391    public function references(string $foreignTable): AbstractStructure
392    {
393        if ($this->currentConstraint !== null) {
394            $this->constraints[$this->currentConstraint]['references'] = $foreignTable;
395        }
396
397        return $this;
398    }
399
400    /**
401     * Assign FOREIGN KEY reference table column
402     *
403     * @param  string $foreignColumn
404     * @return AbstractStructure
405     */
406    public function on(string $foreignColumn): AbstractStructure
407    {
408        if ($this->currentConstraint !== null) {
409            $this->constraints[$this->currentConstraint]['on'] = $foreignColumn;
410        }
411
412        return $this;
413    }
414
415    /**
416     * Assign FOREIGN KEY ON DELETE action
417     *
418     * @param  ?string $action
419     * @return AbstractStructure
420     */
421    public function onDelete(?string $action = null): AbstractStructure
422    {
423        if ($this->currentConstraint !== null) {
424            $this->constraints[$this->currentConstraint]['delete'] = (strtolower((string)$action) == 'cascade') ?
425                'CASCADE' : 'SET NULL';
426        }
427
428        return $this;
429    }
430
431    /*
432     * INTEGER TYPES
433     */
434
435    /**
436     * Add an INTEGER column
437     *
438     * @param  string $name
439     * @param  mixed  $size
440     * @param  array  $attributes
441     * @return AbstractStructure
442     */
443    public function integer(string $name, mixed $size = null, array $attributes = []): AbstractStructure
444    {
445        return $this->addColumn($name, 'integer', $size, null, $attributes);
446    }
447
448    /**
449     * Add an INT column
450     *
451     * @param  string $name
452     * @param  mixed  $size
453     * @param  array  $attributes
454     * @return AbstractStructure
455     */
456    public function int(string $name, mixed $size = null, array $attributes = []): AbstractStructure
457    {
458        return $this->addColumn($name, 'int', $size, null, $attributes);
459    }
460
461    /**
462     * Add a BIGINT column
463     *
464     * @param  string $name
465     * @param  mixed  $size
466     * @param  array  $attributes
467     * @return AbstractStructure
468     */
469    public function bigInt(string $name, mixed $size = null, array $attributes = []): AbstractStructure
470    {
471        return $this->addColumn($name, 'bigint', $size, null, $attributes);
472    }
473
474    /**
475     * Add a MEDIUMINT column
476     *
477     * @param  string $name
478     * @param  mixed  $size
479     * @param  array  $attributes
480     * @return AbstractStructure
481     */
482    public function mediumInt(string $name, mixed $size = null, array $attributes = []): AbstractStructure
483    {
484        return $this->addColumn($name, 'mediumint', $size, null, $attributes);
485    }
486
487    /**
488     * Add a SMALLINT column
489     *
490     * @param  string $name
491     * @param  mixed  $size
492     * @param  array  $attributes
493     * @return AbstractStructure
494     */
495    public function smallInt(string $name, mixed $size = null, array $attributes = []): AbstractStructure
496    {
497        return $this->addColumn($name, 'smallint', $size, null, $attributes);
498    }
499
500    /**
501     * Add a TINYINT column
502     *
503     * @param  string $name
504     * @param  mixed  $size
505     * @param  array  $attributes
506     * @return AbstractStructure
507     */
508    public function tinyInt(string $name, mixed $size = null, array $attributes = []): AbstractStructure
509    {
510        return $this->addColumn($name, 'tinyint', $size, null, $attributes);
511    }
512
513    /*
514     * NUMERIC TYPES
515     */
516
517    /**
518     * Add a FLOAT column
519     *
520     * @param  string $name
521     * @param  mixed  $size
522     * @param  mixed  $precision
523     * @param  array  $attributes
524     * @return AbstractStructure
525     */
526    public function float(string $name, mixed $size = null, mixed $precision = null, array $attributes = []): AbstractStructure
527    {
528        return $this->addColumn($name, 'float', $size, $precision, $attributes);
529    }
530
531    /**
532     * Add a REAL column
533     *
534     * @param  string $name
535     * @param  mixed  $size
536     * @param  mixed  $precision
537     * @param  array  $attributes
538     * @return AbstractStructure
539     */
540    public function real(string $name, mixed $size = null, mixed $precision = null, array $attributes = []): AbstractStructure
541    {
542        return $this->addColumn($name, 'real', $size, $precision, $attributes);
543    }
544
545    /**
546     * Add a DOUBLE column
547     *
548     * @param  string $name
549     * @param  mixed  $size
550     * @param  mixed  $precision
551     * @param  array  $attributes
552     * @return AbstractStructure
553     */
554    public function double(string $name, mixed $size = null, mixed $precision = null, array $attributes = []): AbstractStructure
555    {
556        return $this->addColumn($name, 'double', $size, $precision, $attributes);
557    }
558
559    /**
560     * Add a DECIMAL column
561     *
562     * @param  string $name
563     * @param  mixed  $size
564     * @param  mixed  $precision
565     * @param  array  $attributes
566     * @return AbstractStructure
567     */
568    public function decimal(string $name, mixed $size = null, mixed $precision = null, array $attributes = []): AbstractStructure
569    {
570        return $this->addColumn($name, 'decimal', $size, $precision, $attributes);
571    }
572
573    /**
574     * Add a NUMERIC column
575     *
576     * @param  string $name
577     * @param  mixed  $size
578     * @param  mixed  $precision
579     * @param  array  $attributes
580     * @return AbstractStructure
581     */
582    public function numeric(string $name, mixed $size = null, mixed $precision = null, array $attributes = []): AbstractStructure
583    {
584        return $this->addColumn($name, 'numeric', $size, $precision, $attributes);
585    }
586
587    /*
588     * DATE & TIME TYPES
589     */
590
591    /**
592     * Add a DATE column
593     *
594     * @param  string $name
595     * @param  array  $attributes
596     * @return AbstractStructure
597     */
598    public function date(string $name, array $attributes = []): AbstractStructure
599    {
600        return $this->addColumn($name, 'date', null, null, $attributes);
601    }
602
603    /**
604     * Add a TIME column
605     *
606     * @param  string $name
607     * @param  array  $attributes
608     * @return AbstractStructure
609     */
610    public function time(string $name, array $attributes = []): AbstractStructure
611    {
612        return $this->addColumn($name, 'time', null, null, $attributes);
613    }
614
615    /**
616     * Add a DATETIME column
617     *
618     * @param  string $name
619     * @param  array  $attributes
620     * @return AbstractStructure
621     */
622    public function datetime(string $name, array $attributes = []): AbstractStructure
623    {
624        return $this->addColumn($name, 'datetime', null, null, $attributes);
625    }
626
627    /**
628     * Add a TIMESTAMP column
629     *
630     * @param  string $name
631     * @param  array  $attributes
632     * @return AbstractStructure
633     */
634    public function timestamp(string $name, array $attributes = []): AbstractStructure
635    {
636        return $this->addColumn($name, 'timestamp', null, null, $attributes);
637    }
638
639    /**
640     * Add a YEAR column
641     *
642     * @param  string $name
643     * @param  mixed  $size
644     * @param  array  $attributes
645     * @return AbstractStructure
646     */
647    public function year(string $name, mixed $size = null, array $attributes = []): AbstractStructure
648    {
649        return $this->addColumn($name, 'year', $size, null, $attributes);
650    }
651
652    /*
653     * CHARACTER TYPES
654     */
655
656    /**
657     * Add a TEXT column
658     *
659     * @param  string $name
660     * @param  array  $attributes
661     * @return AbstractStructure
662     */
663    public function text(string $name, array $attributes = []): AbstractStructure
664    {
665        return $this->addColumn($name, 'text', null, null, $attributes);
666    }
667
668    /**
669     * Add a TINYTEXT column
670     *
671     * @param  string $name
672     * @param  array  $attributes
673     * @return AbstractStructure
674     */
675    public function tinyText(string $name, array $attributes = []): AbstractStructure
676    {
677        return $this->addColumn($name, 'tinytext', null, null, $attributes);
678    }
679
680    /**
681     * Add a MEDIUMTEXT column
682     *
683     * @param  string $name
684     * @param  array  $attributes
685     * @return AbstractStructure
686     */
687    public function mediumText(string $name, array $attributes = []): AbstractStructure
688    {
689        return $this->addColumn($name, 'mediumtext', null, null, $attributes);
690    }
691
692    /**
693     * Add a LONGTEXT column
694     *
695     * @param  string $name
696     * @param  array  $attributes
697     * @return AbstractStructure
698     */
699    public function longText(string $name, array $attributes = []): AbstractStructure
700    {
701        return $this->addColumn($name, 'longtext', null, null, $attributes);
702    }
703
704    /**
705     * Add a BLOB column
706     *
707     * @param  string $name
708     * @param  array  $attributes
709     * @return AbstractStructure
710     */
711    public function blob(string $name, array $attributes = []): AbstractStructure
712    {
713        return $this->addColumn($name, 'blob', null, null, $attributes);
714    }
715
716    /**
717     * Add a MEDIUMBLOB column
718     *
719     * @param  string $name
720     * @param  array  $attributes
721     * @return AbstractStructure
722     */
723    public function mediumBlob(string $name, array $attributes = []): AbstractStructure
724    {
725        return $this->addColumn($name, 'mediumblob', null, null, $attributes);
726    }
727
728    /**
729     * Add a LONGBLOB column
730     *
731     * @param  string $name
732     * @param  array  $attributes
733     * @return AbstractStructure
734     */
735    public function longBlob(string $name, array $attributes = []): AbstractStructure
736    {
737        return $this->addColumn($name, 'longblob', null, null, $attributes);
738    }
739
740    /**
741     * Add a CHAR column
742     *
743     * @param  string $name
744     * @param  int    $size
745     * @param  array  $attributes
746     * @return AbstractStructure
747     */
748    public function char(string $name, mixed $size = null, array $attributes = []): AbstractStructure
749    {
750        return $this->addColumn($name, 'char', $size, null, $attributes);
751    }
752
753    /**
754     * Add a VARCHAR column
755     *
756     * @param  string $name
757     * @param  int    $size
758     * @param  array  $attributes
759     * @return AbstractStructure
760     */
761    public function varchar(string $name, mixed $size = null, array $attributes = []): AbstractStructure
762    {
763        return $this->addColumn($name, 'varchar', $size, null, $attributes);
764    }
765
766    /**
767     * Format column schema
768     *
769     * @param  string $name
770     * @param  array $column
771     * @return string
772     */
773    protected function getColumnSchema($name, array $column): string
774    {
775        return Formatter\Column::getColumnSchema($this->getDbType(), $this->quoteId($name), $column, $this->table);
776    }
777
778}