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  }