Skip to content
Snippets Groups Projects
Select Git revision
  • d83ef1345e3658b4fae3f0fad3ecd2d462d91569
  • main default protected
  • v1.303.0
  • v1.302.0
  • v1.301.0
  • v1.300.0
  • v1.299.0
  • v1.298.0
  • v1.297.0
  • v1.296.0
  • v1.295.0
  • v1.294.0
  • v1.293.0
  • v1.292.0
  • v1.291.0
  • v1.290.0
  • v1.289.0
  • v1.288.0
  • v1.287.0
  • v1.286.0
  • v1.285.0
  • v1.284.0
22 results

get.go

Blame
  • get.go 2.14 KiB
    package reflection
    
    import (
    	"fmt"
    	"reflect"
    	"strings"
    
    	"gitlab.com/uafrica/go-utils/errors"
    )
    
    //Get() a jq-named element from a value
    //e.g. get(reflect.ValueOf(myDoc), ".hits.hits[]._source")
    //the result is an array of _source items which may be
    //just one field inside the hits object in the list
    //
    //see usage in search.TimeSeries.Search() to get documents
    //from the OpenSearch response structure that is very nested
    //and parse using a runtime-created reflect Type, i.e. one
    //cannot get it simply by iterating over res.Hits.[]Hits...
    func Get(v reflect.Value, key string) (reflect.Value, error) {
    	return get("", v, key)
    }
    
    func get(name string, v reflect.Value, key string) (reflect.Value, error) {
    	if key == "" {
    		return v, nil
    	}
    
    	switch v.Kind() {
    	case reflect.Ptr:
    		return get(name, v.Elem(), key)
    
    	case reflect.Struct:
    		if key[0] != '.' {
    			return v, errors.Errorf("get(%s): key=\"%s\" does not start with '.'", name, key)
    		}
    		fieldName := key[1:]
    		remainingKey := ""
    		index := strings.IndexAny(fieldName, ".[")
    		if index > 0 {
    			fieldName = key[1 : index+1]
    			remainingKey = key[index+1:]
    		}
    		t := v.Type()
    		fieldIndex := 0
    		for fieldIndex = 0; fieldIndex < t.NumField(); fieldIndex++ {
    			if strings.SplitN(t.Field(fieldIndex).Tag.Get("json"), ",", 2)[0] == fieldName {
    				break
    			}
    		}
    		if fieldIndex >= t.NumField() {
    			return v, errors.Errorf("%s does not have field %s", name, fieldName)
    		}
    		return get(name+"."+fieldName, v.Field(fieldIndex), remainingKey)
    
    	case reflect.Slice:
    		if !strings.HasPrefix(key, "[]") {
    			return v, errors.Errorf("canot get %s from slice, expecting \"[]\" in the key", key)
    		}
    
    		//make array of results from each item in the slice
    		var result reflect.Value
    		for i := 0; i < v.Len(); i++ {
    			if vv, err := get(fmt.Sprintf("%s[%d]", name, i), v.Index(i), key[2:]); err != nil {
    				return v, errors.Wrapf(err, "failed on %s[%d]", name, i)
    			} else {
    				if !result.IsValid() {
    					result = reflect.MakeSlice(reflect.SliceOf(vv.Type()), 0, v.Len())
    				}
    				result = reflect.Append(result, vv)