diff --git a/cli/cli.go b/cli/cli.go index 0f90cfb..775f057 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -2,45 +2,45 @@ package migratecli import ( "context" + "database/sql" "fmt" "gitea.auvem.com/go-toolkit/app" "gitea.auvem.com/go-toolkit/appcli" - "gitea.auvem.com/go-toolkit/dbx" "gitea.auvem.com/go-toolkit/migrate" "github.com/pressly/goose/v3" "github.com/urfave/cli/v3" ) // MigrateCmd returns the main migrate command. -func MigrateCmd(directDeps []*app.Module, childDeps []*app.Module) *cli.Command { +func MigrateCmd(sqlo *sql.DB, directDeps []*app.Module, childDeps []*app.Module) *cli.Command { return appcli.NewCommand(&cli.Command{ Name: "migrate", Usage: "Migrate the database", - Commands: AllSubcommands(childDeps...), + Commands: AllSubcommands(sqlo, childDeps...), }, directDeps...) } // AllSubcommands returns all subcommands of the migrate command. -func AllSubcommands(deps ...*app.Module) []*cli.Command { +func AllSubcommands(sqlo *sql.DB, deps ...*app.Module) []*cli.Command { return []*cli.Command{ - MigrateStatusCmd(deps...), - MigrateCreateCmd(deps...), - MigrateUpCmd(deps...), - MigrateUpToCmd(deps...), - MigrateDownCmd(deps...), - MigrateDownToCmd(deps...), - MigrateRedoCmd(deps...), + MigrateStatusCmd(sqlo, deps...), + MigrateCreateCmd(sqlo, deps...), + MigrateUpCmd(sqlo, deps...), + MigrateUpToCmd(sqlo, deps...), + MigrateDownCmd(sqlo, deps...), + MigrateDownToCmd(sqlo, deps...), + MigrateRedoCmd(sqlo, deps...), } } // MigrateStatusCmd returns a command to get database migration status. -func MigrateStatusCmd(deps ...*app.Module) *cli.Command { +func MigrateStatusCmd(sqlo *sql.DB, deps ...*app.Module) *cli.Command { return appcli.NewCommand(&cli.Command{ Name: "status", Usage: "Get database migration status", Action: func(ctx context.Context, cmd *cli.Command) error { - if err := goose.Status(dbx.SQLO(), migrate.MigrationsConfig().BasePath); err != nil { + if err := goose.Status(sqlo, migrate.MigrationsConfig().BasePath); err != nil { return fmt.Errorf("couldn't get migration status: %v", err) } @@ -50,7 +50,7 @@ func MigrateStatusCmd(deps ...*app.Module) *cli.Command { } // MigrateCreateCmd returns a command to create a new migration. -func MigrateCreateCmd(deps ...*app.Module) *cli.Command { +func MigrateCreateCmd(sqlo *sql.DB, deps ...*app.Module) *cli.Command { return appcli.NewCommand(&cli.Command{ Name: "create", Usage: "Create a new migration", @@ -70,7 +70,7 @@ func MigrateCreateCmd(deps ...*app.Module) *cli.Command { goose.SetSequential(sequential) } - if err := goose.Create(dbx.SQLO(), "migrations", cmd.StringArg("name"), cmd.StringArg("type")); err != nil { + if err := goose.Create(sqlo, "migrations", cmd.StringArg("name"), cmd.StringArg("type")); err != nil { return fmt.Errorf("couldn't create migration: %v", err) } @@ -80,12 +80,12 @@ func MigrateCreateCmd(deps ...*app.Module) *cli.Command { } // MigrateUpCmd returns a command to apply all available database migrations. -func MigrateUpCmd(deps ...*app.Module) *cli.Command { +func MigrateUpCmd(sqlo *sql.DB, deps ...*app.Module) *cli.Command { return appcli.NewCommand(&cli.Command{ Name: "up", Usage: "Apply all available database migrations", Action: func(ctx context.Context, cmd *cli.Command) error { - if err := goose.Up(dbx.SQLO(), migrate.MigrationsConfig().BasePath); err != nil { + if err := goose.Up(sqlo, migrate.MigrationsConfig().BasePath); err != nil { return fmt.Errorf("couldn't apply migrations: %v", err) } return nil @@ -94,7 +94,7 @@ func MigrateUpCmd(deps ...*app.Module) *cli.Command { } // MigrateUpToCmd returns a command to apply all available database migrations up to a specific version. -func MigrateUpToCmd(deps ...*app.Module) *cli.Command { +func MigrateUpToCmd(sqlo *sql.DB, deps ...*app.Module) *cli.Command { return appcli.NewCommand(&cli.Command{ Name: "up-to", Usage: "Apply all available database migrations up to a specific version", @@ -106,7 +106,7 @@ func MigrateUpToCmd(deps ...*app.Module) *cli.Command { }, Action: func(ctx context.Context, cmd *cli.Command) error { version := cmd.Int64("version") - if err := goose.UpTo(dbx.SQLO(), migrate.MigrationsConfig().BasePath, version); err != nil { + if err := goose.UpTo(sqlo, migrate.MigrationsConfig().BasePath, version); err != nil { return fmt.Errorf("couldn't apply migrations to target version %d: %v", version, err) } return nil @@ -115,12 +115,12 @@ func MigrateUpToCmd(deps ...*app.Module) *cli.Command { } // MigrateDownCmd returns a command to rollback the most recent database migration. -func MigrateDownCmd(deps ...*app.Module) *cli.Command { +func MigrateDownCmd(sqlo *sql.DB, deps ...*app.Module) *cli.Command { return appcli.NewCommand(&cli.Command{ Name: "down", Usage: "Rollback the most recent database migration", Action: func(ctx context.Context, cmd *cli.Command) error { - if err := goose.Down(dbx.SQLO(), migrate.MigrationsConfig().BasePath); err != nil { + if err := goose.Down(sqlo, migrate.MigrationsConfig().BasePath); err != nil { return fmt.Errorf("couldn't rollback migration: %v", err) } return nil @@ -129,7 +129,7 @@ func MigrateDownCmd(deps ...*app.Module) *cli.Command { } // MigrateDownToCmd returns a command to rollback all database migrations down to a specific version. -func MigrateDownToCmd(deps ...*app.Module) *cli.Command { +func MigrateDownToCmd(sqlo *sql.DB, deps ...*app.Module) *cli.Command { return appcli.NewCommand(&cli.Command{ Name: "down-to", Usage: "Rollback all database migrations down to a specific version", @@ -141,7 +141,7 @@ func MigrateDownToCmd(deps ...*app.Module) *cli.Command { }, Action: func(ctx context.Context, cmd *cli.Command) error { version := cmd.Int64("version") - if err := goose.DownTo(dbx.SQLO(), migrate.MigrationsConfig().BasePath, version); err != nil { + if err := goose.DownTo(sqlo, migrate.MigrationsConfig().BasePath, version); err != nil { return fmt.Errorf("couldn't rollback migrations to target version %d: %v", version, err) } return nil @@ -150,12 +150,12 @@ func MigrateDownToCmd(deps ...*app.Module) *cli.Command { } // MigrateRedoCmd returns a command to rollback the most recent database migration and reapply it. -func MigrateRedoCmd(deps ...*app.Module) *cli.Command { +func MigrateRedoCmd(sqlo *sql.DB, deps ...*app.Module) *cli.Command { return appcli.NewCommand(&cli.Command{ Name: "redo", Usage: "Rollback the most recent database migration and reapply it", Action: func(ctx context.Context, cmd *cli.Command) error { - if err := goose.Redo(dbx.SQLO(), migrate.MigrationsConfig().BasePath); err != nil { + if err := goose.Redo(sqlo, migrate.MigrationsConfig().BasePath); err != nil { return fmt.Errorf("couldn't redo migration: %v", err) } return nil diff --git a/cmd/cmd.go b/cmd/cmd.go index 39cdc2c..7dd1779 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -1,17 +1,17 @@ package migratecmd import ( + "database/sql" "fmt" "strconv" - "gitea.auvem.com/go-toolkit/dbx" "gitea.auvem.com/go-toolkit/migrate" "github.com/pressly/goose/v3" "github.com/spf13/cobra" ) // MigrateCmd returns the main migrate command. -func MigrateCmd() *cobra.Command { +func MigrateCmd(sqlo *sql.DB) *cobra.Command { cmd := &cobra.Command{ Use: "migrate", Short: "Migrate the database", @@ -20,31 +20,31 @@ func MigrateCmd() *cobra.Command { }, } - cmd.AddCommand(AllSubcommands()...) + cmd.AddCommand(AllSubcommands(sqlo)...) return cmd } // AllSubcommands returns all subcommands of the migrate command. -func AllSubcommands() []*cobra.Command { +func AllSubcommands(sqlo *sql.DB) []*cobra.Command { return []*cobra.Command{ - MigrateStatusCmd(), - MigrateCreateCmd(), - MigrateUpCmd(), - MigrateUpToCmd(), - MigrateDownCmd(), - MigrateDownToCmd(), - MigrateRedoCmd(), + MigrateStatusCmd(sqlo), + MigrateCreateCmd(sqlo), + MigrateUpCmd(sqlo), + MigrateUpToCmd(sqlo), + MigrateDownCmd(sqlo), + MigrateDownToCmd(sqlo), + MigrateRedoCmd(sqlo), } } // MigrateStatusCmd returns a command to get database migration status. -func MigrateStatusCmd() *cobra.Command { +func MigrateStatusCmd(sqlo *sql.DB) *cobra.Command { return &cobra.Command{ Use: "status", Short: "Get database migration status", Run: func(cmd *cobra.Command, args []string) { - if err := goose.Status(dbx.SQLO(), migrate.MigrationsConfig().BasePath); err != nil { + if err := goose.Status(sqlo, migrate.MigrationsConfig().BasePath); err != nil { fmt.Printf("Error: Couldn't get migration status: %v\n", err) return } @@ -53,7 +53,7 @@ func MigrateStatusCmd() *cobra.Command { } // MigrateCreateCmd returns a command to create a new migration. -func MigrateCreateCmd() *cobra.Command { +func MigrateCreateCmd(sqlo *sql.DB) *cobra.Command { cmd := &cobra.Command{ Use: "create [NAME] [TYPE]", Short: "Create a new migration", @@ -69,7 +69,7 @@ func MigrateCreateCmd() *cobra.Command { goose.SetSequential(sequential) } - if err := goose.Create(dbx.SQLO(), "migrations", args[0], args[1]); err != nil { + if err := goose.Create(sqlo, "migrations", args[0], args[1]); err != nil { fmt.Printf("Error: Couldn't create migration: %v\n", err) return } @@ -81,12 +81,12 @@ func MigrateCreateCmd() *cobra.Command { } // MigrateUpCmd returns a command to apply all available database migrations. -func MigrateUpCmd() *cobra.Command { +func MigrateUpCmd(sqlo *sql.DB) *cobra.Command { return &cobra.Command{ Use: "up", Short: "Apply all available database migrations", Run: func(cmd *cobra.Command, args []string) { - if err := goose.Up(dbx.SQLO(), migrate.MigrationsConfig().BasePath); err != nil { + if err := goose.Up(sqlo, migrate.MigrationsConfig().BasePath); err != nil { fmt.Printf("Error: Couldn't apply migrations: %v\n", err) return } @@ -95,7 +95,7 @@ func MigrateUpCmd() *cobra.Command { } // MigrateUpToCmd returns a command to apply all available database migrations up to a specific version. -func MigrateUpToCmd() *cobra.Command { +func MigrateUpToCmd(sqlo *sql.DB) *cobra.Command { return &cobra.Command{ Use: "up-to [VERSION]", Short: "Apply all available database migrations up to a specific version", @@ -107,7 +107,7 @@ func MigrateUpToCmd() *cobra.Command { return } - if err := goose.UpTo(dbx.SQLO(), migrate.MigrationsConfig().BasePath, version); err != nil { + if err := goose.UpTo(sqlo, migrate.MigrationsConfig().BasePath, version); err != nil { fmt.Printf("Error: Couldn't apply migrations to target version %d: %v\n", version, err) return } @@ -116,12 +116,12 @@ func MigrateUpToCmd() *cobra.Command { } // MigrateDownCmd returns a command to rollback the most recent database migration. -func MigrateDownCmd() *cobra.Command { +func MigrateDownCmd(sqlo *sql.DB) *cobra.Command { return &cobra.Command{ Use: "down", Short: "Rollback the most recent database migration", Run: func(cmd *cobra.Command, args []string) { - if err := goose.Down(dbx.SQLO(), migrate.MigrationsConfig().BasePath); err != nil { + if err := goose.Down(sqlo, migrate.MigrationsConfig().BasePath); err != nil { fmt.Printf("Error: Couldn't rollback migration: %v\n", err) return } @@ -130,7 +130,7 @@ func MigrateDownCmd() *cobra.Command { } // MigrateDownToCmd returns a command to rollback all database migrations down to a specific version. -func MigrateDownToCmd() *cobra.Command { +func MigrateDownToCmd(sqlo *sql.DB) *cobra.Command { return &cobra.Command{ Use: "down-to [VERSION]", Short: "Rollback all database migrations down to a specific version", @@ -142,7 +142,7 @@ func MigrateDownToCmd() *cobra.Command { return } - if err := goose.DownTo(dbx.SQLO(), migrate.MigrationsConfig().BasePath, version); err != nil { + if err := goose.DownTo(sqlo, migrate.MigrationsConfig().BasePath, version); err != nil { fmt.Printf("Error: Couldn't rollback migrations to target version %d: %v\n", version, err) return } @@ -151,12 +151,12 @@ func MigrateDownToCmd() *cobra.Command { } // MigrateRedoCmd returns a command to rollback the most recent database migration and reapply it. -func MigrateRedoCmd() *cobra.Command { +func MigrateRedoCmd(sqlo *sql.DB) *cobra.Command { return &cobra.Command{ Use: "redo", Short: "Rollback the most recent database migration and reapply it", Run: func(cmd *cobra.Command, args []string) { - if err := goose.Redo(dbx.SQLO(), migrate.MigrationsConfig().BasePath); err != nil { + if err := goose.Redo(sqlo, migrate.MigrationsConfig().BasePath); err != nil { fmt.Printf("Error: Couldn't redo migration: %v\n", err) return } diff --git a/migrate.go b/migrate.go index daf2c89..39ba38e 100644 --- a/migrate.go +++ b/migrate.go @@ -2,6 +2,7 @@ package migrate import ( "context" + "database/sql" "io/fs" "log/slog" "time" @@ -13,6 +14,13 @@ import ( // MigrationsOpts define the options for the migrations module. type MigrationOpts struct { + // SQLO is the SQL database handle used for migrations. REQUIRED. + SQLO *sql.DB + + // Dialect is the database dialect used for migrations (e.g., "mysql", "postgres"). + // REQUIRED. Must match the dialect used in dbx. + Dialect goose.Dialect + // FS is the filesystem where migration files are stored. FS fs.FS @@ -82,6 +90,9 @@ func ModuleMigrations(cfg MigrationOpts) *app.Module { panic("ModuleMigrations initialized multiple times") } + if cfg.SQLO == nil { + panic("Migration SQL handle (SQLO) must be set in the configuration") + } if cfg.BasePath == "" { cfg.BasePath = "." // default base path if not set } @@ -121,13 +132,13 @@ func ModuleAutoMigrate(enabled bool) *app.Module { func setupMigrations(_ *app.Module) error { var err error - if err := goose.SetDialect("mysql"); err != nil { + if err := goose.SetDialect(string(migrationsConfig.Dialect)); err != nil { slog.Error("Couldn't set database dialect for goose", "err", err) return err } // Initialize the goose migration provider - Migration, err = goose.NewProvider(goose.DialectMySQL, dbx.SQLO(), migrationsConfig.FS) + Migration, err = goose.NewProvider(migrationsConfig.Dialect, migrationsConfig.SQLO, migrationsConfig.FS) if err != nil { slog.Error("Couldn't initialize goose migration provider", "err", err) return err