56 lines
1.4 KiB
Go
56 lines
1.4 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"path"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// ApplyPostgresMigrations runs ordered *.up.sql from an embedded subtree (idempotent via schema_migrations).
|
|
func ApplyPostgresMigrations(ctx context.Context, pool *pgxpool.Pool, fsys fs.FS, subdir string) error {
|
|
if _, err := pool.Exec(ctx, `CREATE TABLE IF NOT EXISTS schema_migrations (version TEXT NOT NULL PRIMARY KEY)`); err != nil {
|
|
return fmt.Errorf("db: schema_migrations: %w", err)
|
|
}
|
|
entries, err := fs.ReadDir(fsys, subdir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var ups []string
|
|
for _, e := range entries {
|
|
if e.IsDir() || !strings.HasSuffix(e.Name(), ".up.sql") {
|
|
continue
|
|
}
|
|
ups = append(ups, e.Name())
|
|
}
|
|
sort.Strings(ups)
|
|
for _, name := range ups {
|
|
ver := strings.TrimSuffix(name, ".up.sql")
|
|
var dummy int
|
|
err := pool.QueryRow(ctx, `SELECT 1 FROM schema_migrations WHERE version = $1`, ver).Scan(&dummy)
|
|
if err == nil {
|
|
continue
|
|
}
|
|
if !errors.Is(err, pgx.ErrNoRows) {
|
|
return err
|
|
}
|
|
body, err := fs.ReadFile(fsys, path.Join(subdir, name))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := pool.Exec(ctx, string(body)); err != nil {
|
|
return fmt.Errorf("db: migrate %s: %w", name, err)
|
|
}
|
|
if _, err := pool.Exec(ctx, `INSERT INTO schema_migrations (version) VALUES ($1)`, ver); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|