mirror of
https://github.com/therootcompany/golib.git
synced 2026-04-24 12:48:00 +00:00
ref(sqlmigrate): add subpath to Collect, add Latest/Drop convenience functions
API changes for v1: - Collect(fsys, subpath) takes a subdirectory path (use "." for root), enabling embed.FS with //go:embed sql/migrations/*.sql - Latest() applies all pending migrations (shorthand for Up with n=-1) - Drop() rolls back all applied migrations (shorthand for Down with n=-1)
This commit is contained in:
parent
9c672a9d76
commit
a3ecf5ac81
@ -71,11 +71,20 @@ var idFromInsert = regexp.MustCompile(
|
|||||||
`(?i)INSERT\s+INTO\s+_migrations\s*\(\s*name\s*,\s*id\s*\)\s*VALUES\s*\(\s*'[^']*'\s*,\s*'([0-9a-fA-F]+)'\s*\)`,
|
`(?i)INSERT\s+INTO\s+_migrations\s*\(\s*name\s*,\s*id\s*\)\s*VALUES\s*\(\s*'[^']*'\s*,\s*'([0-9a-fA-F]+)'\s*\)`,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Collect reads .up.sql and .down.sql files from fsys, pairs them by
|
// Collect reads .up.sql and .down.sql files from fsys under subpath,
|
||||||
// basename, and returns them sorted lexicographically by name.
|
// pairs them by basename, and returns them sorted lexicographically by name.
|
||||||
|
// If subpath is "" or ".", the root of fsys is used.
|
||||||
// If the up SQL contains an INSERT INTO _migrations line, the hex ID
|
// If the up SQL contains an INSERT INTO _migrations line, the hex ID
|
||||||
// is extracted and stored in Migration.ID.
|
// is extracted and stored in Migration.ID.
|
||||||
func Collect(fsys fs.FS) ([]Migration, error) {
|
func Collect(fsys fs.FS, subpath string) ([]Migration, error) {
|
||||||
|
if subpath != "" && subpath != "." {
|
||||||
|
var err error
|
||||||
|
fsys, err = fs.Sub(fsys, subpath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%w: %w", ErrWalkFailed, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ups := map[string]string{}
|
ups := map[string]string{}
|
||||||
downs := map[string]string{}
|
downs := map[string]string{}
|
||||||
|
|
||||||
@ -285,3 +294,13 @@ func GetStatus(ctx context.Context, r Migrator, migrations []Migration) (*Status
|
|||||||
Pending: pending,
|
Pending: pending,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Latest applies all pending migrations. Equivalent to Up(ctx, r, migrations, -1).
|
||||||
|
func Latest(ctx context.Context, r Migrator, migrations []Migration) ([]string, error) {
|
||||||
|
return Up(ctx, r, migrations, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop rolls back all applied migrations. Equivalent to Down(ctx, r, migrations, -1).
|
||||||
|
func Drop(ctx context.Context, r Migrator, migrations []Migration) ([]string, error) {
|
||||||
|
return Down(ctx, r, migrations, -1)
|
||||||
|
}
|
||||||
|
|||||||
@ -63,7 +63,7 @@ func TestCollect(t *testing.T) {
|
|||||||
"001_first.up.sql": {Data: []byte("CREATE TABLE a;")},
|
"001_first.up.sql": {Data: []byte("CREATE TABLE a;")},
|
||||||
"001_first.down.sql": {Data: []byte("DROP TABLE a;")},
|
"001_first.down.sql": {Data: []byte("DROP TABLE a;")},
|
||||||
}
|
}
|
||||||
migrations, err := sqlmigrate.Collect(fsys)
|
migrations, err := sqlmigrate.Collect(fsys, ".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ func TestCollect(t *testing.T) {
|
|||||||
"001_init.up.sql": {Data: []byte("CREATE TABLE a;\nINSERT INTO _migrations (name, id) VALUES ('001_init', 'abcd1234');")},
|
"001_init.up.sql": {Data: []byte("CREATE TABLE a;\nINSERT INTO _migrations (name, id) VALUES ('001_init', 'abcd1234');")},
|
||||||
"001_init.down.sql": {Data: []byte("DROP TABLE a;\nDELETE FROM _migrations WHERE id = 'abcd1234';")},
|
"001_init.down.sql": {Data: []byte("DROP TABLE a;\nDELETE FROM _migrations WHERE id = 'abcd1234';")},
|
||||||
}
|
}
|
||||||
migrations, err := sqlmigrate.Collect(fsys)
|
migrations, err := sqlmigrate.Collect(fsys, ".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ func TestCollect(t *testing.T) {
|
|||||||
"001_init.up.sql": {Data: []byte("CREATE TABLE a;")},
|
"001_init.up.sql": {Data: []byte("CREATE TABLE a;")},
|
||||||
"001_init.down.sql": {Data: []byte("DROP TABLE a;")},
|
"001_init.down.sql": {Data: []byte("DROP TABLE a;")},
|
||||||
}
|
}
|
||||||
migrations, err := sqlmigrate.Collect(fsys)
|
migrations, err := sqlmigrate.Collect(fsys, ".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ func TestCollect(t *testing.T) {
|
|||||||
fsys := fstest.MapFS{
|
fsys := fstest.MapFS{
|
||||||
"001_only-up.up.sql": {Data: []byte("CREATE TABLE x;")},
|
"001_only-up.up.sql": {Data: []byte("CREATE TABLE x;")},
|
||||||
}
|
}
|
||||||
_, err := sqlmigrate.Collect(fsys)
|
_, err := sqlmigrate.Collect(fsys, ".")
|
||||||
if !errors.Is(err, sqlmigrate.ErrMissingDown) {
|
if !errors.Is(err, sqlmigrate.ErrMissingDown) {
|
||||||
t.Errorf("got %v, want ErrMissingDown", err)
|
t.Errorf("got %v, want ErrMissingDown", err)
|
||||||
}
|
}
|
||||||
@ -126,7 +126,7 @@ func TestCollect(t *testing.T) {
|
|||||||
fsys := fstest.MapFS{
|
fsys := fstest.MapFS{
|
||||||
"001_only-down.down.sql": {Data: []byte("DROP TABLE x;")},
|
"001_only-down.down.sql": {Data: []byte("DROP TABLE x;")},
|
||||||
}
|
}
|
||||||
_, err := sqlmigrate.Collect(fsys)
|
_, err := sqlmigrate.Collect(fsys, ".")
|
||||||
if !errors.Is(err, sqlmigrate.ErrMissingUp) {
|
if !errors.Is(err, sqlmigrate.ErrMissingUp) {
|
||||||
t.Errorf("got %v, want ErrMissingUp", err)
|
t.Errorf("got %v, want ErrMissingUp", err)
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ func TestCollect(t *testing.T) {
|
|||||||
"README.md": {Data: []byte("# Migrations")},
|
"README.md": {Data: []byte("# Migrations")},
|
||||||
"_migrations.sql": {Data: []byte("SELECT name FROM _migrations;")},
|
"_migrations.sql": {Data: []byte("SELECT name FROM _migrations;")},
|
||||||
}
|
}
|
||||||
migrations, err := sqlmigrate.Collect(fsys)
|
migrations, err := sqlmigrate.Collect(fsys, ".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ func TestCollect(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("empty fs", func(t *testing.T) {
|
t.Run("empty fs", func(t *testing.T) {
|
||||||
fsys := fstest.MapFS{}
|
fsys := fstest.MapFS{}
|
||||||
migrations, err := sqlmigrate.Collect(fsys)
|
migrations, err := sqlmigrate.Collect(fsys, ".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user