github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/define_element_object.go (about) 1 package lang 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 ) 8 9 func ElementLookup(v interface{}, path string) (interface{}, error) { 10 var err error 11 12 if len(path) < 2 { 13 return nil, fmt.Errorf("invalid path for element lookup: `%s` is too short", path) 14 } 15 16 pathSplit := strings.Split(path, path[0:1]) 17 obj := v 18 19 for i := 1; i < len(pathSplit); i++ { 20 if len(pathSplit[i]) == 0 { 21 if i == len(pathSplit)-1 { 22 break 23 } else { 24 return nil, fmt.Errorf("path element %d is a zero length string: '%s'", i-1, strings.Join(pathSplit, "/")) 25 } 26 } 27 28 obj, err = elementRecursiveLookup(pathSplit, i, obj) 29 if err != nil { 30 return nil, err 31 } 32 } 33 34 return obj, nil 35 } 36 37 func elementRecursiveLookup(path []string, i int, obj interface{}) (interface{}, error) { 38 switch v := obj.(type) { 39 case []string: 40 i, err := isValidElementIndex(path[i], len(v)) 41 if err != nil { 42 return nil, err 43 } 44 return v[i], nil 45 46 case []interface{}: 47 i, err := isValidElementIndex(path[i], len(v)) 48 if err != nil { 49 return nil, err 50 } 51 return v[i], nil 52 53 case []map[string]interface{}: 54 i, err := isValidElementIndex(path[i], len(v)) 55 if err != nil { 56 return nil, err 57 } 58 return v[i], nil 59 60 case map[string]string: 61 switch { 62 case v[path[i]] != "": 63 return v[path[i]], nil 64 case v[strings.Title(path[i])] != "": 65 return v[strings.Title(path[i])], nil 66 case v[strings.ToLower(path[i])] != "": 67 return v[strings.ToLower(path[i])], nil 68 case v[strings.ToUpper(path[i])] != "": 69 return v[strings.ToUpper(path[i])], nil 70 //case v[strings.ToTitle(params[i])] != nil: 71 // return v[strings.ToTitle(path[i])], nil 72 default: 73 return "", nil 74 } 75 76 case map[string]interface{}: 77 switch { 78 case v[path[i]] != nil: 79 return v[path[i]], nil 80 case v[strings.Title(path[i])] != nil: 81 return v[strings.Title(path[i])], nil 82 case v[strings.ToLower(path[i])] != nil: 83 return v[strings.ToLower(path[i])], nil 84 case v[strings.ToUpper(path[i])] != nil: 85 return v[strings.ToUpper(path[i])], nil 86 //case v[strings.ToTitle(params[i])] != nil: 87 // return v[strings.ToTitle(path[i])], nil 88 default: 89 return nil, fmt.Errorf("key '%s' not found", path[i]) 90 } 91 92 case map[interface{}]interface{}: 93 switch { 94 case v[path[i]] != nil: 95 return v[path[i]], nil 96 case v[strings.Title(path[i])] != nil: 97 return v[strings.Title(path[i])], nil 98 case v[strings.ToLower(path[i])] != nil: 99 return v[strings.ToLower(path[i])], nil 100 case v[strings.ToUpper(path[i])] != nil: 101 return v[strings.ToUpper(path[i])], nil 102 //case v[strings.ToTitle(params[i])] != nil: 103 // return v[strings.ToTitle(path[i])], nil 104 default: 105 return nil, fmt.Errorf("key '%s' not found", path[i]) 106 } 107 108 case string, int, float64, bool, nil, []byte, []rune: 109 return nil, fmt.Errorf("primitives like %T cannot be split to return property '%s'", v, path[i]) 110 111 case MxInterface: 112 return elementRecursiveLookup(path, i, v.GetValue()) 113 114 default: 115 return nil, fmt.Errorf("murex doesn't know how to lookup `%T` (please file a bug with on the murex Github page: https://lmorg/murex)", v) 116 } 117 } 118 119 func isValidElementIndex(key string, length int) (int, error) { 120 i, err := strconv.Atoi(key) 121 if err != nil { 122 return 0, fmt.Errorf("element is an array however supplied key, '%s', is not an integer", key) 123 } 124 125 if i < 0 { 126 return 0, fmt.Errorf("negative keys are not allowed for arrays: %s", key) 127 } 128 129 if i >= length { 130 return 0, fmt.Errorf("element is an array however key is greater than the length: %s", key) 131 } 132 133 return i, nil 134 }