github.com/gedevops/x@v1.0.3/jsonx/get.go (about) 1 package jsonx 2 3 import ( 4 "reflect" 5 "strings" 6 7 "github.com/stretchr/testify/require" 8 "github.com/tidwall/gjson" 9 ) 10 11 func jsonKey(f reflect.StructField) *string { 12 if jsonTag := f.Tag.Get("json"); jsonTag != "" { 13 if jsonTag == "-" { 14 return nil 15 } 16 return &strings.Split(jsonTag, ",")[0] 17 } else if f.Anonymous { 18 return nil 19 } else if f.IsExported() { 20 return &f.Name 21 } 22 return nil 23 } 24 25 // AllValidJSONKeys returns all JSON keys from the struct or *struct type. 26 // It does not return keys from nested slices, but embedded/nested structs. 27 func AllValidJSONKeys(s interface{}) (keys []string) { 28 t := reflect.TypeOf(s) 29 v := reflect.ValueOf(s) 30 if t.Kind() == reflect.Ptr { 31 t = t.Elem() 32 v = v.Elem() 33 } 34 for i := 0; i < t.NumField(); i++ { 35 f := t.Field(i) 36 jKey := jsonKey(f) 37 if k := f.Type.Kind(); k == reflect.Struct || k == reflect.Ptr { 38 subKeys := AllValidJSONKeys(v.Field(i).Interface()) 39 for _, subKey := range subKeys { 40 if jKey != nil { 41 keys = append(keys, *jKey+"."+subKey) 42 } else { 43 keys = append(keys, subKey) 44 } 45 } 46 } else if jKey != nil { 47 keys = append(keys, *jKey) 48 } 49 } 50 return keys 51 } 52 53 // ParseEnsureKeys returns a result that has the GetRequireValidKey function. 54 func ParseEnsureKeys(original interface{}, raw []byte) *Result { 55 return &Result{ 56 keys: AllValidJSONKeys(original), 57 result: gjson.ParseBytes(raw), 58 } 59 } 60 61 type Result struct { 62 result gjson.Result 63 keys []string 64 } 65 66 // GetRequireValidKey ensures that the key is valid before returning the result. 67 func (r *Result) GetRequireValidKey(t require.TestingT, key string) gjson.Result { 68 require.Contains(t, r.keys, key) 69 return r.result.Get(key) 70 } 71 72 func GetRequireValidKey(t require.TestingT, original interface{}, raw []byte, key string) gjson.Result { 73 return ParseEnsureKeys(original, raw).GetRequireValidKey(t, key) 74 }