integrate request builder into HTTP client for googleapis support (#159)
This commit is contained in:
		
							
								
								
									
										114
									
								
								builder/helpers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								builder/helpers.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
package builder
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"google.golang.org/protobuf/reflect/protoreflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// findFieldByPath resolves a dot-separated field path in a protobuf message and returns the protoreflect value and its descriptor.
 | 
			
		||||
func findFieldByPath(msg protoreflect.Message, fieldPath string) (protoreflect.Value, protoreflect.FieldDescriptor, bool) {
 | 
			
		||||
	var (
 | 
			
		||||
		current    = msg
 | 
			
		||||
		parts      = strings.Split(fieldPath, ".")
 | 
			
		||||
		partsCount = len(parts) - 1
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for i, part := range parts {
 | 
			
		||||
		fd, ok := findFieldByName(current, part)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return protoreflect.Value{}, nil, false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		val := current.Get(fd)
 | 
			
		||||
		if i == partsCount { // it's last part
 | 
			
		||||
			return val, fd, true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if fd.Kind() != protoreflect.MessageKind {
 | 
			
		||||
			return protoreflect.Value{}, nil, false
 | 
			
		||||
		}
 | 
			
		||||
		current = val.Message()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return protoreflect.Value{}, nil, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// findFieldByName find a field name in a protobuf message and returns the protoreflect field descriptor.
 | 
			
		||||
func findFieldByName(msg protoreflect.Message, fieldName string) (protoreflect.FieldDescriptor, bool) {
 | 
			
		||||
	fields := msg.Descriptor().Fields()
 | 
			
		||||
	for i := 0; i < fields.Len(); i++ {
 | 
			
		||||
		fd := fields.Get(i)
 | 
			
		||||
		if fd.JSONName() == fieldName {
 | 
			
		||||
			return fd, true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isZeroValue checks if protoreflect.Value is zero for the field.
 | 
			
		||||
func isZeroValue(val protoreflect.Value, fd protoreflect.FieldDescriptor) bool {
 | 
			
		||||
	if fd.IsList() {
 | 
			
		||||
		return val.List().Len() == 0
 | 
			
		||||
	}
 | 
			
		||||
	if fd.IsMap() {
 | 
			
		||||
		return val.Map().Len() == 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch fd.Kind() {
 | 
			
		||||
	case protoreflect.StringKind:
 | 
			
		||||
		return val.String() == ""
 | 
			
		||||
	case protoreflect.BytesKind:
 | 
			
		||||
		return len(val.Bytes()) == 0
 | 
			
		||||
	case protoreflect.BoolKind:
 | 
			
		||||
		return !val.Bool()
 | 
			
		||||
	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind,
 | 
			
		||||
		protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
 | 
			
		||||
		return val.Int() == 0
 | 
			
		||||
	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind,
 | 
			
		||||
		protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
 | 
			
		||||
		return val.Uint() == 0
 | 
			
		||||
	case protoreflect.FloatKind, protoreflect.DoubleKind:
 | 
			
		||||
		return val.Float() == 0
 | 
			
		||||
	case protoreflect.EnumKind:
 | 
			
		||||
		return val.Enum() == 0
 | 
			
		||||
	case protoreflect.MessageKind:
 | 
			
		||||
		return !val.Message().IsValid()
 | 
			
		||||
	default:
 | 
			
		||||
		return !val.IsValid()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// stringifyValue converts protoreflect.Value to string for path/query substitution.
 | 
			
		||||
func stringifyValue(val protoreflect.Value, fd protoreflect.FieldDescriptor) (string, error) {
 | 
			
		||||
	switch fd.Kind() {
 | 
			
		||||
	case protoreflect.StringKind:
 | 
			
		||||
		return val.String(), nil
 | 
			
		||||
	case protoreflect.BytesKind:
 | 
			
		||||
		return base64.StdEncoding.EncodeToString(val.Bytes()), nil
 | 
			
		||||
	case protoreflect.BoolKind:
 | 
			
		||||
		if val.Bool() {
 | 
			
		||||
			return "true", nil
 | 
			
		||||
		}
 | 
			
		||||
		return "false", nil
 | 
			
		||||
	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind,
 | 
			
		||||
		protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
 | 
			
		||||
		return fmt.Sprintf("%d", val.Int()), nil
 | 
			
		||||
	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind,
 | 
			
		||||
		protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
 | 
			
		||||
		return fmt.Sprintf("%d", val.Uint()), nil
 | 
			
		||||
	case protoreflect.FloatKind, protoreflect.DoubleKind:
 | 
			
		||||
		return strconv.FormatFloat(val.Float(), 'g', -1, 64), nil
 | 
			
		||||
	case protoreflect.EnumKind:
 | 
			
		||||
		ed := fd.Enum().Values().ByNumber(val.Enum())
 | 
			
		||||
		if ed != nil {
 | 
			
		||||
			return string(ed.Name()), nil
 | 
			
		||||
		}
 | 
			
		||||
		return fmt.Sprintf("%d", val.Enum()), nil
 | 
			
		||||
	default:
 | 
			
		||||
		return "", fmt.Errorf("unsupported field kind: %s", fd.Kind())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user