Нет описания
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

query_builder.go 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package queryreq
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. // FieldMapper 字段映射函数类型:前端字段名 -> 数据库列名
  7. type FieldMapper func(string) string
  8. // DefaultFieldMapper 默认字段映射(直接使用原字段名)
  9. func DefaultFieldMapper(field string) string {
  10. return field
  11. }
  12. // BuildWhereClause 安全构建WHERE子句
  13. // 返回: WHERE条件字符串, 参数值数组
  14. func BuildWhereClause(filters []FilterParam, fieldMapper FieldMapper) (string, []interface{}) {
  15. if len(filters) == 0 {
  16. return "", nil
  17. }
  18. var conditions []string
  19. var args []interface{}
  20. for _, filter := range filters {
  21. if !filter.Operator.IsValid() {
  22. continue
  23. }
  24. // 获取安全的数据库列名
  25. dbField := fieldMapper(filter.Field)
  26. if dbField == "" {
  27. continue // 无效字段,跳过
  28. }
  29. // 根据运算符构建条件
  30. condition, filterArgs := buildCondition(dbField, filter.Operator, filter.Value)
  31. if condition != "" {
  32. conditions = append(conditions, condition)
  33. args = append(args, filterArgs...)
  34. }
  35. }
  36. if len(conditions) == 0 {
  37. return "", nil
  38. }
  39. return "WHERE " + strings.Join(conditions, " AND "), args
  40. }
  41. // BuildOrderByClause 安全构建ORDER BY子句
  42. // 返回: ORDER BY子句字符串
  43. func BuildOrderByClause(sorts []SortParam, fieldMapper FieldMapper) string {
  44. if len(sorts) == 0 {
  45. return ""
  46. }
  47. var orderClauses []string
  48. for _, sort := range sorts {
  49. // 获取安全的数据库列名
  50. dbField := fieldMapper(sort.Field)
  51. if dbField == "" {
  52. continue // 无效字段,跳过
  53. }
  54. // 验证排序方向
  55. order := strings.ToUpper(sort.Order)
  56. if order != "ASC" && order != "DESC" {
  57. order = "ASC" // 默认升序
  58. }
  59. orderClauses = append(orderClauses, fmt.Sprintf("%s %s", dbField, order))
  60. }
  61. if len(orderClauses) == 0 {
  62. return ""
  63. }
  64. return "ORDER BY " + strings.Join(orderClauses, ", ")
  65. }
  66. // buildCondition 构建单个筛选条件
  67. func buildCondition(field string, operator Operator, value interface{}) (string, []interface{}) {
  68. switch operator {
  69. case OpEquals, OpNotEquals, OpGreaterThan, OpLessThan, OpGreaterOrEq, OpLessOrEq:
  70. return fmt.Sprintf("%s %s ?", field, operator.ToSQL()), []interface{}{value}
  71. case OpLike:
  72. // LIKE操作自动添加通配符
  73. if strVal, ok := value.(string); ok {
  74. return fmt.Sprintf("%s LIKE ?", field), []interface{}{"%" + strVal + "%"}
  75. }
  76. // 非字符串类型,直接使用值
  77. return fmt.Sprintf("%s LIKE ?", field), []interface{}{value}
  78. case OpIn:
  79. return buildInCondition(field, value)
  80. default:
  81. return "", nil
  82. }
  83. }
  84. // buildInCondition 构建IN条件
  85. func buildInCondition(field string, value interface{}) (string, []interface{}) {
  86. // 处理IN操作符的值
  87. values, ok := processInValue(value)
  88. if !ok || len(values) == 0 {
  89. return "", nil
  90. }
  91. // 构建占位符 (?, ?, ?)
  92. placeholders := strings.Repeat("?, ", len(values))
  93. placeholders = placeholders[:len(placeholders)-2] // 移除最后的逗号和空格
  94. return fmt.Sprintf("%s IN (%s)", field, placeholders), values
  95. }
  96. // processInValue 处理IN操作符的值,转换为参数数组
  97. // 支持逗号分隔的字符串、字符串数组、接口数组等
  98. func processInValue(value interface{}) ([]interface{}, bool) {
  99. switch v := value.(type) {
  100. case string:
  101. // 逗号分隔的字符串
  102. if strings.Contains(v, ",") {
  103. parts := strings.Split(v, ",")
  104. var result []interface{}
  105. for _, part := range parts {
  106. trimmed := strings.TrimSpace(part)
  107. if trimmed != "" {
  108. // 尝试解析为数值
  109. if num, err := parseNumber(trimmed); err == nil {
  110. result = append(result, num)
  111. } else {
  112. result = append(result, trimmed)
  113. }
  114. }
  115. }
  116. return result, len(result) > 0
  117. }
  118. // 单个字符串值
  119. return []interface{}{v}, true
  120. case []string:
  121. // 字符串数组
  122. var result []interface{}
  123. for _, item := range v {
  124. if trimmed := strings.TrimSpace(item); trimmed != "" {
  125. if num, err := parseNumber(trimmed); err == nil {
  126. result = append(result, num)
  127. } else {
  128. result = append(result, trimmed)
  129. }
  130. }
  131. }
  132. return result, len(result) > 0
  133. case []interface{}:
  134. // 接口数组
  135. var result []interface{}
  136. for _, item := range v {
  137. if item != nil {
  138. result = append(result, item)
  139. }
  140. }
  141. return result, len(result) > 0
  142. default:
  143. // 其他类型视为单个值
  144. return []interface{}{v}, true
  145. }
  146. }
  147. // parseNumber 尝试将字符串解析为数值
  148. func parseNumber(s string) (interface{}, error) {
  149. // 尝试解析为整数
  150. if intVal, err := parseInt(s); err == nil {
  151. return intVal, nil
  152. }
  153. // 尝试解析为浮点数
  154. if floatVal, err := parseFloat(s); err == nil {
  155. return floatVal, nil
  156. }
  157. return nil, fmt.Errorf("not a number")
  158. }
  159. // parseInt 解析整数
  160. func parseInt(s string) (int64, error) {
  161. var val int64
  162. _, err := fmt.Sscanf(s, "%d", &val)
  163. return val, err
  164. }
  165. // parseFloat 解析浮点数
  166. func parseFloat(s string) (float64, error) {
  167. var val float64
  168. _, err := fmt.Sscanf(s, "%f", &val)
  169. return val, err
  170. }