query_handle_base.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package base
  2. import (
  3. "encoding/json"
  4. "github.com/gin-gonic/gin"
  5. "go_server/model/common/response"
  6. "gorm.io/gorm"
  7. "reflect"
  8. )
  9. // gin 封装模型curd处理
  10. // 使用范型 较为鸡肋 不建议使用
  11. type ModelBaseHandler[T any] struct {
  12. }
  13. func NewBaseHandler[T any](t *T) *ModelBaseHandler[T] {
  14. return &ModelBaseHandler[T]{}
  15. }
  16. func (*ModelBaseHandler[T]) DeleteOne(c *gin.Context, db *gorm.DB) {
  17. req := new(BaseRequest)
  18. if err := c.ShouldBindJSON(req); err != nil {
  19. response.Resp(c, err.Error())
  20. return
  21. }
  22. if req.Id == 0 {
  23. response.Resp(c, "id is zero")
  24. return
  25. }
  26. tempInfo := new(T)
  27. // 先通过Id获取记录'
  28. if err := db.First(&tempInfo, req.Id).Error; err != nil {
  29. response.Resp(c, err.Error())
  30. return
  31. }
  32. exCmd := db.Model(&tempInfo).Delete(&tempInfo)
  33. if exCmd.RowsAffected != 1 {
  34. response.Resp(c, "delete fail")
  35. return
  36. }
  37. if exCmd.Error != nil {
  38. response.Resp(c, exCmd.Error.Error())
  39. return
  40. }
  41. response.Resp(c)
  42. return
  43. }
  44. func (*ModelBaseHandler[T]) UpdateOne(c *gin.Context, db *gorm.DB) {
  45. req := new(BaseRequest)
  46. if err := c.BindJSON(req); err != nil {
  47. response.Resp(c, err.Error())
  48. return
  49. }
  50. if req.Id == 0 {
  51. response.Resp(c, "id is zero")
  52. return
  53. }
  54. tempInfo := new(T)
  55. // 先通过Id获取记录'
  56. if err := db.First(&tempInfo, req.Id).Error; err != nil {
  57. response.Resp(c, err.Error())
  58. return
  59. }
  60. // 构建 json tag -> 数据库列名 的映射,用 map 更新以支持零值字段
  61. updateData := new(T)
  62. body, _ := json.Marshal(req.Data)
  63. if err := json.Unmarshal(body, updateData); err != nil {
  64. response.Resp(c, err.Error())
  65. return
  66. }
  67. // 将 struct 转为 map,保留零值字段
  68. updateMap := structToMapWithZero(updateData, req.Data)
  69. dbEx := db.Model(&tempInfo).Where("id", req.Id).
  70. Updates(updateMap)
  71. if dbEx.Error != nil {
  72. response.Resp(c, dbEx.Error.Error())
  73. return
  74. }
  75. // 重新查询最新数据返回
  76. if err := db.First(&tempInfo, req.Id).Error; err != nil {
  77. response.Resp(c, err.Error())
  78. return
  79. }
  80. response.Resp(c, map[string]any{
  81. "info": tempInfo,
  82. "rowsAffected": dbEx.RowsAffected,
  83. })
  84. return
  85. }
  86. func (*ModelBaseHandler[T]) Get(c *gin.Context, db *gorm.DB) {
  87. req := new(BaseRequest)
  88. if err := c.BindQuery(req); err != nil {
  89. response.Resp(c, err.Error())
  90. return
  91. }
  92. if req.Id == 0 {
  93. response.Resp(c, "id is zero")
  94. return
  95. }
  96. tempInfo := new(T)
  97. // 先通过Id获取记录'
  98. if err := db.First(&tempInfo, req.Id).Error; err != nil {
  99. response.Resp(c, err.Error())
  100. return
  101. }
  102. response.Resp(c, map[string]any{
  103. "info": tempInfo,
  104. })
  105. return
  106. }
  107. func (*ModelBaseHandler[T]) Create(c *gin.Context, db *gorm.DB) {
  108. req := new(BaseRequest)
  109. if err := c.BindJSON(req); err != nil {
  110. response.Resp(c, err.Error())
  111. return
  112. }
  113. info := new(T)
  114. body, _ := json.Marshal(req.Data)
  115. if err := json.Unmarshal(body, info); err != nil {
  116. response.Resp(c, err.Error())
  117. return
  118. }
  119. if err := db.Create(info).Error; err != nil {
  120. response.Resp(c, err.Error())
  121. return
  122. }
  123. response.Resp(c, map[string]any{
  124. "info": info,
  125. })
  126. }
  127. func (*ModelBaseHandler[T]) List(c *gin.Context, db *gorm.DB) {
  128. req := NewListRequest[T]()
  129. if err := c.BindQuery(req); err != nil {
  130. response.Resp(c, err.Error())
  131. return
  132. }
  133. resp, err := req.Query(db)
  134. if err != nil {
  135. response.Resp(c, err.Error())
  136. return
  137. }
  138. response.Resp(c, resp)
  139. return
  140. }
  141. // structToMapWithZero 将 struct 转为 map,只包含前端实际传递的字段(含零值)
  142. // dataMap 是前端传来的原始 map,用于判断哪些字段是前端实际传递的
  143. func structToMapWithZero(s any, dataMap map[string]any) map[string]any {
  144. result := make(map[string]any)
  145. v := reflect.ValueOf(s)
  146. if v.Kind() == reflect.Ptr {
  147. v = v.Elem()
  148. }
  149. t := v.Type()
  150. for i := 0; i < t.NumField(); i++ {
  151. field := t.Field(i)
  152. jsonTag := field.Tag.Get("json")
  153. if jsonTag == "" || jsonTag == "-" {
  154. continue
  155. }
  156. // 去掉 omitempty 等选项
  157. if idx := len(jsonTag); idx > 0 {
  158. parts := jsonTag
  159. for j := 0; j < len(parts); j++ {
  160. if parts[j] == ',' {
  161. jsonTag = parts[:j]
  162. break
  163. }
  164. }
  165. }
  166. // 只更新前端实际传递的字段
  167. if _, exists := dataMap[jsonTag]; !exists {
  168. continue
  169. }
  170. // 获取 gorm column tag 作为数据库列名
  171. gormTag := field.Tag.Get("gorm")
  172. colName := ""
  173. if gormTag != "" {
  174. for _, part := range splitGormTag(gormTag) {
  175. if len(part) > 7 && part[:7] == "column:" {
  176. colName = part[7:]
  177. break
  178. }
  179. }
  180. }
  181. if colName == "" {
  182. colName = jsonTag
  183. }
  184. result[colName] = v.Field(i).Interface()
  185. }
  186. return result
  187. }
  188. func splitGormTag(tag string) []string {
  189. var parts []string
  190. start := 0
  191. for i := 0; i <= len(tag); i++ {
  192. if i == len(tag) || tag[i] == ';' {
  193. parts = append(parts, tag[start:i])
  194. start = i + 1
  195. }
  196. }
  197. return parts
  198. }