blob: e1cf7a91461f86bf9473c4d80748abf490dc70e9 [file] [log] [blame]
khenaidoo59ce9dd2019-11-11 13:05:32 -05001package runtime
2
3import (
4 "encoding/json"
5 "io"
6 "strings"
7
8 "github.com/golang/protobuf/protoc-gen-go/generator"
9 "google.golang.org/genproto/protobuf/field_mask"
10)
11
12// FieldMaskFromRequestBody creates a FieldMask printing all complete paths from the JSON body.
13func FieldMaskFromRequestBody(r io.Reader) (*field_mask.FieldMask, error) {
14 fm := &field_mask.FieldMask{}
15 var root interface{}
16 if err := json.NewDecoder(r).Decode(&root); err != nil {
17 if err == io.EOF {
18 return fm, nil
19 }
20 return nil, err
21 }
22
23 queue := []fieldMaskPathItem{{node: root}}
24 for len(queue) > 0 {
25 // dequeue an item
26 item := queue[0]
27 queue = queue[1:]
28
29 if m, ok := item.node.(map[string]interface{}); ok {
30 // if the item is an object, then enqueue all of its children
31 for k, v := range m {
32 queue = append(queue, fieldMaskPathItem{path: append(item.path, generator.CamelCase(k)), node: v})
33 }
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, "."))
37 }
38 }
39
40 return fm, nil
41}
42
43// fieldMaskPathItem stores a in-progress deconstruction of a path for a fieldmask
44type fieldMaskPathItem struct {
45 // the list of prior fields leading up to node
46 path []string
47
48 // a generic decoded json object the current item to inspect for further path extraction
49 node interface{}
50}
51
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.
54func CamelCaseFieldMask(mask *field_mask.FieldMask) {
55 if mask == nil || mask.Paths == nil {
56 return
57 }
58
59 var newPaths []string
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))
65 }
66 newPaths = append(newPaths, strings.Join(camelCasedParts, "."))
67 }
68
69 mask.Paths = newPaths
70}