/web/sca/dbs/db.go

https://github.com/IBM/cloudland · Go · 196 lines · 161 code · 19 blank · 16 comment · 43 complexity · 3b23d80bdf5e1372b7deed24a22f2702 MD5 · raw file

  1. /*
  2. Copyright <holder> All Rights Reserved.
  3. SPDX-License-Identifier: Apache-2.0
  4. History:
  5. Date Who ID Description
  6. -------- --- --- -----------
  7. 01/13/19 nanjj Initial code
  8. */
  9. package dbs
  10. import (
  11. context "context"
  12. "fmt"
  13. "os"
  14. "sort"
  15. "strings"
  16. "sync"
  17. "time"
  18. "github.com/jinzhu/gorm"
  19. _ "github.com/jinzhu/gorm/dialects/postgres"
  20. _ "github.com/jinzhu/gorm/dialects/sqlite"
  21. )
  22. var (
  23. locker = sync.Mutex{}
  24. dbm *gorm.DB
  25. testMode = strings.HasSuffix(os.Args[0], ".test") || os.Getenv("db.testing") != ""
  26. objects = []interface{}{}
  27. migrationErrors = map[string]string{}
  28. upgradeErrors = map[string]string{}
  29. grades = map[string]func(*gorm.DB) error{}
  30. needToUpgrade = false
  31. needToMigrate = false
  32. OpenDB = openDB
  33. )
  34. func openDB() (db *gorm.DB) {
  35. dbType := cfg.GetType()
  36. dbUrl := cfg.GetUri()
  37. dbDebug := cfg.GetDebug()
  38. if testMode {
  39. dbType = "sqlite3"
  40. dbUrl = "file::memory:?cache=shared"
  41. }
  42. if dbType == "" {
  43. dbType = "sqlite3"
  44. dbUrl = "cland.db"
  45. }
  46. var err error
  47. if db, err = gorm.Open(dbType, dbUrl); err != nil {
  48. panic(err)
  49. }
  50. if testMode || dbDebug {
  51. db.LogMode(true)
  52. }
  53. // SetMaxIdleConns sets the maximum number of connections
  54. // in the idle connection pool.
  55. idle := cfg.GetIdle()
  56. db.DB().SetMaxIdleConns(idle)
  57. // SetMaxOpenConns sets the maximum number of open connections
  58. // to the database.
  59. open := cfg.GetOpen()
  60. db.DB().SetMaxOpenConns(open)
  61. // SetConnMaxLifetime set max connection lifetime(in minite)
  62. lifetime := cfg.GetLifetime()
  63. db.DB().SetConnMaxLifetime(time.Minute * time.Duration(lifetime))
  64. return db
  65. }
  66. func newDB() *gorm.DB {
  67. locker.Lock()
  68. defer locker.Unlock()
  69. if dbm == nil {
  70. dbm = OpenDB()
  71. }
  72. doAutoMigrate(dbm)
  73. doAutoUpgrade(dbm)
  74. return dbm
  75. }
  76. func AutoMigrate(values ...interface{}) {
  77. locker.Lock()
  78. defer locker.Unlock()
  79. objects = append(objects, values...)
  80. needToMigrate = true
  81. }
  82. func doAutoMigrate(db *gorm.DB) {
  83. logger, _ := startLogging(context.Background(), "doAutoMigrate")
  84. defer logger.Finish()
  85. if needToMigrate {
  86. names := tableNames(db)
  87. for i := 0; i < len(objects); i++ {
  88. obj := objects[i]
  89. name := names[i]
  90. err := db.AutoMigrate(obj).Error
  91. if err != nil {
  92. logger.Error(err)
  93. msg := err.Error()
  94. if s, ok := migrationErrors[name]; ok {
  95. migrationErrors[name] = fmt.Sprintf("%s\n%s", s, msg)
  96. } else {
  97. migrationErrors[name] = msg
  98. }
  99. }
  100. }
  101. needToMigrate = false
  102. }
  103. }
  104. func AutoUpgrade(name string, grade func(*gorm.DB) error) {
  105. locker.Lock()
  106. defer locker.Unlock()
  107. grades[name] = grade
  108. needToUpgrade = true
  109. }
  110. func doAutoUpgrade(db *gorm.DB) (err error) {
  111. logger, _ := startLogging(context.Background(), "doAutoUpgrade")
  112. defer logger.Finish()
  113. if !needToUpgrade || len(grades) == 0 {
  114. return
  115. }
  116. names := []string{}
  117. for name, _ := range grades {
  118. names = append(names, name)
  119. }
  120. sort.Strings(names)
  121. for _, name := range names {
  122. grade := grades[name]
  123. if grade == nil { // skip nil
  124. continue
  125. }
  126. if err = grade(db); err != nil {
  127. logger.Error(err)
  128. upgradeErrors[name] = err.Error()
  129. continue
  130. }
  131. }
  132. needToUpgrade = false
  133. return
  134. }
  135. func DB() *gorm.DB {
  136. if dbm != nil {
  137. if needToMigrate || needToUpgrade {
  138. locker.Lock()
  139. if needToMigrate {
  140. doAutoMigrate(dbm)
  141. }
  142. if needToUpgrade {
  143. doAutoUpgrade(dbm)
  144. }
  145. locker.Unlock()
  146. }
  147. return dbm
  148. }
  149. return newDB()
  150. }
  151. func SetDB(db *gorm.DB) {
  152. locker.Lock()
  153. defer locker.Unlock()
  154. if db == dbm {
  155. return
  156. }
  157. needToMigrate = true
  158. needToUpgrade = true
  159. dbm = db
  160. }
  161. func TableNames() (names []string) {
  162. if dbm == nil {
  163. return
  164. }
  165. names = tableNames(dbm)
  166. return
  167. }
  168. func tableNames(db *gorm.DB) (names []string) {
  169. for i := 0; i < len(objects); i++ {
  170. obj := objects[i]
  171. names = append(names, db.NewScope(obj).TableName())
  172. }
  173. return
  174. }