Files
micro-client-http/builder/body.go
pugnack 24801750a7
Some checks failed
coverage / build (push) Successful in 2m19s
test / test (push) Failing after 17m15s
integrate request builder into HTTP client for googleapis support (#157)
2025-09-23 13:30:15 +03:00

117 lines
2.8 KiB
Go

package builder
import (
"fmt"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
)
func buildSingleFieldBody(msg proto.Message, fieldName string) (proto.Message, error) {
msgReflect := msg.ProtoReflect()
fd, found := findFieldByName(msgReflect, fieldName)
if !found || fd == nil {
return nil, fmt.Errorf("field %s not found", fieldName)
}
if !msgReflect.Has(fd) {
return nil, fmt.Errorf("field %s is not set", fieldName)
}
val := msgReflect.Get(fd)
if fd.Kind() == protoreflect.MessageKind {
return val.Message().Interface(), nil
}
newMsg := proto.Clone(msg)
newMsgReflect := newMsg.ProtoReflect()
newMsgReflect.Range(func(f protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
if f != fd {
newMsgReflect.Clear(f)
}
return true
})
return newMsg, nil
}
func buildFullBody(msg proto.Message, usedFieldsPath *usedFields) (proto.Message, error) {
var (
msgReflect = msg.ProtoReflect()
newMsg = msgReflect.New().Interface()
newMsgReflect = newMsg.ProtoReflect()
)
fields := msgReflect.Descriptor().Fields()
for i := 0; i < fields.Len(); i++ {
fd := fields.Get(i)
fieldName := fd.JSONName()
if usedFieldsPath.hasTopLevelKey(fieldName) {
continue
}
val := msgReflect.Get(fd)
if !val.IsValid() {
continue
}
// Note: order of the cases is important!
switch {
case fd.IsList():
list := val.List()
newList := newMsgReflect.Mutable(fd).List()
if fd.Kind() == protoreflect.MessageKind {
for j := 0; j < list.Len(); j++ {
elem, err := buildFullBody(list.Get(j).Message().Interface(), usedFieldsPath)
if err != nil {
return nil, fmt.Errorf("recursive build full body: %w", err)
}
newList.Append(protoreflect.ValueOfMessage(elem.ProtoReflect()))
}
} else {
for j := 0; j < list.Len(); j++ {
newList.Append(list.Get(j))
}
}
case fd.IsMap():
var (
m = val.Map()
newMap = newMsgReflect.Mutable(fd).Map()
rangeErr error
)
m.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
if fd.MapValue().Kind() == protoreflect.MessageKind {
elem, err := buildFullBody(v.Message().Interface(), usedFieldsPath)
if err != nil {
rangeErr = fmt.Errorf("recursive build full body: %w", err)
return false
}
newMap.Set(k, protoreflect.ValueOfMessage(elem.ProtoReflect()))
} else {
newMap.Set(k, v)
}
return true
})
if rangeErr != nil {
return nil, fmt.Errorf("map range error: %w", rangeErr)
}
case fd.Kind() == protoreflect.MessageKind:
elem, err := buildFullBody(val.Message().Interface(), usedFieldsPath)
if err != nil {
return nil, fmt.Errorf("recursive build full body: %w", err)
}
newMsgReflect.Set(fd, protoreflect.ValueOfMessage(elem.ProtoReflect()))
default:
newMsgReflect.Set(fd, val)
}
}
return newMsg, nil
}