76 lines
2.2 KiB
Go
76 lines
2.2 KiB
Go
package migration
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
|
|
"github.com/go-errors/errors"
|
|
"github.com/jackc/pgconn"
|
|
"github.com/jackc/pgerrcode"
|
|
"github.com/jackc/pgx/v4"
|
|
"github.com/supabase/cli/pkg/pgxv5"
|
|
)
|
|
|
|
func ListRemoteMigrations(ctx context.Context, conn *pgx.Conn) ([]string, error) {
|
|
// We query the version string only for backwards compatibility
|
|
rows, _ := conn.Query(ctx, LIST_MIGRATION_VERSION)
|
|
versions, err := pgxv5.CollectStrings(rows)
|
|
if err != nil {
|
|
var pgErr *pgconn.PgError
|
|
if errors.As(err, &pgErr) && pgErr.Code == pgerrcode.UndefinedTable {
|
|
// If migration history table is undefined, the remote project has no migrations
|
|
return nil, nil
|
|
}
|
|
}
|
|
return versions, err
|
|
}
|
|
|
|
func ListLocalMigrations(migrationsDir string, fsys fs.FS, filter ...func(string) bool) ([]string, error) {
|
|
localMigrations, err := fs.ReadDir(fsys, migrationsDir)
|
|
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
return nil, errors.Errorf("failed to read directory: %w", err)
|
|
}
|
|
if len(filter) == 0 {
|
|
filter = append(filter, func(string) bool { return true })
|
|
}
|
|
var clean []string
|
|
for i, migration := range localMigrations {
|
|
filename := migration.Name()
|
|
if i == 0 && shouldSkip(filename) {
|
|
fmt.Fprintf(os.Stderr, "Skipping migration %s... (replace \"init\" with a different file name to apply this migration)\n", filename)
|
|
continue
|
|
}
|
|
matches := migrateFilePattern.FindStringSubmatch(filename)
|
|
if len(matches) == 0 {
|
|
fmt.Fprintf(os.Stderr, "Skipping migration %s... (file name must match pattern \"<timestamp>_name.sql\")\n", filename)
|
|
continue
|
|
}
|
|
path := filepath.Join(migrationsDir, filename)
|
|
for _, keep := range filter {
|
|
if version := matches[1]; keep(version) {
|
|
clean = append(clean, path)
|
|
}
|
|
}
|
|
}
|
|
return clean, nil
|
|
}
|
|
|
|
var initSchemaPattern = regexp.MustCompile(`([0-9]{14})_init\.sql`)
|
|
|
|
func shouldSkip(name string) bool {
|
|
// NOTE: To handle backward-compatibility. `<timestamp>_init.sql` as
|
|
// the first migration (prev versions of the CLI) is deprecated.
|
|
matches := initSchemaPattern.FindStringSubmatch(name)
|
|
if len(matches) == 2 {
|
|
if timestamp, err := strconv.ParseUint(matches[1], 10, 64); err == nil && timestamp < 20211209000000 {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|