diff --git a/cmd/resolve.go b/cmd/resolve.go new file mode 100644 index 000000000..e67a5d5f9 --- /dev/null +++ b/cmd/resolve.go @@ -0,0 +1,34 @@ +package cmd + +import ( + "errors" + + "github.com/spf13/cobra" + "github.com/supabase/cli/internal/resolve" +) + +var ( + appliedTimestamp *string + rolledBackTimestamp *string + + resolveCmd = &cobra.Command{ + Use: "resolve", + Short: "Resolve issues with migration history on the deploy database.", + RunE: func(cmd *cobra.Command, args []string) error { + if appliedTimestamp != nil { + return resolve.ResolveApplied(*appliedTimestamp) + } else if rolledBackTimestamp != nil { + return resolve.ResolveRolledBack(*rolledBackTimestamp) + } else { + return errors.New("Must set either --applied or --rolled-back.") + } + }, + } +) + +func init() { + resolveCmd.Flags().StringVar(appliedTimestamp, "applied", "", "Migration timestamp to be recorded as applied.") + resolveCmd.Flags().StringVar(rolledBackTimestamp, "rolled-back", "", "Migration timestamp to be recorded as rolled back.") + + rootCmd.AddCommand(resolveCmd) +} diff --git a/internal/deploy/deploy.go b/internal/deploy/deploy.go index 978b71fe4..2f5a37449 100644 --- a/internal/deploy/deploy.go +++ b/internal/deploy/deploy.go @@ -24,7 +24,7 @@ func Deploy() error { } defer conn.Close(context.Background()) - rows, err := conn.Query(ctx, "SELECT version FROM supabase_migrations.schema_migrations") + rows, err := conn.Query(ctx, "SELECT version FROM supabase_migrations.schema_migrations ORDER BY version") if err != nil { return errors.New("❌ supabase_migrations.schema_migrations table does not exist.") } diff --git a/internal/link/link.go b/internal/link/link.go index 848229ac2..791ec8af6 100644 --- a/internal/link/link.go +++ b/internal/link/link.go @@ -123,7 +123,7 @@ func Link(url string) error { fmt.Println("Done pulling images.") // sync `migrations` - if rows, err := conn.Query(ctx, "SELECT version FROM supabase_migrations.schema_migrations"); err == nil { + if rows, err := conn.Query(ctx, "SELECT version FROM supabase_migrations.schema_migrations ORDER BY version"); err == nil { // supabase_migrations.schema_migrations exists. fmt.Println("supabase_migrations.schema_migrations exists on the deploy database.") diff --git a/internal/resolve/resolve.go b/internal/resolve/resolve.go new file mode 100644 index 000000000..9039830c5 --- /dev/null +++ b/internal/resolve/resolve.go @@ -0,0 +1,62 @@ +package resolve + +import ( + "context" + "errors" + "fmt" + "os" + + pgx "github.com/jackc/pgx/v4" +) + +var ctx = context.TODO() + +func ResolveApplied(timestamp string) error { + url := os.Getenv("SUPABASE_DEPLOY_DB_URL") + if url == "" { + return errors.New("❌ SUPABASE_DEPLOY_DB_URL is not set.") + } + + conn, err := pgx.Connect(ctx, url) + if err != nil { + return err + } + defer conn.Close(context.Background()) + + if _, err := conn.Query( + ctx, + "INSERT INTO supabase_migrations.schema_migrations(version) VALUES ($1)", + timestamp, + ); err != nil { + return err + } + + fmt.Println("Finished supabase resolve.") + + return nil +} + +func ResolveRolledBack(timestamp string) error { + url := os.Getenv("SUPABASE_DEPLOY_DB_URL") + if url == "" { + return errors.New("❌ SUPABASE_DEPLOY_DB_URL is not set.") + } + + conn, err := pgx.Connect(ctx, url) + if err != nil { + return err + } + defer conn.Close(context.Background()) + + if _, err := conn.Query( + ctx, + "DELETE FROM supabase_migrations.schema_migrations WHERE version = $1", + timestamp, + ); err != nil { + return err + } + + fmt.Println("Finished supabase resolve.") + + return nil +}