package db import ( "errors" "fmt" "io/fs" "database/sql" "github.com/golang-migrate/migrate/v4" "github.com/golang-migrate/migrate/v4/database/pgx/v5" sqlitemig "github.com/golang-migrate/migrate/v4/database/sqlite" "github.com/golang-migrate/migrate/v4/source/iofs" _ "github.com/jackc/pgx/v5/stdlib" _ "modernc.org/sqlite" ) // Migrate applies all up migrations from the given fs (root contains *.sql files). func Migrate(dsn string, migrations fs.FS) error { source, err := iofs.New(migrations, ".") if err != nil { return fmt.Errorf("migrations source: %w", err) } sqlDB, err := sql.Open("pgx", dsn) if err != nil { return fmt.Errorf("open sql db: %w", err) } defer sqlDB.Close() driver, err := pgx.WithInstance(sqlDB, &pgx.Config{}) if err != nil { return fmt.Errorf("migrate driver: %w", err) } m, err := migrate.NewWithInstance("iofs", source, "pgx", driver) if err != nil { return fmt.Errorf("migrate instance: %w", err) } if err := m.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) { return fmt.Errorf("migrate up: %w", err) } return nil } // MigrateSQLite applies all up migrations from the given fs to a SQLite database // at path (creating it if needed). func MigrateSQLite(path string, migrations fs.FS) error { source, err := iofs.New(migrations, ".") if err != nil { return fmt.Errorf("migrations source: %w", err) } sqlDB, err := sql.Open("sqlite", path) if err != nil { return fmt.Errorf("open sql db: %w", err) } defer sqlDB.Close() driver, err := sqlitemig.WithInstance(sqlDB, &sqlitemig.Config{}) if err != nil { return fmt.Errorf("migrate driver: %w", err) } m, err := migrate.NewWithInstance("iofs", source, "sqlite", driver) if err != nil { return fmt.Errorf("migrate instance: %w", err) } if err := m.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) { return fmt.Errorf("migrate up: %w", err) } return nil }