@@ -21,6 +21,23 @@ pub(crate) fn build_create_table_for_backend(
2121 . iter ( )
2222 . any ( |c| matches ! ( c, TableConstraint :: PrimaryKey { .. } ) ) ;
2323
24+ // Extract auto_increment columns from constraints
25+ let auto_increment_columns: std:: collections:: HashSet < & str > = constraints
26+ . iter ( )
27+ . filter_map ( |c| {
28+ if let TableConstraint :: PrimaryKey {
29+ columns : pk_cols,
30+ auto_increment : true ,
31+ } = c
32+ {
33+ Some ( pk_cols. iter ( ) . map ( |s| s. as_str ( ) ) . collect :: < Vec < _ > > ( ) )
34+ } else {
35+ None
36+ }
37+ } )
38+ . flatten ( )
39+ . collect ( ) ;
40+
2441 // Add columns
2542 for column in columns {
2643 let mut col = build_sea_column_def_with_table ( backend, table, column) ;
@@ -30,6 +47,11 @@ pub(crate) fn build_create_table_for_backend(
3047 col. primary_key ( ) ;
3148 }
3249
50+ // Apply auto_increment if this column is in the auto_increment primary key
51+ if auto_increment_columns. contains ( column. name . as_str ( ) ) {
52+ col. auto_increment ( ) ;
53+ }
54+
3355 // NOTE: We do NOT add inline unique constraints here.
3456 // All unique constraints are handled as separate CREATE UNIQUE INDEX statements
3557 // so they have proper names and can be dropped later.
@@ -502,4 +524,126 @@ mod tests {
502524 assert_snapshot!( sql) ;
503525 } ) ;
504526 }
527+
528+ #[ rstest]
529+ #[ case:: auto_increment_postgres( DatabaseBackend :: Postgres ) ]
530+ #[ case:: auto_increment_mysql( DatabaseBackend :: MySql ) ]
531+ #[ case:: auto_increment_sqlite( DatabaseBackend :: Sqlite ) ]
532+ fn test_create_table_with_auto_increment_primary_key ( #[ case] backend : DatabaseBackend ) {
533+ // Test that auto_increment on primary key generates SERIAL/AUTO_INCREMENT/AUTOINCREMENT
534+ let columns = vec ! [ ColumnDef {
535+ name: "id" . into( ) ,
536+ r#type: ColumnType :: Simple ( SimpleColumnType :: Integer ) ,
537+ nullable: false ,
538+ default : None ,
539+ comment: None ,
540+ primary_key: None ,
541+ unique: None ,
542+ index: None ,
543+ foreign_key: None ,
544+ } ] ;
545+ let constraints = vec ! [ TableConstraint :: PrimaryKey {
546+ auto_increment: true ,
547+ columns: vec![ "id" . into( ) ] ,
548+ } ] ;
549+
550+ let result = build_create_table ( & backend, "users" , & columns, & constraints) ;
551+ assert ! ( result. is_ok( ) ) ;
552+ let queries = result. unwrap ( ) ;
553+ let sql = queries
554+ . iter ( )
555+ . map ( |q| q. build ( backend) )
556+ . collect :: < Vec < String > > ( )
557+ . join ( ";\n " ) ;
558+
559+ // Verify auto_increment is applied correctly for each backend
560+ match backend {
561+ DatabaseBackend :: Postgres => {
562+ assert ! (
563+ sql. contains( "SERIAL" ) || sql. contains( "serial" ) ,
564+ "PostgreSQL should use SERIAL for auto_increment, got: {}" ,
565+ sql
566+ ) ;
567+ }
568+ DatabaseBackend :: MySql => {
569+ assert ! (
570+ sql. contains( "AUTO_INCREMENT" ) || sql. contains( "auto_increment" ) ,
571+ "MySQL should use AUTO_INCREMENT for auto_increment, got: {}" ,
572+ sql
573+ ) ;
574+ }
575+ DatabaseBackend :: Sqlite => {
576+ assert ! (
577+ sql. contains( "AUTOINCREMENT" ) || sql. contains( "autoincrement" ) ,
578+ "SQLite should use AUTOINCREMENT for auto_increment, got: {}" ,
579+ sql
580+ ) ;
581+ }
582+ }
583+
584+ with_settings ! ( { snapshot_suffix => format!( "create_table_with_auto_increment_{:?}" , backend) } , {
585+ assert_snapshot!( sql) ;
586+ } ) ;
587+ }
588+
589+ #[ rstest]
590+ #[ case:: inline_auto_increment_postgres( DatabaseBackend :: Postgres ) ]
591+ #[ case:: inline_auto_increment_mysql( DatabaseBackend :: MySql ) ]
592+ #[ case:: inline_auto_increment_sqlite( DatabaseBackend :: Sqlite ) ]
593+ fn test_create_table_with_inline_auto_increment_primary_key ( #[ case] backend : DatabaseBackend ) {
594+ // Test that inline primary_key with auto_increment generates correct SQL
595+ use vespertide_core:: schema:: primary_key:: { PrimaryKeyDef , PrimaryKeySyntax } ;
596+
597+ let columns = vec ! [ ColumnDef {
598+ name: "id" . into( ) ,
599+ r#type: ColumnType :: Simple ( SimpleColumnType :: Integer ) ,
600+ nullable: false ,
601+ default : None ,
602+ comment: None ,
603+ primary_key: Some ( PrimaryKeySyntax :: Object ( PrimaryKeyDef {
604+ auto_increment: true ,
605+ } ) ) ,
606+ unique: None ,
607+ index: None ,
608+ foreign_key: None ,
609+ } ] ;
610+
611+ let result = build_create_table ( & backend, "users" , & columns, & [ ] ) ;
612+ assert ! ( result. is_ok( ) ) ;
613+ let queries = result. unwrap ( ) ;
614+ let sql = queries
615+ . iter ( )
616+ . map ( |q| q. build ( backend) )
617+ . collect :: < Vec < String > > ( )
618+ . join ( ";\n " ) ;
619+
620+ // Verify auto_increment is applied correctly for each backend
621+ match backend {
622+ DatabaseBackend :: Postgres => {
623+ assert ! (
624+ sql. contains( "SERIAL" ) || sql. contains( "serial" ) ,
625+ "PostgreSQL should use SERIAL for auto_increment, got: {}" ,
626+ sql
627+ ) ;
628+ }
629+ DatabaseBackend :: MySql => {
630+ assert ! (
631+ sql. contains( "AUTO_INCREMENT" ) || sql. contains( "auto_increment" ) ,
632+ "MySQL should use AUTO_INCREMENT for auto_increment, got: {}" ,
633+ sql
634+ ) ;
635+ }
636+ DatabaseBackend :: Sqlite => {
637+ assert ! (
638+ sql. contains( "AUTOINCREMENT" ) || sql. contains( "autoincrement" ) ,
639+ "SQLite should use AUTOINCREMENT for auto_increment, got: {}" ,
640+ sql
641+ ) ;
642+ }
643+ }
644+
645+ with_settings ! ( { snapshot_suffix => format!( "create_table_with_inline_auto_increment_{:?}" , backend) } , {
646+ assert_snapshot!( sql) ;
647+ } ) ;
648+ }
505649}
0 commit comments