Skip to content

Commit

Permalink
WIP.
Browse files Browse the repository at this point in the history
  • Loading branch information
efritz committed Sep 19, 2024
1 parent ef0d73f commit 5650198
Show file tree
Hide file tree
Showing 20 changed files with 436 additions and 288 deletions.
40 changes: 0 additions & 40 deletions cmd/migrate/describe.go

This file was deleted.

49 changes: 0 additions & 49 deletions cmd/migrate/drift.go

This file was deleted.

35 changes: 22 additions & 13 deletions cmd/migrate/create.go → cmd/migrate/internal/commands/create.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package commands

import (
"fmt"
Expand All @@ -7,27 +7,36 @@ import (
"regexp"
"strings"

"github.com/go-nacelle/log/v2"
"github.com/go-nacelle/pgutil"
"github.com/go-nacelle/pgutil/cmd/migrate/internal/flags"
"github.com/spf13/cobra"
)

var createCmd = &cobra.Command{
Use: "create [flags] 'migration name'",
Short: "Create a new schema migration",
Args: cobra.ExactArgs(1),
RunE: create,
}
func CreateCommand(logger log.Logger) *cobra.Command {
var (
migrationsDirectory string
)

createCmd := &cobra.Command{
Use: "create [flags] 'migration name'",
Short: "Create a new schema migration",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return create(migrationsDirectory, args[0])
},
}

func init() {
rootCmd.AddCommand(createCmd)
flags.RegisterMigrationsDirectoryFlag(createCmd, &migrationsDirectory)
return createCmd
}

func create(cmd *cobra.Command, args []string) error {
if err := ensureMigrationDirectoryExists(migrationDirectory); err != nil {
func create(migrationsDirectory string, name string) error {
if err := ensureMigrationDirectoryExists(migrationsDirectory); err != nil {
return err
}

definitions, err := pgutil.ReadMigrations(pgutil.NewFilesystemMigrationReader(migrationDirectory))
definitions, err := pgutil.ReadMigrations(pgutil.NewFilesystemMigrationReader(migrationsDirectory))
if err != nil {
return err
}
Expand All @@ -37,7 +46,7 @@ func create(cmd *cobra.Command, args []string) error {
lastID = definitions[len(definitions)-1].ID
}

dirPath := filepath.Join(migrationDirectory, fmt.Sprintf("%d_%s", lastID+1, canonicalize(args[0])))
dirPath := filepath.Join(migrationsDirectory, fmt.Sprintf("%d_%s", lastID+1, canonicalize(name)))
upPath := filepath.Join(dirPath, "up.sql")
downPath := filepath.Join(dirPath, "down.sql")

Expand Down
50 changes: 50 additions & 0 deletions cmd/migrate/internal/commands/describe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package commands

import (
"context"
"encoding/json"
"fmt"

"github.com/go-nacelle/log/v2"
"github.com/go-nacelle/pgutil"
"github.com/go-nacelle/pgutil/cmd/migrate/internal/database"
"github.com/go-nacelle/pgutil/cmd/migrate/internal/flags"
"github.com/spf13/cobra"
)

func DescribeCommand(logger log.Logger) *cobra.Command {
var (
databaseURL string
)

describeCmd := &cobra.Command{
Use: "describe",
Short: "Describe the current database schema",
RunE: func(cmd *cobra.Command, args []string) error {
return describe(databaseURL, logger)
},
}

flags.RegisterDatabaseURLFlag(describeCmd, &databaseURL)
return describeCmd
}

func describe(databaseURL string, logger log.Logger) error {
db, err := database.Dial(databaseURL, logger)
if err != nil {
return err
}

description, err := pgutil.DescribeSchema(context.Background(), db)
if err != nil {
return err
}

serialized, err := json.Marshal(description)
if err != nil {
return err
}

fmt.Printf("%s\n", serialized)
return nil
}
67 changes: 67 additions & 0 deletions cmd/migrate/internal/commands/drift.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package commands

import (
"context"
"encoding/json"
"fmt"
"os"

"github.com/go-nacelle/log/v2"
"github.com/go-nacelle/pgutil"
"github.com/go-nacelle/pgutil/cmd/migrate/internal/database"
"github.com/go-nacelle/pgutil/cmd/migrate/internal/flags"
"github.com/spf13/cobra"
)

func DriftCommand(logger log.Logger) *cobra.Command {
var (
databaseURL string
)

driftCmd := &cobra.Command{
Use: "drift",
Short: "Compare the current database schema against the expected schema",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return drift(databaseURL, logger, args[0])
},
}

flags.RegisterDatabaseURLFlag(driftCmd, &databaseURL)
return driftCmd
}

func drift(databaseURL string, logger log.Logger, filename string) error {
db, err := database.Dial(databaseURL, logger)
if err != nil {
return err
}

description, err := pgutil.DescribeSchema(context.Background(), db)
if err != nil {
return err
}

b, err := os.ReadFile(filename)
if err != nil {
return err
}

var expected pgutil.SchemaDescription
if err := json.Unmarshal(b, &expected); err != nil {
return err
}

statements := pgutil.Compare(expected, description)

if len(statements) == 0 {
fmt.Printf("No drift detected\n")
return nil
}

for _, d := range statements {
fmt.Printf("%s\n\n", d)
}

return nil
}
35 changes: 24 additions & 11 deletions cmd/migrate/state.go → cmd/migrate/internal/commands/state.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,40 @@
package main
package commands

import (
"context"
"fmt"
"strings"

"github.com/fatih/color"
"github.com/go-nacelle/log/v2"
"github.com/go-nacelle/pgutil"
"github.com/go-nacelle/pgutil/cmd/migrate/internal/database"
"github.com/go-nacelle/pgutil/cmd/migrate/internal/flags"
"github.com/spf13/cobra"
)

var stateCmd = &cobra.Command{
Use: "state",
Short: "Display the current state of the database schema",
RunE: state,
}
func StatCommand(logger log.Logger) *cobra.Command {
var (
databaseURL string
migrationsDirectory string
)

stateCmd := &cobra.Command{
Use: "state",
Short: "Display the current state of the database schema",
RunE: func(cmd *cobra.Command, args []string) error {
return state(databaseURL, migrationsDirectory, logger)
},
}

func init() {
rootCmd.AddCommand(stateCmd)
flags.RegisterDatabaseURLFlag(stateCmd, &databaseURL)
flags.RegisterMigrationsDirectoryFlag(stateCmd, &migrationsDirectory)
flags.RegisterNoColorFlag(stateCmd)
return stateCmd
}

func state(cmd *cobra.Command, args []string) error {
runner, err := runner()
func state(databaseURL, migrationsDirectory string, logger log.Logger) error {
runner, err := database.CreateRunner(databaseURL, migrationsDirectory, logger)
if err != nil {
return err
}
Expand Down Expand Up @@ -55,7 +68,7 @@ func state(cmd *cobra.Command, args []string) error {
color, statusEmoji, statusText := definitionStatus(log, exists)

color.Printf(
"%s %04d: %s\t%s\n",
"%s %04d: %s\t\t%s\n",
statusEmoji,
definition.ID,
definition.Name+strings.Repeat(" ", maxDefinitionLen-len(definition.Name)),
Expand Down
46 changes: 46 additions & 0 deletions cmd/migrate/internal/commands/undo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package commands

import (
"context"
"fmt"
"strconv"

"github.com/go-nacelle/log/v2"
"github.com/go-nacelle/pgutil/cmd/migrate/internal/database"
"github.com/go-nacelle/pgutil/cmd/migrate/internal/flags"
"github.com/spf13/cobra"
)

func UndoCommand(logger log.Logger) *cobra.Command {
var (
databaseURL string
migrationsDirectory string
)

undoCmd := &cobra.Command{
Use: "undo [migration_id]",
Short: "Undo migrations up to and including the specified migration ID",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
migrationID, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid migration ID: %v", err)
}

return undo(databaseURL, migrationsDirectory, logger, migrationID)
},
}

flags.RegisterDatabaseURLFlag(undoCmd, &databaseURL)
flags.RegisterMigrationsDirectoryFlag(undoCmd, &migrationsDirectory)
return undoCmd
}

func undo(databaseURL string, migrationsDirectory string, logger log.Logger, migrationID int) error {
runner, err := database.CreateRunner(databaseURL, migrationsDirectory, logger)
if err != nil {
return err
}

return runner.Undo(context.Background(), migrationID)
}
Loading

0 comments on commit 5650198

Please sign in to comment.