From d0ce031ddf58caeb9c5a4ba4d7b3ff280b31f7a6 Mon Sep 17 00:00:00 2001 From: Felipe Araujo Date: Tue, 26 Sep 2023 10:30:12 +0100 Subject: [PATCH] feat(fieldbehavior): Support `optional` keyword when validating REQUIRED fields --- fieldbehavior/fieldbehavior.go | 7 ++- fieldbehavior/fieldbehavior_test.go | 11 ++++ proto/einride/example/freight/v1/site.proto | 2 + .../gen/einride/example/freight/v1/site.pb.go | 61 ++++++++++++------- 4 files changed, 56 insertions(+), 25 deletions(-) diff --git a/fieldbehavior/fieldbehavior.go b/fieldbehavior/fieldbehavior.go index 0f984518cd..e59a520797 100644 --- a/fieldbehavior/fieldbehavior.go +++ b/fieldbehavior/fieldbehavior.go @@ -62,13 +62,16 @@ func CopyFields(dst, src proto.Message, behaviorsToCopy ...annotations.FieldBeha } func isMessageFieldPresent(m protoreflect.Message, f protoreflect.FieldDescriptor) bool { - return isPresent(m.Get(f), f) + return isPresent(m.Get(f), f, m.Has(f)) } -func isPresent(v protoreflect.Value, f protoreflect.FieldDescriptor) bool { +func isPresent(v protoreflect.Value, f protoreflect.FieldDescriptor, populated bool) bool { if !v.IsValid() { return false } + if f.HasOptionalKeyword() && populated { + return true + } if f.IsList() { return v.List().Len() > 0 } diff --git a/fieldbehavior/fieldbehavior_test.go b/fieldbehavior/fieldbehavior_test.go index 9934f43cd5..2857317efe 100644 --- a/fieldbehavior/fieldbehavior_test.go +++ b/fieldbehavior/fieldbehavior_test.go @@ -100,6 +100,17 @@ func TestValidateRequiredFieldsWithMask(t *testing.T) { "missing required field: shipment.origin_site", ) }) + t.Run("missing optional field annotated with required", func(t *testing.T) { + t.Parallel() + assert.Error( + t, + ValidateRequiredFieldsWithMask( + &examplefreightv1.Site{}, + &fieldmaskpb.FieldMask{Paths: []string{"personnel_count"}}, + ), + "missing required field: personnel_count", + ) + }) t.Run("missing nested not in mask", func(t *testing.T) { t.Parallel() assert.NilError( diff --git a/proto/einride/example/freight/v1/site.proto b/proto/einride/example/freight/v1/site.proto index 370e67344f..0193098cad 100644 --- a/proto/einride/example/freight/v1/site.proto +++ b/proto/einride/example/freight/v1/site.proto @@ -30,4 +30,6 @@ message Site { string display_name = 5 [(google.api.field_behavior) = REQUIRED]; // The geographic location of the site. google.type.LatLng lat_lng = 6; + // Personnel count on site. + optional int64 personnel_count = 7 [(google.api.field_behavior) = REQUIRED]; } diff --git a/proto/gen/einride/example/freight/v1/site.pb.go b/proto/gen/einride/example/freight/v1/site.pb.go index e52c1c3a1b..20e2ca2e86 100644 --- a/proto/gen/einride/example/freight/v1/site.pb.go +++ b/proto/gen/einride/example/freight/v1/site.pb.go @@ -44,6 +44,8 @@ type Site struct { DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // The geographic location of the site. LatLng *latlng.LatLng `protobuf:"bytes,6,opt,name=lat_lng,json=latLng,proto3" json:"lat_lng,omitempty"` + // Personnel count on site. + PersonnelCount *int64 `protobuf:"varint,7,opt,name=personnel_count,json=personnelCount,proto3,oneof" json:"personnel_count,omitempty"` } func (x *Site) Reset() { @@ -120,6 +122,13 @@ func (x *Site) GetLatLng() *latlng.LatLng { return nil } +func (x *Site) GetPersonnelCount() int64 { + if x != nil && x.PersonnelCount != nil { + return *x.PersonnelCount + } + return 0 +} + var File_einride_example_freight_v1_site_proto protoreflect.FileDescriptor var file_einride_example_freight_v1_site_proto_rawDesc = []byte{ @@ -134,7 +143,7 @@ var file_einride_example_freight_v1_site_proto_rawDesc = []byte{ 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x2f, 0x6c, 0x61, - 0x74, 0x6c, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8c, 0x03, 0x0a, 0x04, 0x53, + 0x74, 0x6c, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd3, 0x03, 0x0a, 0x04, 0x53, 0x69, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, @@ -154,28 +163,33 @@ var file_einride_example_freight_v1_site_proto_rawDesc = []byte{ 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x6c, 0x61, 0x74, 0x5f, 0x6c, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x4c, 0x61, 0x74, 0x4c, 0x6e, 0x67, 0x52, 0x06, 0x6c, 0x61, 0x74, - 0x4c, 0x6e, 0x67, 0x3a, 0x54, 0xea, 0x41, 0x51, 0x0a, 0x21, 0x66, 0x72, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x2d, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x65, 0x69, 0x6e, 0x72, 0x69, 0x64, - 0x65, 0x2e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x53, 0x69, 0x74, 0x65, 0x12, 0x1f, 0x73, 0x68, 0x69, - 0x70, 0x70, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x73, 0x68, 0x69, 0x70, 0x70, 0x65, 0x72, 0x7d, 0x2f, - 0x73, 0x69, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x69, 0x74, 0x65, 0x7d, 0x2a, 0x05, 0x73, 0x69, - 0x74, 0x65, 0x73, 0x32, 0x04, 0x73, 0x69, 0x74, 0x65, 0x42, 0xfa, 0x01, 0x0a, 0x1e, 0x63, 0x6f, - 0x6d, 0x2e, 0x65, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x2e, 0x66, 0x72, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x09, 0x53, 0x69, - 0x74, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x42, 0x67, 0x6f, 0x2e, 0x65, 0x69, - 0x6e, 0x72, 0x69, 0x64, 0x65, 0x2e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x61, 0x69, 0x70, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x65, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, - 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x66, 0x72, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x2f, 0x76, 0x31, 0x3b, 0x66, 0x72, 0x65, 0x69, 0x67, 0x68, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, - 0x45, 0x45, 0x46, 0xaa, 0x02, 0x1a, 0x45, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, 0x2e, 0x45, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x46, 0x72, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2e, 0x56, 0x31, - 0xca, 0x02, 0x1a, 0x45, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, 0x5c, 0x45, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x5c, 0x46, 0x72, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x26, - 0x45, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, 0x5c, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5c, - 0x46, 0x72, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1d, 0x45, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, - 0x3a, 0x3a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x3a, 0x3a, 0x46, 0x72, 0x65, 0x69, 0x67, - 0x68, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4c, 0x6e, 0x67, 0x12, 0x31, 0x0a, 0x0f, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x6e, 0x65, 0x6c, + 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x42, 0x03, 0xe0, 0x41, + 0x02, 0x48, 0x00, 0x52, 0x0e, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x3a, 0x54, 0xea, 0x41, 0x51, 0x0a, 0x21, 0x66, 0x72, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x2d, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x65, 0x69, 0x6e, + 0x72, 0x69, 0x64, 0x65, 0x2e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x53, 0x69, 0x74, 0x65, 0x12, 0x1f, + 0x73, 0x68, 0x69, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x73, 0x68, 0x69, 0x70, 0x70, 0x65, + 0x72, 0x7d, 0x2f, 0x73, 0x69, 0x74, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x69, 0x74, 0x65, 0x7d, 0x2a, + 0x05, 0x73, 0x69, 0x74, 0x65, 0x73, 0x32, 0x04, 0x73, 0x69, 0x74, 0x65, 0x42, 0x12, 0x0a, 0x10, + 0x5f, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x42, 0xfa, 0x01, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x66, 0x72, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x2e, 0x76, 0x31, 0x42, 0x09, 0x53, 0x69, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x42, 0x67, 0x6f, 0x2e, 0x65, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, 0x2e, 0x74, 0x65, 0x63, + 0x68, 0x2f, 0x61, 0x69, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, + 0x65, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, + 0x66, 0x72, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x66, 0x72, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x45, 0x45, 0x46, 0xaa, 0x02, 0x1a, 0x45, 0x69, 0x6e, + 0x72, 0x69, 0x64, 0x65, 0x2e, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x46, 0x72, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x1a, 0x45, 0x69, 0x6e, 0x72, 0x69, 0x64, + 0x65, 0x5c, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5c, 0x46, 0x72, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x26, 0x45, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, 0x5c, 0x45, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5c, 0x46, 0x72, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5c, 0x56, + 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1d, + 0x45, 0x69, 0x6e, 0x72, 0x69, 0x64, 0x65, 0x3a, 0x3a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x3a, 0x3a, 0x46, 0x72, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -227,6 +241,7 @@ func file_einride_example_freight_v1_site_proto_init() { } } } + file_einride_example_freight_v1_site_proto_msgTypes[0].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{