query_handle_base.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. if dbEx.RowsAffected == 0 {
  76. response.Resp(c, "update fail")
  77. return
  78. }
  79. if err := db.First(&tempInfo, req.Id).Error; err != nil {
  80. response.Resp(c, err.Error())
  81. return
  82. }
  83. response.Resp(c, map[string]any{
  84. "info": tempInfo,
  85. "rowsAffected": dbEx.RowsAffected,
  86. })
  87. return
  88. }
  89. func (*ModelBaseHandler[T]) Get(c *gin.Context, db *gorm.DB) {
  90. req := new(BaseRequest)
  91. if err := c.BindQuery(req); err != nil {
  92. response.Resp(c, err.Error())
  93. return
  94. }
  95. if req.Id == 0 {
  96. response.Resp(c, "id is zero")
  97. return
  98. }
  99. tempInfo := new(T)
  100. // 先通过Id获取记录'
  101. if err := db.First(&tempInfo, req.Id).Error; err != nil {
  102. response.Resp(c, err.Error())
  103. return
  104. }
  105. response.Resp(c, map[string]any{
  106. "info": tempInfo,
  107. })
  108. return
  109. }
  110. func (*ModelBaseHandler[T]) Create(c *gin.Context, db *gorm.DB) {
  111. req := new(BaseRequest)
  112. if err := c.BindJSON(req); err != nil {
  113. response.Resp(c, err.Error())
  114. return
  115. }
  116. info := new(T)
  117. body, _ := json.Marshal(req.Data)
  118. if err := json.Unmarshal(body, info); err != nil {
  119. response.Resp(c, err.Error())
  120. return
  121. }
  122. if err := db.Create(info).Error; err != nil {
  123. response.Resp(c, err.Error())
  124. return
  125. }
  126. response.Resp(c, map[string]any{
  127. "info": info,
  128. })
  129. }
  130. func (*ModelBaseHandler[T]) List(c *gin.Context, db *gorm.DB) {
  131. req := NewListRequest[T]()
  132. if err := c.BindQuery(req); err != nil {
  133. response.Resp(c, err.Error())
  134. return
  135. }
  136. resp, err := req.Query(db)
  137. if err != nil {
  138. response.Resp(c, err.Error())
  139. return
  140. }
  141. response.Resp(c, resp)
  142. return
  143. }
  144. // structToMapWithZero 将 struct 转为 map,只包含前端实际传递的字段(含零值)
  145. // dataMap 是前端传来的原始 map,用于判断哪些字段是前端实际传递的
  146. func structToMapWithZero(s any, dataMap map[string]any) map[string]any {
  147. result := make(map[string]any)
  148. v := reflect.ValueOf(s)
  149. if v.Kind() == reflect.Ptr {
  150. v = v.Elem()
  151. }
  152. t := v.Type()
  153. for i := 0; i < t.NumField(); i++ {
  154. field := t.Field(i)
  155. jsonTag := field.Tag.Get("json")
  156. if jsonTag == "" || jsonTag == "-" {
  157. continue
  158. }
  159. // 去掉 omitempty 等选项
  160. if idx := len(jsonTag); idx > 0 {
  161. parts := jsonTag
  162. for j := 0; j < len(parts); j++ {
  163. if parts[j] == ',' {
  164. jsonTag = parts[:j]
  165. break
  166. }
  167. }
  168. }
  169. // 只更新前端实际传递的字段
  170. if _, exists := dataMap[jsonTag]; !exists {
  171. continue
  172. }
  173. // 获取 gorm column tag 作为数据库列名
  174. gormTag := field.Tag.Get("gorm")
  175. colName := ""
  176. if gormTag != "" {
  177. for _, part := range splitGormTag(gormTag) {
  178. if len(part) > 7 && part[:7] == "column:" {
  179. colName = part[7:]
  180. break
  181. }
  182. }
  183. }
  184. if colName == "" {
  185. colName = jsonTag
  186. }
  187. result[colName] = v.Field(i).Interface()
  188. }
  189. return result
  190. }
  191. func splitGormTag(tag string) []string {
  192. var parts []string
  193. start := 0
  194. for i := 0; i <= len(tag); i++ {
  195. if i == len(tag) || tag[i] == ';' {
  196. parts = append(parts, tag[start:i])
  197. start = i + 1
  198. }
  199. }
  200. return parts
  201. }