New returns a new migrator with the given database driver and configuration. The config parameter may be omitted as nil. Two drivers are supported for migrations, one for Pgx v5 and one for the built-in database/sql package for use with migration frameworks like Goose. See packages riverpgxv5 and r
(driver riverdriver.Driver[TTx], config *Config)
| 114 | // // handle error |
| 115 | // } |
| 116 | func New[TTx any](driver riverdriver.Driver[TTx], config *Config) (*Migrator[TTx], error) { |
| 117 | if config == nil { |
| 118 | config = &Config{} |
| 119 | } |
| 120 | |
| 121 | line := cmp.Or(config.Line, riverdriver.MigrationLineMain) |
| 122 | |
| 123 | logger := config.Logger |
| 124 | if logger == nil { |
| 125 | logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ |
| 126 | Level: slog.LevelWarn, |
| 127 | })) |
| 128 | } |
| 129 | |
| 130 | archetype := &baseservice.Archetype{ |
| 131 | Logger: logger, |
| 132 | Time: &baseservice.UnStubbableTimeGenerator{}, |
| 133 | } |
| 134 | |
| 135 | if !slices.Contains(driver.GetMigrationLines(), line) { |
| 136 | const minLevenshteinDistance = 2 |
| 137 | |
| 138 | var suggestedLines []string |
| 139 | for _, existingLine := range driver.GetMigrationLines() { |
| 140 | if distance := levenshtein.ComputeDistance(existingLine, line); distance <= minLevenshteinDistance { |
| 141 | suggestedLines = append(suggestedLines, "`"+existingLine+"`") |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | errorStr := "migration line does not exist: " + line |
| 146 | switch { |
| 147 | case len(suggestedLines) == 1: |
| 148 | errorStr += fmt.Sprintf(" (did you mean %s?)", suggestedLines[0]) |
| 149 | case len(suggestedLines) > 1: |
| 150 | errorStr += fmt.Sprintf(" (did you mean one of %v?)", strings.Join(suggestedLines, ", ")) |
| 151 | } |
| 152 | |
| 153 | return nil, errors.New(errorStr) |
| 154 | } |
| 155 | |
| 156 | riverMigrations, err := migrationsFromFS(driver.GetMigrationFS(line), line) |
| 157 | if err != nil { |
| 158 | // If there's ever a problem here, it's a very fundamental internal |
| 159 | // River one, so it's okay to panic. |
| 160 | panic(err) |
| 161 | } |
| 162 | |
| 163 | return baseservice.Init(archetype, &Migrator[TTx]{ |
| 164 | driver: driver, |
| 165 | line: line, |
| 166 | migrations: validateAndInit(riverMigrations), |
| 167 | schema: config.Schema, |
| 168 | }), nil |
| 169 | } |
| 170 | |
| 171 | // ExistingVersions gets the existing set of versions that have been migrated in |
| 172 | // the database, ordered by version. |