package db import ( "fmt" "strconv" "strings" "gitea.dwysokinski.me/twhelp/sessions/cmd/sessions/internal" "gitea.dwysokinski.me/twhelp/sessions/internal/bundb/migrations" "github.com/urfave/cli/v2" "go.uber.org/zap" ) func New() *cli.Command { return &cli.Command{ Name: "db", Usage: "Manages database migrations", Subcommands: []*cli.Command{ newMigrateCmd(), newRollbackCmd(), newCreateCmd(), newStatusCmd(), }, } } func newMigrateCmd() *cli.Command { return &cli.Command{ Name: "migrate", Usage: "Migrates database", Action: func(c *cli.Context) error { logger := zap.L() db, err := internal.NewBunDB() if err != nil { return fmt.Errorf("internal.NewBunDB: %w", err) } defer func() { _ = db.Close() }() migrator := migrations.NewMigrator(db) if err = migrator.Init(c.Context); err != nil { return fmt.Errorf("migrator.Init: %w", err) } group, err := migrator.Migrate(c.Context) if err != nil { return fmt.Errorf("migrator.Migrate: %w", err) } if group.ID == 0 { logger.Info("there are no new migrations to run") return nil } logger.Info("migrated to "+strconv.FormatInt(group.ID, 10), zap.Int64("id", group.ID)) return nil }, } } func newRollbackCmd() *cli.Command { return &cli.Command{ Name: "rollback", Usage: "Rollbacks the last migration group", Action: func(c *cli.Context) error { logger := zap.L() db, err := internal.NewBunDB() if err != nil { return fmt.Errorf("internal.NewBunDB: %w", err) } defer func() { _ = db.Close() }() migrator := migrations.NewMigrator(db) group, err := migrator.Rollback(c.Context) if err != nil { return fmt.Errorf("migrator.Rollback: %w", err) } if group.ID == 0 { logger.Info("there are no groups to roll back") return nil } logger.Info("rolled back "+strconv.FormatInt(group.ID, 10), zap.Int64("id", group.ID)) return nil }, } } func newCreateCmd() *cli.Command { return &cli.Command{ Name: "create", Usage: "Creates migration", Subcommands: []*cli.Command{ { Name: "go", Usage: "Creates Go migration", Action: func(c *cli.Context) error { logger := zap.L() migrator := migrations.NewMigrator(nil) mf, err := migrator.CreateGoMigration(c.Context, strings.Join(c.Args().Slice(), "_")) if err != nil { return fmt.Errorf("migrator.CreateGoMigration: %w", err) } logger.Info("created migration", zap.String("name", mf.Name), zap.String("path", mf.Path)) return nil }, }, { Name: "sql", Usage: "Creates SQL migration", Action: func(c *cli.Context) error { logger := zap.L() migrator := migrations.NewMigrator(nil) files, err := migrator.CreateSQLMigrations(c.Context, strings.Join(c.Args().Slice(), "_")) if err != nil { return fmt.Errorf("migrator.CreateSQLMigrations: %w", err) } for _, mf := range files { logger.Info("created migration", zap.String("name", mf.Name), zap.String("path", mf.Path)) } return nil }, }, }, } } func newStatusCmd() *cli.Command { return &cli.Command{ Name: "status", Usage: "Prints migrations status", Action: func(c *cli.Context) error { logger := zap.L() db, err := internal.NewBunDB() if err != nil { return fmt.Errorf("internal.NewBunDB: %w", err) } defer func() { _ = db.Close() }() migrator := migrations.NewMigrator(db) ms, err := migrator.MigrationsWithStatus(c.Context) if err != nil { return fmt.Errorf("migrator.MigrationsWithStatus: %w", err) } logger.Info("migrations: " + ms.String()) logger.Info("last migration group: " + ms.LastGroup().String()) logger.Info("unapplied: " + ms.Unapplied().String()) return nil }, } }