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