gstructs_field.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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 gstructs
  7. import (
  8. "reflect"
  9. "strings"
  10. "github.com/gogf/gf/v2/internal/utils"
  11. "github.com/gogf/gf/v2/util/gtag"
  12. )
  13. const (
  14. jsonTagName = `json`
  15. )
  16. // Tag returns the value associated with key in the tag string. If there is no
  17. // such key in the tag, Tag returns the empty string.
  18. func (f *Field) Tag(key string) string {
  19. s := f.Field.Tag.Get(key)
  20. if s != "" {
  21. s = gtag.Parse(s)
  22. }
  23. return s
  24. }
  25. // TagJsonName returns the `json` tag name string of the field.
  26. func (f *Field) TagJsonName() string {
  27. if jsonTag := f.Tag(jsonTagName); jsonTag != "" {
  28. return strings.Split(jsonTag, ",")[0]
  29. }
  30. return ""
  31. }
  32. // TagLookup returns the value associated with key in the tag string.
  33. // If the key is present in the tag the value (which may be empty)
  34. // is returned. Otherwise, the returned value will be the empty string.
  35. // The ok return value reports whether the value was explicitly set in
  36. // the tag string. If the tag does not have the conventional format,
  37. // the value returned by Lookup is unspecified.
  38. func (f *Field) TagLookup(key string) (value string, ok bool) {
  39. value, ok = f.Field.Tag.Lookup(key)
  40. if ok && value != "" {
  41. value = gtag.Parse(value)
  42. }
  43. return
  44. }
  45. // IsEmbedded returns true if the given field is an anonymous field (embedded)
  46. func (f *Field) IsEmbedded() bool {
  47. return f.Field.Anonymous
  48. }
  49. // TagStr returns the tag string of the field.
  50. func (f *Field) TagStr() string {
  51. return string(f.Field.Tag)
  52. }
  53. // TagMap returns all the tag of the field along with its value string as map.
  54. func (f *Field) TagMap() map[string]string {
  55. var (
  56. data = ParseTag(f.TagStr())
  57. )
  58. for k, v := range data {
  59. data[k] = utils.StripSlashes(gtag.Parse(v))
  60. }
  61. return data
  62. }
  63. // IsExported returns true if the given field is exported.
  64. func (f *Field) IsExported() bool {
  65. return f.Field.PkgPath == ""
  66. }
  67. // Name returns the name of the given field.
  68. func (f *Field) Name() string {
  69. return f.Field.Name
  70. }
  71. // Type returns the type of the given field.
  72. // Note that this Type is not reflect.Type. If you need reflect.Type, please use Field.Type().Type.
  73. func (f *Field) Type() Type {
  74. return Type{
  75. Type: f.Field.Type,
  76. }
  77. }
  78. // Kind returns the reflect.Kind for Value of Field `f`.
  79. func (f *Field) Kind() reflect.Kind {
  80. return f.Value.Kind()
  81. }
  82. // OriginalKind retrieves and returns the original reflect.Kind for Value of Field `f`.
  83. func (f *Field) OriginalKind() reflect.Kind {
  84. var (
  85. kind = f.Value.Kind()
  86. value = f.Value
  87. )
  88. for kind == reflect.Ptr {
  89. value = value.Elem()
  90. kind = value.Kind()
  91. }
  92. return kind
  93. }
  94. // Fields retrieves and returns the fields of `pointer` as slice.
  95. func Fields(in FieldsInput) ([]Field, error) {
  96. var (
  97. ok bool
  98. fieldFilterMap = make(map[string]struct{})
  99. retrievedFields = make([]Field, 0)
  100. currentLevelFieldMap = make(map[string]Field)
  101. )
  102. rangeFields, err := getFieldValues(in.Pointer)
  103. if err != nil {
  104. return nil, err
  105. }
  106. for index := 0; index < len(rangeFields); index++ {
  107. field := rangeFields[index]
  108. currentLevelFieldMap[field.Name()] = field
  109. }
  110. for index := 0; index < len(rangeFields); index++ {
  111. field := rangeFields[index]
  112. if _, ok = fieldFilterMap[field.Name()]; ok {
  113. continue
  114. }
  115. if field.IsEmbedded() {
  116. if in.RecursiveOption != RecursiveOptionNone {
  117. switch in.RecursiveOption {
  118. case RecursiveOptionEmbeddedNoTag:
  119. if field.TagStr() != "" {
  120. break
  121. }
  122. fallthrough
  123. case RecursiveOptionEmbedded:
  124. structFields, err := Fields(FieldsInput{
  125. Pointer: field.Value,
  126. RecursiveOption: in.RecursiveOption,
  127. })
  128. if err != nil {
  129. return nil, err
  130. }
  131. // The current level fields can overwrite the sub-struct fields with the same name.
  132. for i := 0; i < len(structFields); i++ {
  133. var (
  134. structField = structFields[i]
  135. fieldName = structField.Name()
  136. )
  137. if _, ok = fieldFilterMap[fieldName]; ok {
  138. continue
  139. }
  140. fieldFilterMap[fieldName] = struct{}{}
  141. if v, ok := currentLevelFieldMap[fieldName]; !ok {
  142. retrievedFields = append(retrievedFields, structField)
  143. } else {
  144. retrievedFields = append(retrievedFields, v)
  145. }
  146. }
  147. continue
  148. }
  149. }
  150. continue
  151. }
  152. fieldFilterMap[field.Name()] = struct{}{}
  153. retrievedFields = append(retrievedFields, field)
  154. }
  155. return retrievedFields, nil
  156. }
  157. // FieldMap retrieves and returns struct field as map[name/tag]Field from `pointer`.
  158. //
  159. // The parameter `pointer` should be type of struct/*struct.
  160. //
  161. // The parameter `priority` specifies the priority tag array for retrieving from high to low.
  162. // If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.
  163. //
  164. // The parameter `recursive` specifies the whether retrieving the fields recursively if the attribute
  165. // is an embedded struct.
  166. //
  167. // Note that it only retrieves the exported attributes with first letter up-case from struct.
  168. func FieldMap(in FieldMapInput) (map[string]Field, error) {
  169. fields, err := getFieldValues(in.Pointer)
  170. if err != nil {
  171. return nil, err
  172. }
  173. var (
  174. tagValue string
  175. mapField = make(map[string]Field)
  176. )
  177. for _, field := range fields {
  178. // Only retrieve exported attributes.
  179. if !field.IsExported() {
  180. continue
  181. }
  182. tagValue = ""
  183. for _, p := range in.PriorityTagArray {
  184. tagValue = field.Tag(p)
  185. if tagValue != "" && tagValue != "-" {
  186. break
  187. }
  188. }
  189. tempField := field
  190. tempField.TagValue = tagValue
  191. if tagValue != "" {
  192. mapField[tagValue] = tempField
  193. } else {
  194. if in.RecursiveOption != RecursiveOptionNone && field.IsEmbedded() {
  195. switch in.RecursiveOption {
  196. case RecursiveOptionEmbeddedNoTag:
  197. if field.TagStr() != "" {
  198. mapField[field.Name()] = tempField
  199. break
  200. }
  201. fallthrough
  202. case RecursiveOptionEmbedded:
  203. m, err := FieldMap(FieldMapInput{
  204. Pointer: field.Value,
  205. PriorityTagArray: in.PriorityTagArray,
  206. RecursiveOption: in.RecursiveOption,
  207. })
  208. if err != nil {
  209. return nil, err
  210. }
  211. for k, v := range m {
  212. if _, ok := mapField[k]; !ok {
  213. tempV := v
  214. mapField[k] = tempV
  215. }
  216. }
  217. }
  218. } else {
  219. mapField[field.Name()] = tempField
  220. }
  221. }
  222. }
  223. return mapField, nil
  224. }