mirror of
https://github.com/go-kratos/kratos.git
synced 2025-01-14 02:33:03 +02:00
feat(form/form): add support google.protobuf.Struct; (#1617)
Co-authored-by: soul <chenzhiag@163.com>
This commit is contained in:
parent
c70cdc9a11
commit
0fad751032
@ -8,6 +8,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
"google.golang.org/genproto/protobuf/field_mask"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
@ -33,17 +35,12 @@ func populateFieldValues(v protoreflect.Message, fieldPath []string, values []st
|
||||
if len(values) < 1 {
|
||||
return errors.New("no value provided")
|
||||
}
|
||||
|
||||
var fd protoreflect.FieldDescriptor
|
||||
for i, fieldName := range fieldPath {
|
||||
fields := v.Descriptor().Fields()
|
||||
if fd = getDescriptorByFieldAndName(fields, fieldName); fd == nil {
|
||||
if len(fieldName) > 2 && strings.HasSuffix(fieldName, "[]") {
|
||||
fd = getDescriptorByFieldAndName(fields, strings.TrimSuffix(fieldName, "[]"))
|
||||
}
|
||||
if fd == nil {
|
||||
// ignore unexpected field.
|
||||
return nil
|
||||
}
|
||||
if fd = getFieldDescriptor(v, fieldName); fd == nil {
|
||||
// ignore unexpected field.
|
||||
return nil
|
||||
}
|
||||
|
||||
if i == len(fieldPath)-1 {
|
||||
@ -51,6 +48,10 @@ func populateFieldValues(v protoreflect.Message, fieldPath []string, values []st
|
||||
}
|
||||
|
||||
if fd.Message() == nil || fd.Cardinality() == protoreflect.Repeated {
|
||||
if fd.IsMap() && len(fieldPath) > 1 {
|
||||
// post sub field
|
||||
return populateMapField(fd, v.Mutable(fd).Map(), []string{fieldPath[1]}, values)
|
||||
}
|
||||
return fmt.Errorf("invalid path: %q is not a message", fieldName)
|
||||
}
|
||||
|
||||
@ -65,7 +66,7 @@ func populateFieldValues(v protoreflect.Message, fieldPath []string, values []st
|
||||
case fd.IsList():
|
||||
return populateRepeatedField(fd, v.Mutable(fd).List(), values)
|
||||
case fd.IsMap():
|
||||
return populateMapField(fd, v.Mutable(fd).Map(), values)
|
||||
return populateMapField(fd, v.Mutable(fd).Map(), fieldPath, values)
|
||||
}
|
||||
if len(values) > 1 {
|
||||
return fmt.Errorf("too many values for field %q: %s", fd.FullName().Name(), strings.Join(values, ", "))
|
||||
@ -73,13 +74,23 @@ func populateFieldValues(v protoreflect.Message, fieldPath []string, values []st
|
||||
return populateField(fd, v, values[0])
|
||||
}
|
||||
|
||||
func getFieldDescriptor(v protoreflect.Message, fieldName string) protoreflect.FieldDescriptor {
|
||||
fields := v.Descriptor().Fields()
|
||||
var fd protoreflect.FieldDescriptor
|
||||
if fd = getDescriptorByFieldAndName(fields, fieldName); fd == nil {
|
||||
if v.Descriptor().FullName() == structMessageFullname {
|
||||
fd = fields.ByNumber(structFieldsFieldNumber)
|
||||
} else if len(fieldName) > 2 && strings.HasSuffix(fieldName, "[]") {
|
||||
fd = getDescriptorByFieldAndName(fields, strings.TrimSuffix(fieldName, "[]"))
|
||||
}
|
||||
}
|
||||
return fd
|
||||
}
|
||||
|
||||
func getDescriptorByFieldAndName(fields protoreflect.FieldDescriptors, fieldName string) protoreflect.FieldDescriptor {
|
||||
var fd protoreflect.FieldDescriptor
|
||||
if fd = fields.ByName(protoreflect.Name(fieldName)); fd == nil {
|
||||
fd = fields.ByJSONName(fieldName)
|
||||
if fd == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fd
|
||||
}
|
||||
@ -104,15 +115,17 @@ func populateRepeatedField(fd protoreflect.FieldDescriptor, list protoreflect.Li
|
||||
return nil
|
||||
}
|
||||
|
||||
func populateMapField(fd protoreflect.FieldDescriptor, mp protoreflect.Map, values []string) error {
|
||||
if len(values) != 2 { //nolint:gomnd
|
||||
return fmt.Errorf("more than one value provided for key %q in map %q", values[0], fd.FullName())
|
||||
}
|
||||
key, err := parseField(fd.MapKey(), values[0])
|
||||
func populateMapField(fd protoreflect.FieldDescriptor, mp protoreflect.Map, fieldPath []string, values []string) error {
|
||||
flen := len(fieldPath)
|
||||
vlen := len(values)
|
||||
// post sub key.
|
||||
nkey := flen - 1
|
||||
key, err := parseField(fd.MapKey(), fieldPath[nkey])
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing map key %q: %w", fd.FullName().Name(), err)
|
||||
}
|
||||
value, err := parseField(fd.MapValue(), values[1])
|
||||
vkey := vlen - 1
|
||||
value, err := parseField(fd.MapValue(), values[vkey])
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing map value %q: %w", fd.FullName().Name(), err)
|
||||
}
|
||||
@ -274,6 +287,12 @@ func parseMessage(md protoreflect.MessageDescriptor, value string) (protoreflect
|
||||
fm := &field_mask.FieldMask{}
|
||||
fm.Paths = append(fm.Paths, strings.Split(value, ",")...)
|
||||
msg = fm
|
||||
case "google.protobuf.Value":
|
||||
fm, err := structpb.NewValue(value)
|
||||
if err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
}
|
||||
msg = fm
|
||||
default:
|
||||
return protoreflect.Value{}, fmt.Errorf("unsupported message type: %q", string(md.FullName()))
|
||||
}
|
||||
|
@ -27,6 +27,10 @@ const (
|
||||
// bytes
|
||||
bytesMessageFullname protoreflect.FullName = "google.protobuf.BytesValue"
|
||||
bytesValueFieldNumber protoreflect.FieldNumber = 1
|
||||
|
||||
// google.protobuf.Struct.
|
||||
structMessageFullname protoreflect.FullName = "google.protobuf.Struct"
|
||||
structFieldsFieldNumber protoreflect.FieldNumber = 1
|
||||
)
|
||||
|
||||
func marshalTimestamp(m protoreflect.Message) (string, error) {
|
||||
|
Loading…
Reference in New Issue
Block a user