github.com/dannyzhou2015/migrate/v4@v4.15.2/source/migration.go (about) 1 package source 2 3 import ( 4 "sort" 5 ) 6 7 // Direction is either up or down. 8 type Direction string 9 10 const ( 11 Down Direction = "down" 12 Up Direction = "up" 13 ) 14 15 // Migration is a helper struct for source drivers that need to 16 // build the full directory tree in memory. 17 // Migration is fully independent from migrate.Migration. 18 type Migration struct { 19 // Version is the version of this migration. 20 Version uint 21 22 // Identifier can be any string that helps identifying 23 // this migration in the source. 24 Identifier string 25 26 // Direction is either Up or Down. 27 Direction Direction 28 29 // Raw holds the raw location path to this migration in source. 30 // ReadUp and ReadDown will use this. 31 Raw string 32 } 33 34 // Migrations wraps Migration and has an internal index 35 // to keep track of Migration order. 36 type Migrations struct { 37 index uintSlice 38 migrations map[uint]map[Direction]*Migration 39 } 40 41 func NewMigrations() *Migrations { 42 return &Migrations{ 43 index: make(uintSlice, 0), 44 migrations: make(map[uint]map[Direction]*Migration), 45 } 46 } 47 48 func (i *Migrations) Append(m *Migration) (ok bool) { 49 if m == nil { 50 return false 51 } 52 53 if i.migrations[m.Version] == nil { 54 i.migrations[m.Version] = make(map[Direction]*Migration) 55 } 56 57 // reject duplicate versions 58 if _, dup := i.migrations[m.Version][m.Direction]; dup { 59 return false 60 } 61 62 i.migrations[m.Version][m.Direction] = m 63 i.buildIndex() 64 65 return true 66 } 67 68 func (i *Migrations) buildIndex() { 69 i.index = make(uintSlice, 0, len(i.migrations)) 70 for version := range i.migrations { 71 i.index = append(i.index, version) 72 } 73 sort.Slice(i.index, func(x, y int) bool { 74 return i.index[x] < i.index[y] 75 }) 76 } 77 78 func (i *Migrations) First() (version uint, ok bool) { 79 if len(i.index) == 0 { 80 return 0, false 81 } 82 return i.index[0], true 83 } 84 85 func (i *Migrations) Prev(version uint) (prevVersion uint, ok bool) { 86 pos := i.findPos(version) 87 if pos >= 1 && len(i.index) > pos-1 { 88 return i.index[pos-1], true 89 } 90 return 0, false 91 } 92 93 func (i *Migrations) Next(version uint) (nextVersion uint, ok bool) { 94 pos := i.findPos(version) 95 if pos >= 0 && len(i.index) > pos+1 { 96 return i.index[pos+1], true 97 } 98 return 0, false 99 } 100 101 func (i *Migrations) Up(version uint) (m *Migration, ok bool) { 102 if _, ok := i.migrations[version]; ok { 103 if mx, ok := i.migrations[version][Up]; ok { 104 return mx, true 105 } 106 } 107 return nil, false 108 } 109 110 func (i *Migrations) Down(version uint) (m *Migration, ok bool) { 111 if _, ok := i.migrations[version]; ok { 112 if mx, ok := i.migrations[version][Down]; ok { 113 return mx, true 114 } 115 } 116 return nil, false 117 } 118 119 func (i *Migrations) findPos(version uint) int { 120 if len(i.index) > 0 { 121 ix := i.index.Search(version) 122 if ix < len(i.index) && i.index[ix] == version { 123 return ix 124 } 125 } 126 return -1 127 } 128 129 type uintSlice []uint 130 131 func (s uintSlice) Search(x uint) int { 132 return sort.Search(len(s), func(i int) bool { return s[i] >= x }) 133 }