gconv_maptomaps.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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 gconv
  7. import (
  8. "github.com/gogf/gf/errors/gcode"
  9. "github.com/gogf/gf/errors/gerror"
  10. "github.com/gogf/gf/internal/json"
  11. "reflect"
  12. )
  13. // MapToMaps converts any slice type variable `params` to another map slice type variable `pointer`.
  14. // See doMapToMaps.
  15. func MapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) error {
  16. return doMapToMaps(params, pointer, mapping...)
  17. }
  18. // MapToMapsDeep converts any slice type variable `params` to another map slice type variable
  19. // `pointer` recursively.
  20. // Deprecated, use MapToMaps instead.
  21. func MapToMapsDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error {
  22. return doMapToMaps(params, pointer, mapping...)
  23. }
  24. // doMapToMaps converts any map type variable `params` to another map slice variable `pointer`.
  25. //
  26. // The parameter `params` can be type of []map, []*map, []struct, []*struct.
  27. //
  28. // The parameter `pointer` should be type of []map, []*map.
  29. //
  30. // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
  31. // sense only if the item of `params` is type struct.
  32. func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
  33. // If given `params` is JSON, it then uses json.Unmarshal doing the converting.
  34. switch r := params.(type) {
  35. case []byte:
  36. if json.Valid(r) {
  37. if rv, ok := pointer.(reflect.Value); ok {
  38. if rv.Kind() == reflect.Ptr {
  39. return json.UnmarshalUseNumber(r, rv.Interface())
  40. }
  41. } else {
  42. return json.UnmarshalUseNumber(r, pointer)
  43. }
  44. }
  45. case string:
  46. if paramsBytes := []byte(r); json.Valid(paramsBytes) {
  47. if rv, ok := pointer.(reflect.Value); ok {
  48. if rv.Kind() == reflect.Ptr {
  49. return json.UnmarshalUseNumber(paramsBytes, rv.Interface())
  50. }
  51. } else {
  52. return json.UnmarshalUseNumber(paramsBytes, pointer)
  53. }
  54. }
  55. }
  56. // Params and its element type check.
  57. var (
  58. paramsRv reflect.Value
  59. paramsKind reflect.Kind
  60. )
  61. if v, ok := params.(reflect.Value); ok {
  62. paramsRv = v
  63. } else {
  64. paramsRv = reflect.ValueOf(params)
  65. }
  66. paramsKind = paramsRv.Kind()
  67. if paramsKind == reflect.Ptr {
  68. paramsRv = paramsRv.Elem()
  69. paramsKind = paramsRv.Kind()
  70. }
  71. if paramsKind != reflect.Array && paramsKind != reflect.Slice {
  72. return gerror.NewCode(gcode.CodeInvalidParameter, "params should be type of slice, eg: []map/[]*map/[]struct/[]*struct")
  73. }
  74. var (
  75. paramsElem = paramsRv.Type().Elem()
  76. paramsElemKind = paramsElem.Kind()
  77. )
  78. if paramsElemKind == reflect.Ptr {
  79. paramsElem = paramsElem.Elem()
  80. paramsElemKind = paramsElem.Kind()
  81. }
  82. if paramsElemKind != reflect.Map && paramsElemKind != reflect.Struct && paramsElemKind != reflect.Interface {
  83. return gerror.NewCodef(gcode.CodeInvalidParameter, "params element should be type of map/*map/struct/*struct, but got: %s", paramsElemKind)
  84. }
  85. // Empty slice, no need continue.
  86. if paramsRv.Len() == 0 {
  87. return nil
  88. }
  89. // Pointer and its element type check.
  90. var (
  91. pointerRv = reflect.ValueOf(pointer)
  92. pointerKind = pointerRv.Kind()
  93. )
  94. for pointerKind == reflect.Ptr {
  95. pointerRv = pointerRv.Elem()
  96. pointerKind = pointerRv.Kind()
  97. }
  98. if pointerKind != reflect.Array && pointerKind != reflect.Slice {
  99. return gerror.NewCode(gcode.CodeInvalidParameter, "pointer should be type of *[]map/*[]*map")
  100. }
  101. var (
  102. pointerElemType = pointerRv.Type().Elem()
  103. pointerElemKind = pointerElemType.Kind()
  104. )
  105. if pointerElemKind == reflect.Ptr {
  106. pointerElemKind = pointerElemType.Elem().Kind()
  107. }
  108. if pointerElemKind != reflect.Map {
  109. return gerror.NewCode(gcode.CodeInvalidParameter, "pointer element should be type of map/*map")
  110. }
  111. defer func() {
  112. // Catch the panic, especially the reflect operation panics.
  113. if exception := recover(); exception != nil {
  114. if e, ok := exception.(errorStack); ok {
  115. err = e
  116. } else {
  117. err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception)
  118. }
  119. }
  120. }()
  121. var (
  122. pointerSlice = reflect.MakeSlice(pointerRv.Type(), paramsRv.Len(), paramsRv.Len())
  123. )
  124. for i := 0; i < paramsRv.Len(); i++ {
  125. var item reflect.Value
  126. if pointerElemType.Kind() == reflect.Ptr {
  127. item = reflect.New(pointerElemType.Elem())
  128. if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil {
  129. return err
  130. }
  131. pointerSlice.Index(i).Set(item)
  132. } else {
  133. item = reflect.New(pointerElemType)
  134. if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil {
  135. return err
  136. }
  137. pointerSlice.Index(i).Set(item.Elem())
  138. }
  139. }
  140. pointerRv.Set(pointerSlice)
  141. return
  142. }