77 "fmt"
88 "io"
99 "net/http"
10- "os"
1110 "path"
1211 "regexp"
1312 "sort"
@@ -121,15 +120,61 @@ func SetIgnoreUnknown(v bool) {
121120 migSet .IgnoreUnknown = v
122121}
123122
124- type Migration struct {
125- Id string
126- Up []string
127- Down []string
128-
123+ type MigrationData struct {
124+ Up []string
125+ Down []string
129126 DisableTransactionUp bool
130127 DisableTransactionDown bool
131128}
132129
130+ type migrationFile struct {
131+ dir http.FileSystem
132+ root string
133+ baseName string
134+ }
135+
136+ type Migration struct {
137+ Id string
138+
139+ // data may be nil if not parsed yet.
140+ data * MigrationData
141+ // file is information of migration file, which is used to parse later.
142+ // file may be nil if migration file has already been parsed when Migration is initialized.
143+ file * migrationFile
144+ }
145+
146+ // Data parses migration file if not yet, and returns *MigrationData
147+ func (m * Migration ) Data () (* MigrationData , error ) {
148+ if m .data != nil {
149+ return m .data , nil
150+ }
151+ err := m .loadFile ()
152+ if err != nil {
153+ return nil , err
154+ }
155+ return m .data , nil
156+ }
157+
158+ func (m * Migration ) loadFile () error {
159+ if m .file == nil {
160+ return fmt .Errorf ("Error m.file must not be nil when call loadFile" )
161+ }
162+ root := m .file .root
163+ name := m .file .baseName
164+ file , err := m .file .dir .Open (path .Join (root , name ))
165+ if err != nil {
166+ return fmt .Errorf ("Error while opening %s: %s" , name , err )
167+ }
168+ defer func () { _ = file .Close () }()
169+
170+ migrationData , err := ParseMigration (name , file )
171+ if err != nil {
172+ return fmt .Errorf ("Error while parsing %s: %s" , name , err )
173+ }
174+ m .data = migrationData
175+ return nil
176+ }
177+
133178func (m Migration ) Less (other * Migration ) bool {
134179 switch {
135180 case m .isNumeric () && other .isNumeric () && m .VersionInt () != other .VersionInt ():
@@ -266,11 +311,14 @@ func findMigrations(dir http.FileSystem, root string) ([]*Migration, error) {
266311
267312 for _ , info := range files {
268313 if strings .HasSuffix (info .Name (), ".sql" ) {
269- migration , err := migrationFromFile (dir , root , info )
270- if err != nil {
271- return nil , err
314+ migration := & Migration {
315+ Id : info .Name (),
316+ file : & migrationFile {
317+ dir : dir ,
318+ root : root ,
319+ baseName : info .Name (),
320+ },
272321 }
273-
274322 migrations = append (migrations , migration )
275323 }
276324 }
@@ -281,21 +329,6 @@ func findMigrations(dir http.FileSystem, root string) ([]*Migration, error) {
281329 return migrations , nil
282330}
283331
284- func migrationFromFile (dir http.FileSystem , root string , info os.FileInfo ) (* Migration , error ) {
285- path := path .Join (root , info .Name ())
286- file , err := dir .Open (path )
287- if err != nil {
288- return nil , fmt .Errorf ("Error while opening %s: %s" , info .Name (), err )
289- }
290- defer func () { _ = file .Close () }()
291-
292- migration , err := ParseMigration (info .Name (), file )
293- if err != nil {
294- return nil , fmt .Errorf ("Error while parsing %s: %s" , info .Name (), err )
295- }
296- return migration , nil
297- }
298-
299332// Migrations from a bindata asset set.
300333type AssetMigrationSource struct {
301334 // Asset should return content of file in path if exists
@@ -325,11 +358,14 @@ func (a AssetMigrationSource) FindMigrations() ([]*Migration, error) {
325358 return nil , err
326359 }
327360
328- migration , err := ParseMigration (name , bytes .NewReader (file ))
361+ migrationData , err := ParseMigration (name , bytes .NewReader (file ))
329362 if err != nil {
330363 return nil , err
331364 }
332-
365+ migration := & Migration {
366+ Id : name ,
367+ data : migrationData ,
368+ }
333369 migrations = append (migrations , migration )
334370 }
335371 }
@@ -382,11 +418,14 @@ func (p PackrMigrationSource) FindMigrations() ([]*Migration, error) {
382418 return nil , err
383419 }
384420
385- migration , err := ParseMigration (name , bytes .NewReader (file ))
421+ migrationData , err := ParseMigration (name , bytes .NewReader (file ))
386422 if err != nil {
387423 return nil , err
388424 }
389-
425+ migration := & Migration {
426+ Id : name ,
427+ data : migrationData ,
428+ }
390429 migrations = append (migrations , migration )
391430 }
392431 }
@@ -398,23 +437,18 @@ func (p PackrMigrationSource) FindMigrations() ([]*Migration, error) {
398437}
399438
400439// Migration parsing
401- func ParseMigration (id string , r io.ReadSeeker ) (* Migration , error ) {
402- m := & Migration {
403- Id : id ,
404- }
405-
440+ func ParseMigration (id string , r io.ReadSeeker ) (* MigrationData , error ) {
406441 parsed , err := sqlparse .ParseMigration (r )
407442 if err != nil {
408443 return nil , fmt .Errorf ("Error parsing migration (%s): %s" , id , err )
409444 }
410445
411- m .Up = parsed .UpStatements
412- m .Down = parsed .DownStatements
413-
414- m .DisableTransactionUp = parsed .DisableTransactionUp
415- m .DisableTransactionDown = parsed .DisableTransactionDown
416-
417- return m , nil
446+ return & MigrationData {
447+ Up : parsed .UpStatements ,
448+ Down : parsed .DownStatements ,
449+ DisableTransactionUp : parsed .DisableTransactionUp ,
450+ DisableTransactionDown : parsed .DisableTransactionDown ,
451+ }, nil
418452}
419453
420454type SqlExecutor interface {
@@ -575,7 +609,11 @@ func (ms MigrationSet) PlanMigration(db *sql.DB, dialect string, m MigrationSour
575609 // Add missing migrations up to the last run migration.
576610 // This can happen for example when merges happened.
577611 if len (existingMigrations ) > 0 {
578- result = append (result , ToCatchup (migrations , existingMigrations , record )... )
612+ catchUp , err := ToCatchup (migrations , existingMigrations , record )
613+ if err != nil {
614+ return nil , nil , err
615+ }
616+ result = append (result , catchUp ... )
579617 }
580618
581619 // Figure out which migrations to apply
@@ -585,18 +623,21 @@ func (ms MigrationSet) PlanMigration(db *sql.DB, dialect string, m MigrationSour
585623 toApplyCount = max
586624 }
587625 for _ , v := range toApply [0 :toApplyCount ] {
588-
626+ migrationData , err := v .Data ()
627+ if err != nil {
628+ return nil , nil , err
629+ }
589630 if dir == Up {
590631 result = append (result , & PlannedMigration {
591632 Migration : v ,
592- Queries : v .Up ,
593- DisableTransaction : v .DisableTransactionUp ,
633+ Queries : migrationData .Up ,
634+ DisableTransaction : migrationData .DisableTransactionUp ,
594635 })
595636 } else if dir == Down {
596637 result = append (result , & PlannedMigration {
597638 Migration : v ,
598- Queries : v .Down ,
599- DisableTransaction : v .DisableTransactionDown ,
639+ Queries : migrationData .Down ,
640+ DisableTransaction : migrationData .DisableTransactionDown ,
600641 })
601642 }
602643 }
@@ -683,7 +724,7 @@ func ToApply(migrations []*Migration, current string, direction MigrationDirecti
683724 panic ("Not possible" )
684725}
685726
686- func ToCatchup (migrations , existingMigrations []* Migration , lastRun * Migration ) []* PlannedMigration {
727+ func ToCatchup (migrations , existingMigrations []* Migration , lastRun * Migration ) ( []* PlannedMigration , error ) {
687728 missing := make ([]* PlannedMigration , 0 )
688729 for _ , migration := range migrations {
689730 found := false
@@ -694,14 +735,18 @@ func ToCatchup(migrations, existingMigrations []*Migration, lastRun *Migration)
694735 }
695736 }
696737 if ! found && migration .Less (lastRun ) {
738+ migrationData , err := migration .Data ()
739+ if err != nil {
740+ return nil , err
741+ }
697742 missing = append (missing , & PlannedMigration {
698743 Migration : migration ,
699- Queries : migration .Up ,
700- DisableTransaction : migration .DisableTransactionUp ,
744+ Queries : migrationData .Up ,
745+ DisableTransaction : migrationData .DisableTransactionUp ,
701746 })
702747 }
703748 }
704- return missing
749+ return missing , nil
705750}
706751
707752func GetMigrationRecords (db * sql.DB , dialect string ) ([]* MigrationRecord , error ) {
0 commit comments