3333 * @method $this|AbstractColumn unsigned(bool $value)
3434 * @method $this|AbstractColumn zerofill(bool $value)
3535 * @method $this|AbstractColumn comment(string $value)
36+ * @method $this|AbstractColumn after(string $column)
3637 */
3738class MySQLColumn extends AbstractColumn
3839{
@@ -41,7 +42,7 @@ class MySQLColumn extends AbstractColumn
4142 */
4243 public const DATETIME_NOW = 'CURRENT_TIMESTAMP ' ;
4344
44- public const EXCLUDE_FROM_COMPARE = ['size ' , 'timezone ' , 'userType ' , 'attributes ' ];
45+ public const EXCLUDE_FROM_COMPARE = ['size ' , 'timezone ' , 'userType ' , 'attributes ' , ' first ' , ' after ' ];
4546 protected const INTEGER_TYPES = ['tinyint ' , 'smallint ' , 'mediumint ' , 'int ' , 'bigint ' ];
4647
4748 protected array $ mapping = [
@@ -184,6 +185,18 @@ class MySQLColumn extends AbstractColumn
184185 #[ColumnAttribute]
185186 protected string $ comment = '' ;
186187
188+ /**
189+ * Column name to position after.
190+ */
191+ #[ColumnAttribute]
192+ protected string $ after = '' ;
193+
194+ /**
195+ * Whether the column should be positioned first.
196+ */
197+ #[ColumnAttribute]
198+ protected bool $ first = false ;
199+
187200 /**
188201 * @psalm-param non-empty-string $table
189202 */
@@ -283,23 +296,30 @@ public static function createInstance(string $table, array $schema, ?\DateTimeZo
283296 public function sqlStatement (DriverInterface $ driver ): string
284297 {
285298 if (\in_array ($ this ->type , self ::INTEGER_TYPES , true )) {
286- return $ this ->sqlStatementInteger ($ driver );
287- }
299+ $ statement = $ this ->sqlStatementInteger ($ driver );
300+ } else {
301+ $ defaultValue = $ this ->defaultValue ;
288302
289- $ defaultValue = $ this ->defaultValue ;
303+ if (\in_array ($ this ->type , $ this ->forbiddenDefaults , true )) {
304+ // Flushing default value for forbidden types
305+ $ this ->defaultValue = null ;
306+ }
307+
308+ $ statement = parent ::sqlStatement ($ driver );
290309
291- if (\in_array ($ this ->type , $ this ->forbiddenDefaults , true )) {
292- //Flushing default value for forbidden types
293- $ this ->defaultValue = null ;
310+ $ this ->defaultValue = $ defaultValue ;
294311 }
295312
296- $ statement = parent :: sqlStatement ( $ driver) ;
313+ $ this -> comment === '' or $ statement .= " COMMENT { $ driver-> quote ( $ this -> comment )}" ;
297314
298- $ this ->defaultValue = $ defaultValue ;
315+ $ first = $ this ->first ;
316+ $ after = $ first ? '' : $ this ->after ;
299317
300- if ($ this ->comment !== '' ) {
301- return "{$ statement } COMMENT {$ driver ->quote ($ this ->comment )}" ;
302- }
318+ $ statement .= match (true ) {
319+ $ first => ' FIRST ' ,
320+ $ after !== '' => " AFTER {$ driver ->identifier ($ after )}" ,
321+ default => '' ,
322+ };
303323
304324 return $ statement ;
305325 }
@@ -325,6 +345,13 @@ public function isZerofill(): bool
325345 return $ this ->zerofill ;
326346 }
327347
348+ public function first (bool $ value = true ): self
349+ {
350+ $ this ->first = $ value ;
351+
352+ return $ this ;
353+ }
354+
328355 public function set (string |array $ values ): self
329356 {
330357 $ this ->type ('set ' );
@@ -395,12 +422,11 @@ protected function formatDatetime(
395422 private function sqlStatementInteger (DriverInterface $ driver ): string
396423 {
397424 return \sprintf (
398- '%s %s(%s)%s%s%s%s%s%s ' ,
425+ '%s %s(%s)%s%s%s%s%s ' ,
399426 $ driver ->identifier ($ this ->name ),
400427 $ this ->type ,
401428 $ this ->size ,
402429 $ this ->unsigned ? ' UNSIGNED ' : '' ,
403- $ this ->comment !== '' ? " COMMENT {$ driver ->quote ($ this ->comment )}" : '' ,
404430 $ this ->zerofill ? ' ZEROFILL ' : '' ,
405431 $ this ->nullable ? ' NULL ' : ' NOT NULL ' ,
406432 $ this ->defaultValue !== null ? " DEFAULT {$ this ->quoteDefault ($ driver )}" : '' ,
0 commit comments