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. 57
      encoding/form/proto_decode.go
  2. 4
      encoding/form/well_known_types.go

@ -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,17 +35,12 @@ 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 { // ignore unexpected field.
if len(fieldName) > 2 && strings.HasSuffix(fieldName, "[]") { return nil
fd = getDescriptorByFieldAndName(fields, strings.TrimSuffix(fieldName, "[]"))
}
if fd == nil {
// ignore unexpected field.
return nil
}
} }
if i == len(fieldPath)-1 { 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.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) {

Loading…
Cancel
Save