-
Notifications
You must be signed in to change notification settings - Fork 10
/
encode.go
132 lines (126 loc) · 3.81 KB
/
encode.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package protoavro
import (
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
)
// encodeJSON returns the Avro JSON encoding of message.
func (o SchemaOptions) encodeJSON(message proto.Message) (interface{}, error) {
return o.messageJSON(message.ProtoReflect(), 0)
}
func (o SchemaOptions) unionValue(key string, value interface{}) map[string]interface{} {
return map[string]interface{}{
key: value,
}
}
func (o SchemaOptions) messageJSON(message protoreflect.Message, recursiveIndex int) (interface{}, error) {
if !message.IsValid() {
return nil, nil
}
if isWKT(message.Descriptor().FullName()) {
value, err := o.encodeWKT(message)
if err != nil {
return nil, err
}
return value, nil
}
desc := message.Descriptor()
record := make(map[string]interface{}, desc.Fields().Len())
for i := 0; i < desc.Fields().Len(); i++ {
field := desc.Fields().Get(i)
if field.ContainingOneof() != nil {
if !message.Has(field) {
// dont populate scalar fields belonging to
// a oneof (.Get returns the default value)
record[string(field.Name())] = nil
} else {
value := message.Get(field)
jsonValue, err := o.fieldJSON(field, value, recursiveIndex+1)
if err != nil {
return nil, err
}
record[string(field.Name())] = jsonValue
}
continue
}
value := message.Get(field)
jsonValue, err := o.fieldJSON(field, value, recursiveIndex+1)
if err != nil {
return nil, err
}
record[string(field.Name())] = jsonValue
}
if o.OmitRootElement && recursiveIndex == 0 {
return record, nil
}
return map[string]interface{}{
string(desc.FullName()): record,
}, nil
}
func (o SchemaOptions) fieldJSON(
field protoreflect.FieldDescriptor,
value protoreflect.Value,
recursiveIndex int,
) (interface{}, error) {
if field.IsList() {
list := make([]interface{}, 0, value.List().Len())
for i := 0; i < value.List().Len(); i++ {
v := value.List().Get(i)
fieldValue, err := o.fieldKindJSON(field, v, recursiveIndex)
if err != nil {
return nil, err
}
list = append(list, fieldValue)
}
return o.unionValue("array", list), nil
}
if field.IsMap() {
return o.encodeMap(field, value.Map(), recursiveIndex)
}
return o.fieldKindJSON(field, value, recursiveIndex)
}
func (o SchemaOptions) fieldKindJSON(
field protoreflect.FieldDescriptor,
value protoreflect.Value,
recursiveIndex int,
) (interface{}, error) {
switch field.Kind() {
case protoreflect.MessageKind, protoreflect.GroupKind:
return o.messageJSON(value.Message(), recursiveIndex)
case protoreflect.EnumKind:
if field.Enum().Values().ByNumber(value.Enum()) == nil {
return o.unionValue(
string(field.Enum().FullName()),
string(field.Enum().Values().ByNumber(protoreflect.EnumNumber(0)).Name()),
), nil
}
return o.unionValue(
string(field.Enum().FullName()),
string(field.Enum().Values().ByNumber(value.Enum()).Name()),
), nil
case protoreflect.StringKind:
return o.unionValue("string", value.String()), nil
case protoreflect.Int32Kind,
protoreflect.Fixed32Kind,
protoreflect.Sfixed32Kind,
protoreflect.Sint32Kind:
return o.unionValue("int", int32(value.Int())), nil
case protoreflect.Uint32Kind:
return o.unionValue("int", int32(value.Uint())), nil
case protoreflect.Int64Kind,
protoreflect.Fixed64Kind,
protoreflect.Sfixed64Kind,
protoreflect.Sint64Kind:
return o.unionValue("long", value.Int()), nil
case protoreflect.Uint64Kind:
return o.unionValue("long", int64(value.Uint())), nil
case protoreflect.BoolKind:
return o.unionValue("boolean", value.Bool()), nil
case protoreflect.BytesKind:
return o.unionValue("bytes", value.Bytes()), nil
case protoreflect.DoubleKind:
return o.unionValue("double", value.Float()), nil
case protoreflect.FloatKind:
return o.unionValue("float", float32(value.Float())), nil
}
return value.Interface(), nil
}