github.com/mattes/migrate@v3.0.2-0.20180508041624-4768a648fbd9+incompatible/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 = "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) 70 for version, _ := range i.migrations { 71 i.index = append(i.index, version) 72 } 73 sort.Sort(i.index) 74 } 75 76 func (i *Migrations) First() (version uint, ok bool) { 77 if len(i.index) == 0 { 78 return 0, false 79 } 80 return i.index[0], true 81 } 82 83 func (i *Migrations) Prev(version uint) (prevVersion uint, ok bool) { 84 pos := i.findPos(version) 85 if pos >= 1 && len(i.index) > pos-1 { 86 return i.index[pos-1], true 87 } 88 return 0, false 89 } 90 91 func (i *Migrations) Next(version uint) (nextVersion uint, ok bool) { 92 pos := i.findPos(version) 93 if pos >= 0 && len(i.index) > pos+1 { 94 return i.index[pos+1], true 95 } 96 return 0, false 97 } 98 99 func (i *Migrations) Up(version uint) (m *Migration, ok bool) { 100 if _, ok := i.migrations[version]; ok { 101 if mx, ok := i.migrations[version][Up]; ok { 102 return mx, true 103 } 104 } 105 return nil, false 106 } 107 108 func (i *Migrations) Down(version uint) (m *Migration, ok bool) { 109 if _, ok := i.migrations[version]; ok { 110 if mx, ok := i.migrations[version][Down]; ok { 111 return mx, true 112 } 113 } 114 return nil, false 115 } 116 117 func (i *Migrations) findPos(version uint) int { 118 if len(i.index) > 0 { 119 ix := i.index.Search(version) 120 if ix < len(i.index) && i.index[ix] == version { 121 return ix 122 } 123 } 124 return -1 125 } 126 127 type uintSlice []uint 128 129 func (s uintSlice) Len() int { 130 return len(s) 131 } 132 133 func (s uintSlice) Swap(i, j int) { 134 s[i], s[j] = s[j], s[i] 135 } 136 137 func (s uintSlice) Less(i, j int) bool { 138 return s[i] < s[j] 139 } 140 141 func (s uintSlice) Search(x uint) int { 142 return sort.Search(len(s), func(i int) bool { return s[i] >= x }) 143 }