...
1 package source
2
3 import (
4 "sort"
5 )
6
7
8 type Direction string
9
10 const (
11 Down Direction = "down"
12 Up Direction = "up"
13 )
14
15
16
17
18 type Migration struct {
19
20 Version uint
21
22
23
24 Identifier string
25
26
27 Direction Direction
28
29
30
31 Raw string
32 }
33
34
35
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
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 }
144
View as plain text