github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/utils/migration/migration.go (about) 1 package migration 2 3 import ( 4 "crypto/sha256" 5 "errors" 6 "fmt" 7 8 "github.com/unicornultrafoundation/go-u2u/log" 9 ) 10 11 // Migration is a migration step. 12 type Migration struct { 13 name string 14 exec func() error 15 prev *Migration 16 } 17 18 // Begin with empty unique migration step. 19 func Begin(appName string) *Migration { 20 return &Migration{ 21 name: appName, 22 } 23 } 24 25 // Next creates next migration. 26 func (m *Migration) Next(name string, exec func() error) *Migration { 27 if name == "" { 28 panic("empty name") 29 } 30 31 if exec == nil { 32 panic("empty exec") 33 } 34 35 return &Migration{ 36 name: name, 37 exec: exec, 38 prev: m, 39 } 40 } 41 42 func idOf(name string) string { 43 digest := sha256.New() 44 digest.Write([]byte(name)) 45 46 bytes := digest.Sum(nil) 47 return fmt.Sprintf("%x", bytes) 48 } 49 50 // ID is an uniq migration's id. 51 func (m *Migration) ID() string { 52 return idOf(m.name) 53 } 54 55 // Exec method run migrations chain in order 56 func (m *Migration) Exec(curr IDStore, flush func() error) error { 57 currID := curr.GetID() 58 myID := m.ID() 59 60 if m.veryFirst() { 61 if currID != myID { 62 return errors.New("unknown version: " + currID) 63 } 64 return nil 65 } 66 67 if currID == myID { 68 return nil 69 } 70 71 err := m.prev.Exec(curr, flush) 72 if err != nil { 73 return err 74 } 75 76 log.Warn("Applying migration", "name", m.name) 77 err = m.exec() 78 if err != nil { 79 log.Error("'"+m.name+"' migration failed", "err", err) 80 return err 81 } 82 83 curr.SetID(myID) 84 85 return flush() 86 } 87 88 func (m *Migration) veryFirst() bool { 89 return m.exec == nil 90 } 91 92 // IDs return list of migrations ids in chain 93 func (m *Migration) IDs() []string { 94 if m.prev == nil { 95 return []string{m.ID()} 96 } 97 98 return append(m.prev.IDs(), m.ID()) 99 }