98 lines
1.6 KiB
Go
98 lines
1.6 KiB
Go
package database
|
|
|
|
import (
|
|
"embed"
|
|
"fmt"
|
|
"io/fs"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
)
|
|
|
|
//go:embed migrations/*.sql
|
|
var migrationStorage embed.FS
|
|
|
|
func getAppliedMigrationsSet(db *sqlx.DB) (map[string]bool, error) {
|
|
set := make(map[string]bool)
|
|
|
|
rows, err := db.Query("SELECT id FROM migrations")
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
var id string
|
|
|
|
err := rows.Scan(&id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
set[id] = true
|
|
}
|
|
|
|
err = rows.Err()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return set, nil
|
|
}
|
|
|
|
func getMigrations() ([]string, error) {
|
|
var items []string
|
|
|
|
entries, err := migrationStorage.ReadDir("migrations")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".sql") {
|
|
items = append(items, strings.TrimSuffix(entry.Name(), ".sql"))
|
|
}
|
|
}
|
|
|
|
sort.Strings(items)
|
|
|
|
return items, nil
|
|
}
|
|
|
|
func getMigrationContent(id string) (string, error) {
|
|
content, err := fs.ReadFile(migrationStorage, "migrations/"+id+".sql")
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return string(content), nil
|
|
}
|
|
|
|
func getPendingMigrations(db *sqlx.DB) ([]string, error) {
|
|
var migrationsToRun []string
|
|
|
|
migrationSet, err := getAppliedMigrationsSet(db)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
storedMigrations, err := getMigrations()
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to load stored migrations: %w", err)
|
|
}
|
|
|
|
for _, storedMigration := range storedMigrations {
|
|
if !migrationSet[storedMigration] {
|
|
migrationsToRun = append(migrationsToRun, storedMigration)
|
|
}
|
|
}
|
|
|
|
return migrationsToRun, nil
|
|
}
|