package database import ( "database/sql" "embed" "fmt" "io/fs" "sort" "strings" ) //go:embed migrations/*.sql var migrationStorage embed.FS func getAppliedMigrationsSet(db *sql.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")) } } if err != nil { return nil, err } 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 *sql.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 }