| package source |
| |
| import ( |
| "sort" |
| ) |
| |
| // Direction is either up or down. |
| type Direction string |
| |
| const ( |
| Down Direction = "down" |
| Up = "up" |
| ) |
| |
| // Migration is a helper struct for source drivers that need to |
| // build the full directory tree in memory. |
| // Migration is fully independent from migrate.Migration. |
| type Migration struct { |
| // Version is the version of this migration. |
| Version uint |
| |
| // Identifier can be any string that helps identifying |
| // this migration in the source. |
| Identifier string |
| |
| // Direction is either Up or Down. |
| Direction Direction |
| |
| // Raw holds the raw location path to this migration in source. |
| // ReadUp and ReadDown will use this. |
| Raw string |
| } |
| |
| // Migrations wraps Migration and has an internal index |
| // to keep track of Migration order. |
| type Migrations struct { |
| index uintSlice |
| migrations map[uint]map[Direction]*Migration |
| } |
| |
| func NewMigrations() *Migrations { |
| return &Migrations{ |
| index: make(uintSlice, 0), |
| migrations: make(map[uint]map[Direction]*Migration), |
| } |
| } |
| |
| func (i *Migrations) Append(m *Migration) (ok bool) { |
| if m == nil { |
| return false |
| } |
| |
| if i.migrations[m.Version] == nil { |
| i.migrations[m.Version] = make(map[Direction]*Migration) |
| } |
| |
| // reject duplicate versions |
| if _, dup := i.migrations[m.Version][m.Direction]; dup { |
| return false |
| } |
| |
| i.migrations[m.Version][m.Direction] = m |
| i.buildIndex() |
| |
| return true |
| } |
| |
| func (i *Migrations) buildIndex() { |
| i.index = make(uintSlice, 0) |
| for version, _ := range i.migrations { |
| i.index = append(i.index, version) |
| } |
| sort.Sort(i.index) |
| } |
| |
| func (i *Migrations) First() (version uint, ok bool) { |
| if len(i.index) == 0 { |
| return 0, false |
| } |
| return i.index[0], true |
| } |
| |
| func (i *Migrations) Prev(version uint) (prevVersion uint, ok bool) { |
| pos := i.findPos(version) |
| if pos >= 1 && len(i.index) > pos-1 { |
| return i.index[pos-1], true |
| } |
| return 0, false |
| } |
| |
| func (i *Migrations) Next(version uint) (nextVersion uint, ok bool) { |
| pos := i.findPos(version) |
| if pos >= 0 && len(i.index) > pos+1 { |
| return i.index[pos+1], true |
| } |
| return 0, false |
| } |
| |
| func (i *Migrations) Up(version uint) (m *Migration, ok bool) { |
| if _, ok := i.migrations[version]; ok { |
| if mx, ok := i.migrations[version][Up]; ok { |
| return mx, true |
| } |
| } |
| return nil, false |
| } |
| |
| func (i *Migrations) Down(version uint) (m *Migration, ok bool) { |
| if _, ok := i.migrations[version]; ok { |
| if mx, ok := i.migrations[version][Down]; ok { |
| return mx, true |
| } |
| } |
| return nil, false |
| } |
| |
| func (i *Migrations) findPos(version uint) int { |
| if len(i.index) > 0 { |
| ix := i.index.Search(version) |
| if ix < len(i.index) && i.index[ix] == version { |
| return ix |
| } |
| } |
| return -1 |
| } |
| |
| type uintSlice []uint |
| |
| func (s uintSlice) Len() int { |
| return len(s) |
| } |
| |
| func (s uintSlice) Swap(i, j int) { |
| s[i], s[j] = s[j], s[i] |
| } |
| |
| func (s uintSlice) Less(i, j int) bool { |
| return s[i] < s[j] |
| } |
| |
| func (s uintSlice) Search(x uint) int { |
| return sort.Search(len(s), func(i int) bool { return s[i] >= x }) |
| } |