github.com/Accefy/pop@v0.0.0-20230428174248-e9f677eab5b9/migration_box.go (about) 1 package pop 2 3 import ( 4 "fmt" 5 "io" 6 "io/fs" 7 "strings" 8 9 "github.com/gobuffalo/pop/v6/logging" 10 ) 11 12 // MigrationBox is a wrapper around fs.FS and Migrator. 13 // This will allow you to run migrations from a fs.FS 14 // inside of a compiled binary. 15 type MigrationBox struct { 16 Migrator 17 FS fs.FS 18 } 19 20 // NewMigrationBox from a fs.FS and a Connection. 21 func NewMigrationBox(fsys fs.FS, c *Connection) (MigrationBox, error) { 22 fm := MigrationBox{ 23 Migrator: NewMigrator(c), 24 FS: fsys, 25 } 26 27 runner := func(r io.Reader) func(mf Migration, tx *Connection) error { 28 return func(mf Migration, tx *Connection) error { 29 content, err := MigrationContent(mf, tx, r, true) 30 if err != nil { 31 return fmt.Errorf("error processing %s: %w", mf.Path, err) 32 } 33 if content == "" { 34 return nil 35 } 36 err = tx.RawQuery(content).Exec() 37 if err != nil { 38 return fmt.Errorf("error executing %s, sql: %s: %w", mf.Path, content, err) 39 } 40 return nil 41 } 42 } 43 44 err := fm.findMigrations(runner) 45 if err != nil { 46 return fm, err 47 } 48 49 return fm, nil 50 } 51 52 func (fm *MigrationBox) findMigrations(runner func(r io.Reader) func(mf Migration, tx *Connection) error) error { 53 return fs.WalkDir(fm.FS, ".", func(path string, d fs.DirEntry, err error) error { 54 if err != nil { 55 return err 56 } 57 58 if d.IsDir() { 59 return nil 60 } 61 62 info, err := d.Info() 63 if err != nil { 64 return err 65 } 66 67 match, err := ParseMigrationFilename(info.Name()) 68 if err != nil { 69 if strings.HasPrefix(err.Error(), "unsupported dialect") { 70 log(logging.Warn, "ignoring migration file with %s", err.Error()) 71 return nil 72 } 73 return err 74 } 75 if match == nil { 76 log(logging.Warn, "ignoring file %s because it does not match the migration file pattern", info.Name()) 77 return nil 78 } 79 80 f, err := fm.FS.Open(path) 81 if err != nil { 82 return err 83 } 84 85 mf := Migration{ 86 Path: path, 87 Version: match.Version, 88 Name: match.Name, 89 DBType: match.DBType, 90 Direction: match.Direction, 91 Type: match.Type, 92 Runner: runner(f), 93 } 94 switch mf.Direction { 95 case "up": 96 fm.UpMigrations.Migrations = append(fm.UpMigrations.Migrations, mf) 97 case "down": 98 fm.DownMigrations.Migrations = append(fm.DownMigrations.Migrations, mf) 99 default: 100 // the regex only matches `(up|down)` for direction, so a panic here is appropriate 101 panic("got unknown migration direction " + mf.Direction) 102 } 103 return nil 104 }) 105 }