github.com/sujit-baniya/migrate@v0.0.4/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  }