feat(form/form): add support google.protobuf.Struct; (#1617)

Co-authored-by: soul <chenzhiag@163.com>
pull/1622/head
Soul 3 years ago committed by GitHub
parent c70cdc9a11
commit 0fad751032
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 53
      encoding/form/proto_decode.go
  2. 4
      encoding/form/well_known_types.go

@ -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,24 +35,23 @@ 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 {
if fd = getFieldDescriptor(v, fieldName); fd == nil {
// ignore unexpected field.
return nil
}
}
if i == len(fieldPath)-1 {
break
}
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…
Cancel
Save