gins_database.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gins
  7. import (
  8. "context"
  9. "fmt"
  10. "github.com/gogf/gf/v2/database/gdb"
  11. "github.com/gogf/gf/v2/errors/gcode"
  12. "github.com/gogf/gf/v2/errors/gerror"
  13. "github.com/gogf/gf/v2/internal/consts"
  14. "github.com/gogf/gf/v2/internal/intlog"
  15. "github.com/gogf/gf/v2/os/gcfg"
  16. "github.com/gogf/gf/v2/os/glog"
  17. "github.com/gogf/gf/v2/util/gconv"
  18. "github.com/gogf/gf/v2/util/gutil"
  19. )
  20. const (
  21. frameCoreComponentNameDatabase = "gf.core.component.database"
  22. )
  23. // Database returns an instance of database ORM object with specified configuration group name.
  24. // Note that it panics if any error occurs duration instance creating.
  25. func Database(name ...string) gdb.DB {
  26. var (
  27. ctx = context.Background()
  28. group = gdb.DefaultGroupName
  29. )
  30. if len(name) > 0 && name[0] != "" {
  31. group = name[0]
  32. }
  33. instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameDatabase, group)
  34. db := localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
  35. // It ignores returned error to avoid file no found error while it's not necessary.
  36. var (
  37. configMap map[string]interface{}
  38. configNodeKey = consts.ConfigNodeNameDatabase
  39. )
  40. // It firstly searches the configuration of the instance name.
  41. if configData, _ := Config().Data(ctx); len(configData) > 0 {
  42. if v, _ := gutil.MapPossibleItemByKey(configData, consts.ConfigNodeNameDatabase); v != "" {
  43. configNodeKey = v
  44. }
  45. }
  46. if v, _ := Config().Get(ctx, configNodeKey); !v.IsEmpty() {
  47. configMap = v.Map()
  48. }
  49. // No configuration found, it formats and panics error.
  50. if len(configMap) == 0 && !gdb.IsConfigured() {
  51. // File configuration object checks.
  52. var err error
  53. if fileConfig, ok := Config().GetAdapter().(*gcfg.AdapterFile); ok {
  54. if _, err = fileConfig.GetFilePath(); err != nil {
  55. panic(gerror.WrapCode(gcode.CodeMissingConfiguration, err,
  56. `configuration not found, did you miss the configuration file or misspell the configuration file name`,
  57. ))
  58. }
  59. }
  60. // Panic if nothing found in Config object or in gdb configuration.
  61. if len(configMap) == 0 && !gdb.IsConfigured() {
  62. panic(gerror.NewCodef(
  63. gcode.CodeMissingConfiguration,
  64. `database initialization failed: configuration missing for database node "%s"`,
  65. consts.ConfigNodeNameDatabase,
  66. ))
  67. }
  68. }
  69. if len(configMap) == 0 {
  70. configMap = make(map[string]interface{})
  71. }
  72. // Parse `m` as map-slice and adds it to global configurations for package gdb.
  73. for g, groupConfig := range configMap {
  74. cg := gdb.ConfigGroup{}
  75. switch value := groupConfig.(type) {
  76. case []interface{}:
  77. for _, v := range value {
  78. if node := parseDBConfigNode(v); node != nil {
  79. cg = append(cg, *node)
  80. }
  81. }
  82. case map[string]interface{}:
  83. if node := parseDBConfigNode(value); node != nil {
  84. cg = append(cg, *node)
  85. }
  86. }
  87. if len(cg) > 0 {
  88. if gdb.GetConfig(group) == nil {
  89. intlog.Printf(ctx, "add configuration for group: %s, %#v", g, cg)
  90. gdb.SetConfigGroup(g, cg)
  91. } else {
  92. intlog.Printf(ctx, "ignore configuration as it already exists for group: %s, %#v", g, cg)
  93. intlog.Printf(ctx, "%s, %#v", g, cg)
  94. }
  95. }
  96. }
  97. // Parse `m` as a single node configuration,
  98. // which is the default group configuration.
  99. if node := parseDBConfigNode(configMap); node != nil {
  100. cg := gdb.ConfigGroup{}
  101. if node.Link != "" || node.Host != "" {
  102. cg = append(cg, *node)
  103. }
  104. if len(cg) > 0 {
  105. if gdb.GetConfig(group) == nil {
  106. intlog.Printf(ctx, "add configuration for group: %s, %#v", gdb.DefaultGroupName, cg)
  107. gdb.SetConfigGroup(gdb.DefaultGroupName, cg)
  108. } else {
  109. intlog.Printf(
  110. ctx,
  111. "ignore configuration as it already exists for group: %s, %#v",
  112. gdb.DefaultGroupName, cg,
  113. )
  114. intlog.Printf(ctx, "%s, %#v", gdb.DefaultGroupName, cg)
  115. }
  116. }
  117. }
  118. // Create a new ORM object with given configurations.
  119. if db, err := gdb.NewByGroup(name...); err == nil {
  120. // Initialize logger for ORM.
  121. var (
  122. loggerConfigMap map[string]interface{}
  123. loggerNodeName = fmt.Sprintf("%s.%s", configNodeKey, consts.ConfigNodeNameLogger)
  124. )
  125. if v, _ := Config().Get(ctx, loggerNodeName); !v.IsEmpty() {
  126. loggerConfigMap = v.Map()
  127. }
  128. if len(loggerConfigMap) == 0 {
  129. if v, _ := Config().Get(ctx, configNodeKey); !v.IsEmpty() {
  130. loggerConfigMap = v.Map()
  131. }
  132. }
  133. if len(loggerConfigMap) > 0 {
  134. if logger, ok := db.GetLogger().(*glog.Logger); ok {
  135. if err = logger.SetConfigWithMap(loggerConfigMap); err != nil {
  136. panic(err)
  137. }
  138. }
  139. }
  140. return db
  141. } else {
  142. // If panics, often because it does not find its configuration for given group.
  143. panic(err)
  144. }
  145. return nil
  146. })
  147. if db != nil {
  148. return db.(gdb.DB)
  149. }
  150. return nil
  151. }
  152. func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
  153. nodeMap, ok := value.(map[string]interface{})
  154. if !ok {
  155. return nil
  156. }
  157. var (
  158. node = &gdb.ConfigNode{}
  159. err = gconv.Struct(nodeMap, node)
  160. )
  161. if err != nil {
  162. panic(err)
  163. }
  164. // Find possible `Link` configuration content.
  165. if _, v := gutil.MapPossibleItemByKey(nodeMap, "Link"); v != nil {
  166. node.Link = gconv.String(v)
  167. }
  168. return node
  169. }