goyave.dev/goyave/v4@v4.4.11/util/reflectutil/reflectutil.go (about) 1 package reflectutil 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "goyave.dev/goyave/v4/util/sliceutil" 8 ) 9 10 // Only extracts the requested field from the given map[string] or structure and 11 // returns a map[string]interface{} containing only those values. 12 // 13 // For example: 14 // 15 // type Model struct { 16 // Field string 17 // Num int 18 // Slice []float64 19 // } 20 // model := Model{ 21 // Field: "value", 22 // Num: 42, 23 // Slice: []float64{3, 6, 9}, 24 // } 25 // res := reflectutil.Only(model, "Field", "Slice") 26 // 27 // Result: 28 // 29 // map[string]interface{}{ 30 // "Field": "value", 31 // "Slice": []float64{3, 6, 9}, 32 // } 33 // 34 // In case of conflicting fields (if a promoted field has the same name as a parent's 35 // struct field), the higher level field is kept. 36 func Only(data interface{}, fields ...string) map[string]interface{} { 37 result := make(map[string]interface{}, len(fields)) 38 t := reflect.TypeOf(data) 39 value := reflect.ValueOf(data) 40 if t.Kind() == reflect.Ptr { 41 t = t.Elem() 42 value = value.Elem() 43 } 44 45 if !value.IsValid() { 46 return result 47 } 48 49 switch t.Kind() { 50 case reflect.Map: 51 if t.Key().Kind() != reflect.String { 52 panic(fmt.Errorf("reflectutil.Only only supports map[string] and structures, %s given", t.String())) 53 } 54 for _, k := range value.MapKeys() { 55 name := k.String() 56 if sliceutil.ContainsStr(fields, name) { 57 result[name] = value.MapIndex(k).Interface() 58 } 59 } 60 case reflect.Struct: 61 for i := 0; i < t.NumField(); i++ { 62 field := value.Field(i) 63 strctType := t.Field(i) 64 fieldType := strctType.Type 65 if fieldType.Kind() == reflect.Ptr { 66 fieldType = fieldType.Elem() 67 } 68 name := strctType.Name 69 if fieldType.Kind() == reflect.Struct && strctType.Anonymous { 70 for k, v := range Only(field.Interface(), fields...) { 71 // Check if fields are conflicting 72 // Highest level fields have priority 73 if _, ok := result[k]; !ok { 74 result[k] = v 75 } 76 } 77 } else if sliceutil.ContainsStr(fields, name) { 78 result[name] = value.Field(i).Interface() 79 } 80 } 81 default: 82 panic(fmt.Errorf("reflectutil.Only only supports map[string] and structures, %s given", t.Kind())) 83 } 84 85 return result 86 }