Nenhuma descrição
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

query_yaml_configure.go 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package service
  2. import (
  3. "fmt"
  4. "strconv"
  5. "strings"
  6. "time"
  7. "git.x2erp.com/qdy/go-base/ctx"
  8. "git.x2erp.com/qdy/go-base/logger"
  9. "git.x2erp.com/qdy/go-base/types"
  10. "git.x2erp.com/qdy/go-db/factory/database"
  11. "github.com/jmoiron/sqlx"
  12. )
  13. func QueryYamlConfigure(dbFactory *database.DBFactory, req types.QueryRequest, reqCtx *ctx.RequestContext) *types.QueryResult[map[string]interface{}] {
  14. return query(dbFactory.GetDB(), req, reqCtx)
  15. }
  16. // QueryYamlConfigure 执行带位置参数的查询
  17. func query(db *sqlx.DB, req types.QueryRequest, reqCtx *ctx.RequestContext) *types.QueryResult[map[string]interface{}] {
  18. startTime := time.Now()
  19. // 安全检查
  20. if db == nil {
  21. return createErrorResult("database connection is nil", startTime, reqCtx)
  22. }
  23. sqlStr := `
  24. SELECT b.config_startup_detail_id, b.config_key, b.config_value
  25. FROM config_startup a
  26. JOIN config_startup_detail b ON a.config_startup_id = b.config_startup_id
  27. WHERE a.config_environment_id = $1
  28. AND a.config_service_id = $2;`
  29. params := req.PositionalParams
  30. logger.DebugC(reqCtx, sqlStr)
  31. logger.DebugC(reqCtx, fmt.Sprintf("PositionalParams: %v", params))
  32. // 执行查询
  33. rows, err := db.Queryx(sqlStr, params...)
  34. if err != nil {
  35. return createErrorResult(fmt.Sprintf("Query execution failed: %v", err), startTime, reqCtx)
  36. }
  37. defer rows.Close()
  38. // 处理结果集
  39. return processQueryResult(rows, startTime, reqCtx)
  40. }
  41. func processQueryResult(rows *sqlx.Rows, startTime time.Time, reqCtx *ctx.RequestContext) *types.QueryResult[map[string]interface{}] {
  42. // 初始化结果结构体
  43. result := &types.QueryResult[map[string]interface{}]{
  44. Metadata: reqCtx,
  45. }
  46. // 获取列信息
  47. columns, err := rows.Columns()
  48. if err != nil {
  49. return createErrorResult(fmt.Sprintf("Failed to get columns: %v", err), startTime, reqCtx)
  50. }
  51. // 存储最终结果:根key -> 内层配置map
  52. results := make(map[string]interface{})
  53. count := 0
  54. // 记录已经出现的内层key,用于检测重复
  55. // outerKey -> innerKey -> rowNumber
  56. //keyTracker := make(map[string]map[string]int)
  57. // 遍历行数据
  58. for rows.Next() {
  59. count++
  60. values := make([]interface{}, len(columns))
  61. valuePtrs := make([]interface{}, len(columns))
  62. for i := range columns {
  63. valuePtrs[i] = &values[i]
  64. }
  65. // 扫描行数据
  66. if err := rows.Scan(valuePtrs...); err != nil {
  67. return createErrorResult(fmt.Sprintf("Scan row %d failed: %v", count, err), startTime, reqCtx)
  68. }
  69. // 提取当前行的三个核心字段
  70. var detailID, configKey string
  71. var configValue interface{}
  72. for i, col := range columns {
  73. v := values[i]
  74. if v == nil {
  75. continue
  76. }
  77. switch col {
  78. case "config_startup_detail_id":
  79. detailID = toString(v) // detailID 需要字符串
  80. case "config_key":
  81. configKey = toString(v) // config_key 需要字符串
  82. case "config_value":
  83. configValue = convertValue(v) // config_value 需要带类型转换
  84. }
  85. }
  86. //logger.DebugC(reqCtx, fmt.Sprintf("Row %d - detailID: %s, configKey: %s", count, detailID, configKey))
  87. // 解析 detailID 获取根key(倒数第3段)
  88. parts := strings.Split(detailID, ".")
  89. if len(parts) < 3 {
  90. return createErrorResult(fmt.Sprintf("Row %d detailID format error: %s", count, detailID), startTime, reqCtx)
  91. }
  92. rootKey := parts[len(parts)-3] // 取倒数第3段,例如 "database"
  93. // 获取或创建外层key对应的map
  94. configMap, exists := results[rootKey]
  95. if !exists {
  96. // 不存在则创建
  97. configMap = make(map[string]interface{})
  98. results[rootKey] = configMap
  99. }
  100. // 添加或覆盖内层配置
  101. configMap.(map[string]interface{})[configKey] = configValue
  102. }
  103. // 检查行遍历错误
  104. if err := rows.Err(); err != nil {
  105. return createErrorResult(fmt.Sprintf("Row iteration error: %v", err), startTime, reqCtx)
  106. }
  107. // 构建成功结果
  108. result.Success = true
  109. result.Data = results
  110. result.Count = count
  111. result.Time = time.Since(startTime).String()
  112. result.Message = "Query success"
  113. return result
  114. }
  115. // createErrorResult 创建错误结果的辅助函数(复用你提供的)
  116. func createErrorResult(errorMsg string, startTime time.Time, reqCtx *ctx.RequestContext) *types.QueryResult[map[string]interface{}] {
  117. logger.ErrorC(reqCtx, errorMsg)
  118. return &types.QueryResult[map[string]interface{}]{
  119. Success: false,
  120. Error: errorMsg,
  121. Time: time.Since(startTime).String(),
  122. Metadata: reqCtx,
  123. }
  124. }
  125. // 辅助函数:转换为字符串
  126. func toString(v interface{}) string {
  127. switch val := v.(type) {
  128. case string:
  129. return val
  130. case []byte:
  131. return string(val)
  132. case int64:
  133. return strconv.FormatInt(val, 10)
  134. case int32:
  135. return strconv.FormatInt(int64(val), 10)
  136. case int:
  137. return strconv.Itoa(val)
  138. case float64:
  139. return strconv.FormatFloat(val, 'f', -1, 64)
  140. case float32:
  141. return strconv.FormatFloat(float64(val), 'f', -1, 32)
  142. case bool:
  143. return strconv.FormatBool(val)
  144. default:
  145. return fmt.Sprintf("%v", val)
  146. }
  147. }
  148. // 辅助函数:转换值,保持合适的数据类型
  149. func convertValue(v interface{}) interface{} {
  150. switch val := v.(type) {
  151. case []byte:
  152. // 尝试解析为合适的数据类型
  153. strVal := string(val)
  154. return parseStringValue(strVal)
  155. case string:
  156. return parseStringValue(val)
  157. case int64, int32, int:
  158. return val
  159. case float64, float32:
  160. return val
  161. case bool:
  162. return val
  163. default:
  164. // 其他类型转换为字符串
  165. return toString(val)
  166. }
  167. }
  168. // 辅助函数:解析字符串值为合适的数据类型
  169. func parseStringValue(strVal string) interface{} {
  170. // 1. 尝试布尔值 (支持 true/false, yes/no, on/off, 1/0)
  171. lowerVal := strings.ToLower(strings.TrimSpace(strVal))
  172. if lowerVal == "true" || lowerVal == "yes" || lowerVal == "on" || lowerVal == "1" {
  173. return true
  174. }
  175. if lowerVal == "false" || lowerVal == "no" || lowerVal == "off" || lowerVal == "0" {
  176. return false
  177. }
  178. // 2. 尝试整数
  179. if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil {
  180. return intVal
  181. }
  182. // 3. 尝试浮点数
  183. if floatVal, err := strconv.ParseFloat(strVal, 64); err == nil {
  184. return floatVal
  185. }
  186. // 4. 保持为字符串
  187. return strVal
  188. }