migrator.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package migrations
  2. import (
  3. "time"
  4. _ "github.com/go-sql-driver/mysql"
  5. "github.com/go-xorm/xorm"
  6. _ "github.com/lib/pq"
  7. _ "github.com/mattn/go-sqlite3"
  8. "github.com/torkelo/grafana-pro/pkg/log"
  9. )
  10. type Migrator struct {
  11. LogLevel log.LogLevel
  12. x *xorm.Engine
  13. dialect Dialect
  14. migrations []Migration
  15. }
  16. func NewMigrator(engine *xorm.Engine) *Migrator {
  17. mg := &Migrator{}
  18. mg.x = engine
  19. mg.LogLevel = log.WARN
  20. mg.migrations = make([]Migration, 0)
  21. switch mg.x.DriverName() {
  22. case MYSQL:
  23. mg.dialect = NewMysqlDialect()
  24. case SQLITE:
  25. mg.dialect = NewSqlite3Dialect()
  26. }
  27. return mg
  28. }
  29. func (mg *Migrator) AddMigration(id string, m Migration) {
  30. m.SetId(id)
  31. mg.migrations = append(mg.migrations, m)
  32. }
  33. func (mg *Migrator) GetMigrationLog() (map[string]MigrationLog, error) {
  34. logMap := make(map[string]MigrationLog)
  35. logItems := make([]MigrationLog, 0)
  36. exists, err := mg.x.IsTableExist(new(MigrationLog))
  37. if err != nil {
  38. return nil, err
  39. }
  40. if !exists {
  41. return logMap, nil
  42. }
  43. if err = mg.x.Find(&logItems); err != nil {
  44. return nil, err
  45. }
  46. for _, logItem := range logItems {
  47. if !logItem.Success {
  48. continue
  49. }
  50. logMap[logItem.MigrationId] = logItem
  51. }
  52. return logMap, nil
  53. }
  54. func (mg *Migrator) Start() error {
  55. if mg.LogLevel <= log.INFO {
  56. log.Info("Migrator:: Starting DB migration")
  57. }
  58. logMap, err := mg.GetMigrationLog()
  59. if err != nil {
  60. return err
  61. }
  62. for _, m := range mg.migrations {
  63. _, exists := logMap[m.Id()]
  64. if exists {
  65. log.Debug("Migrator:: Skipping migration: %v, Already executed", m.Id())
  66. continue
  67. }
  68. sql := m.Sql(mg.dialect)
  69. record := MigrationLog{
  70. MigrationId: m.Id(),
  71. Sql: sql,
  72. Timestamp: time.Now(),
  73. }
  74. log.Debug("Migrator: Executing SQL: \n %v \n", sql)
  75. if err := mg.exec(m); err != nil {
  76. record.Error = err.Error()
  77. mg.x.Insert(&record)
  78. return err
  79. } else {
  80. record.Success = true
  81. mg.x.Insert(&record)
  82. }
  83. }
  84. return nil
  85. }
  86. func (mg *Migrator) exec(m Migration) error {
  87. log.Info("Migrator::exec migration id: %v", m.Id())
  88. err := mg.inTransaction(func(sess *xorm.Session) error {
  89. _, err := sess.Exec(m.Sql(mg.dialect))
  90. if err != nil {
  91. log.Error(3, "Migrator::exec FAILED migration id: %v, err: %v", m.Id(), err)
  92. return err
  93. }
  94. return nil
  95. })
  96. if err != nil {
  97. return err
  98. }
  99. return nil
  100. }
  101. type dbTransactionFunc func(sess *xorm.Session) error
  102. func (mg *Migrator) inTransaction(callback dbTransactionFunc) error {
  103. var err error
  104. sess := mg.x.NewSession()
  105. defer sess.Close()
  106. if err = sess.Begin(); err != nil {
  107. return err
  108. }
  109. err = callback(sess)
  110. if err != nil {
  111. sess.Rollback()
  112. return err
  113. } else if err = sess.Commit(); err != nil {
  114. return err
  115. }
  116. return nil
  117. }