8 "github.com/golang/protobuf/protoc-gen-go/generator"
9 "google.golang.org/genproto/protobuf/field_mask"
12 // FieldMaskFromRequestBody creates a FieldMask printing all complete paths from the JSON body.
13 func FieldMaskFromRequestBody(r io.Reader) (*field_mask.FieldMask, error) {
14 fm := &field_mask.FieldMask{}
16 if err := json.NewDecoder(r).Decode(&root); err != nil {
23 queue := []fieldMaskPathItem{{node: root}}
29 if m, ok := item.node.(map[string]interface{}); ok {
30 // if the item is an object, then enqueue all of its children
32 queue = append(queue, fieldMaskPathItem{path: append(item.path, generator.CamelCase(k)), node: v})
34 } else if len(item.path) > 0 {
35 // otherwise, it's a leaf node so print its path
36 fm.Paths = append(fm.Paths, strings.Join(item.path, "."))
43 // fieldMaskPathItem stores a in-progress deconstruction of a path for a fieldmask
44 type fieldMaskPathItem struct {
45 // the list of prior fields leading up to node
48 // a generic decoded json object the current item to inspect for further path extraction
52 // CamelCaseFieldMask updates the given FieldMask by converting all of its paths to CamelCase, using the same heuristic
53 // that's used for naming protobuf fields in Go.
54 func CamelCaseFieldMask(mask *field_mask.FieldMask) {
55 if mask == nil || mask.Paths == nil {
60 for _, path := range mask.Paths {
61 lowerCasedParts := strings.Split(path, ".")
62 var camelCasedParts []string
63 for _, part := range lowerCasedParts {
64 camelCasedParts = append(camelCasedParts, generator.CamelCase(part))
66 newPaths = append(newPaths, strings.Join(camelCasedParts, "."))