Skip to content

Commit 2905c5e

Browse files
committed
Adding ability to use JSON Names for pb fields
This adds a simple variable to map the fields to the JSONName() instead of Name() on the protobuf field descriptors. This allows for using cel expressions against the same JSON representations in some scenarios. The default behavior is identical. Test has been added to validate field names with setting turned on
1 parent 305809d commit 2905c5e

File tree

2 files changed

+90
-1
lines changed

2 files changed

+90
-1
lines changed

common/types/pb/type.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ import (
3030
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
3131
)
3232

33+
var (
34+
// UseJSONFieldNames enables protobuf JSON field names for field access instead of the short name of the declaration.
35+
//
36+
// This should be set before any types are loaded into the Db.
37+
//
38+
// For example, given a proto field declaration:
39+
//
40+
// message Sample {
41+
// int32 sample_field = 1;
42+
// }
43+
//
44+
// The default field name for access is "sample_field". If UseJSONFieldNames is set to true,
45+
// the field name for access becomes "sampleField".
46+
UseJSONFieldNames = false
47+
)
48+
3349
// description is a private interface used to make it convenient to perform type unwrapping at
3450
// the TypeDescription or FieldDescription level.
3551
type description interface {
@@ -47,7 +63,11 @@ func newTypeDescription(typeName string, desc protoreflect.MessageDescriptor, ex
4763
fields := desc.Fields()
4864
for i := 0; i < fields.Len(); i++ {
4965
f := fields.Get(i)
50-
fieldMap[string(f.Name())] = newFieldDescription(f)
66+
if UseJSONFieldNames {
67+
fieldMap[string(f.JSONName())] = newFieldDescription(f)
68+
} else {
69+
fieldMap[string(f.Name())] = newFieldDescription(f)
70+
}
5171
}
5272
return &TypeDescription{
5373
typeName: typeName,

common/types/pb/type_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,75 @@ func TestFieldDescriptionGetFrom(t *testing.T) {
210210
}
211211
}
212212

213+
func TestFieldDescriptionGetFromJSON(t *testing.T) {
214+
UseJSONFieldNames = true
215+
defer func() { UseJSONFieldNames = false }()
216+
217+
pbdb := NewDb()
218+
msg := &proto3pb.TestAllTypes{
219+
SingleUint64: 12,
220+
SingleDuration: dpb.New(time.Duration(1234)),
221+
SingleTimestamp: tpb.New(time.Unix(12345, 0).UTC()),
222+
SingleBoolWrapper: wrapperspb.Bool(false),
223+
SingleInt32Wrapper: wrapperspb.Int32(42),
224+
StandaloneEnum: proto3pb.TestAllTypes_BAR,
225+
NestedType: &proto3pb.TestAllTypes_SingleNestedMessage{
226+
SingleNestedMessage: &proto3pb.TestAllTypes_NestedMessage{
227+
Bb: 123,
228+
},
229+
},
230+
SingleValue: structpb.NewStringValue("hello world"),
231+
SingleStruct: jsonStruct(t, map[string]any{
232+
"null": nil,
233+
}),
234+
}
235+
msgName := string(msg.ProtoReflect().Descriptor().FullName())
236+
_, err := pbdb.RegisterMessage(msg)
237+
if err != nil {
238+
t.Fatalf("pbdb.RegisterMessage(%q) failed: %v", msgName, err)
239+
}
240+
td, found := pbdb.DescribeType(msgName)
241+
if !found {
242+
t.Fatalf("pbdb.DescribeType(%q) not found", msgName)
243+
}
244+
expected := map[string]any{
245+
"singleUint64": uint64(12),
246+
"singleDuration": time.Duration(1234),
247+
"singleTimestamp": time.Unix(12345, 0).UTC(),
248+
"singleBoolWrapper": false,
249+
"singleInt32Wrapper": int32(42),
250+
"singleInt64Wrapper": structpb.NullValue_NULL_VALUE,
251+
"singleNestedMessage": &proto3pb.TestAllTypes_NestedMessage{
252+
Bb: 123,
253+
},
254+
"standaloneEnum": int64(1),
255+
"singleValue": "hello world",
256+
"singleStruct": jsonStruct(t, map[string]any{
257+
"null": nil,
258+
}),
259+
}
260+
for field, want := range expected {
261+
f, found := td.FieldByName(field)
262+
if !found {
263+
t.Fatalf("td.FieldByName(%q) not found", field)
264+
}
265+
got, err := f.GetFrom(msg)
266+
if err != nil {
267+
t.Fatalf("field.GetFrom() failed: %v", err)
268+
}
269+
switch g := got.(type) {
270+
case proto.Message:
271+
if !proto.Equal(g, want.(proto.Message)) {
272+
t.Errorf("got field %s value %v, wanted %v", field, g, want)
273+
}
274+
default:
275+
if !reflect.DeepEqual(g, want) {
276+
t.Errorf("got field %s value %v, wanted %v", field, g, want)
277+
}
278+
}
279+
}
280+
}
281+
213282
func TestFieldDescriptionIsSet(t *testing.T) {
214283
pbdb := NewDb()
215284
msg := &proto3pb.TestAllTypes{}

0 commit comments

Comments
 (0)