Files
job-search/internal/cli/migrate/status.go
T
bwilliams 465358609a Naming, layout and comments: descriptive full-word names, one item per line in wrapped calls and literals, and doc comments on exported names
Short and single-letter names in application code become full words (tests
keep theirs). Wrapped calls, signatures and composite literals put one item
per line, and one-line function bodies are expanded. Exported names and
groups of constants get doc comments, and comments refer to the renamed
identifiers.
2026-10-15 16:12:56 +01:00

108 lines
2.6 KiB
Go

package migrate
import (
"context"
"errors"
"io"
"log/slog"
"path/filepath"
"text/tabwriter"
"github.com/pressly/goose/v3"
"github.com/spf13/cobra"
"git.avsdev.uk/Go/job-search/internal/cli"
"git.avsdev.uk/Go/job-search/internal/store"
)
// printStatus lists every migration as applied (with when) or pending,
// after a summary line, e.g.
//
// Database version 4 of 6 (2 pending)
// 1 applied 2026-10-07 10:12:01 00001_create_opportunities_table.sql
// ...
// 5 pending 00005_create_opportunity_classifications_table.sql
func printStatus(ctx context.Context, out io.Writer, migrator *goose.Provider) error {
statuses, err := migrator.Status(ctx)
if err != nil {
return err
}
current, err := migrator.GetDBVersion(ctx)
if err != nil {
return err
}
latest := store.LatestVersion(migrator)
pending := 0
for _, status := range statuses {
if status.State == goose.StatePending {
pending++
}
}
output := &errWriter{
w: out,
}
switch {
case current > latest:
output.printf(
"Database version %d is newer than this build (latest %d)\n",
current,
latest,
)
case pending == 0:
output.printf("Database version %d of %d (up-to-date)\n", current, latest)
default:
output.printf("Database version %d of %d (%d pending)\n", current, latest, pending)
}
if output.err != nil {
return output.err
}
table := tabwriter.NewWriter(out, 0, 0, 2, ' ', 0)
output = &errWriter{
w: table,
}
for _, status := range statuses {
applied := ""
if status.State == goose.StateApplied {
applied = status.AppliedAt.Local().Format("2006-01-02 15:04:05")
}
output.printf(
" %d\t%s\t%s\t%s\n",
status.Source.Version,
status.State,
applied,
filepath.Base(status.Source.Path),
)
}
return errors.Join(output.err, table.Flush())
}
func commandStatus(opts *cli.Options) *cobra.Command {
return &cobra.Command{
Use: "status",
Short: "Show which migrations have been applied to the SQLite database",
Args: cobra.NoArgs,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
slog.Debug("command persistent pre-run", "command", "migrate.status")
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
slog.Debug("command persistent post-run", "command", "migrate.status")
},
RunE: func(cmd *cobra.Command, args []string) (err error) {
slog.Debug("command run", "command", "migrate.status")
migrator, db, err := openMigrator(cmd, opts, false, false)
if err != nil {
return err
}
defer closeDB(db, &err)
return printStatus(cmd.Context(), cmd.OutOrStdout(), migrator)
},
}
}