github.com/atrox/migrate@v3.5.4+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   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)
    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  }