| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 | 
							- package jsonpb
 
- import (
 
- 	"net/url"
 
- 	"reflect"
 
- 	"strings"
 
- 	"kpt-tmr-group/pkg/xerr"
 
- 	"kpt-tmr-group/pkg/xreflect"
 
- 	"github.com/golang/protobuf/proto"
 
- )
 
- var emptyField = reflect.StructField{}
 
- func UnmarshalQuery(values url.Values, pb proto.Message) error {
 
- 	target := reflect.ValueOf(pb).Elem()
 
- 	targetType := target.Type()
 
- 	if targetType.Kind() != reflect.Struct {
 
- 		return xerr.New("target should be struct")
 
- 	}
 
- 	sprops := proto.GetProperties(targetType)
 
- 	for i := 0; i < target.NumField(); i++ {
 
- 		ft := target.Type().Field(i)
 
- 		if strings.HasPrefix(ft.Name, "XXX_") {
 
- 			continue
 
- 		}
 
- 		getField := func(prop *proto.Properties) ([]string, bool) {
 
- 			// Be liberal in what names we accept; both orig_name and camelName are okay.
 
- 			camel, orig := prop.JSONName, prop.OrigName
 
- 			keys := []string{camel, orig}
 
- 			// handle condition xxx[]=1&xxx[]=2
 
- 			if prop.Repeated {
 
- 				keys = append(keys, camel+"[]", orig+"[]")
 
- 			}
 
- 			for _, key := range keys {
 
- 				v, ok := values[key]
 
- 				if ok {
 
- 					return v, true
 
- 				}
 
- 			}
 
- 			return nil, false
 
- 		}
 
- 		valueForField, ok := getField(sprops.Prop[i])
 
- 		if !ok {
 
- 			continue
 
- 		}
 
- 		err := setProtoByQueryValue(target.Field(i), valueForField, sprops.Prop[i])
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 	}
 
- 	return nil
 
- }
 
- func setProtoByQueryValue(target reflect.Value, queryValue []string, prop *proto.Properties) (err error) {
 
- 	if len(queryValue) == 0 {
 
- 		if prop.HasDefault {
 
- 			queryValue = []string{prop.Default}
 
- 		} else {
 
- 			return nil
 
- 		}
 
- 	}
 
- 	if target.Kind() == reflect.Slice {
 
- 		slice := reflect.MakeSlice(target.Type(), len(queryValue), len(queryValue))
 
- 		for i, s := range queryValue {
 
- 			err := setProtoByQueryValue(slice.Index(i), []string{s}, prop)
 
- 			if err != nil {
 
- 				return err
 
- 			}
 
- 		}
 
- 		target.Set(slice)
 
- 		return nil
 
- 	}
 
- 	// Handle enums, which have an underlying type of int32,
 
- 	// and may appear as strings.
 
- 	// The case of an enum appearing as a number is handled
 
- 	// at the bottom of this function.
 
- 	if prop != nil && prop.Enum != "" {
 
- 		vmap := proto.EnumValueMap(prop.Enum)
 
- 		if len(queryValue) == 1 {
 
- 			// Don't need to do unquoting; valid enum names
 
- 			// are from a limited character set.
 
- 			s := queryValue[0]
 
- 			n, ok := vmap[s]
 
- 			if !ok {
 
- 				return xerr.Errorf("unknown value %q for enum %s", s, prop.Enum)
 
- 			}
 
- 			return setProtoEnum(n, target, prop)
 
- 		}
 
- 	}
 
- 	return xreflect.SetString(target, queryValue[0])
 
- }
 
- func setProtoEnum(val int32, target reflect.Value, prop *proto.Properties) error {
 
- 	if target.Kind() == reflect.Ptr { // proto2
 
- 		target.Set(reflect.New(target.Type().Elem()))
 
- 		target = target.Elem()
 
- 	}
 
- 	if target.Kind() != reflect.Int32 {
 
- 		return xerr.Errorf("invalid target %q for enum %s", target.Kind(), prop.Enum)
 
- 	}
 
- 	target.SetInt(int64(val))
 
- 	return nil
 
- }
 
 
  |