diff --git a/internal/servers/controller/handlers/mask_manager.go b/internal/servers/controller/handlers/mask_manager.go index 2f319c5a4e..ef3f9d26a9 100644 --- a/internal/servers/controller/handlers/mask_manager.go +++ b/internal/servers/controller/handlers/mask_manager.go @@ -19,8 +19,9 @@ type ( MaskSource []protoreflect.ProtoMessage ) -// NewMaskManager returns a mask manager that can translate field masks into the first proto from all subsequent -// protos assuming they are both using the mask_mapping custom option. Error is returned if no mappings are +// NewMaskManager returns a mask manager that can translate field masks into +// the first proto from all subsequent protos assuming they are both using the +// mask_mapping custom option. Error is returned if no mappings are // found or if one of the passed protos has a mapping that doesn't reciprocate. func NewMaskManager(dest MaskDestination, src MaskSource) (MaskManager, error) { const op = "handlers.NewMaskManager" @@ -76,14 +77,32 @@ func mapFromProto(ps []protoreflect.ProtoMessage) (map[string]string, error) { return mapping, nil } -// Translate takes a field mask's paths and returns paths translated for the destination's protobuf. -func (m MaskManager) Translate(paths []string) []string { +// Translate takes a field mask's paths and returns paths translated for the +// destination's protobuf. If a translation doesn't exist for a specific path +// entry then nothing is returned for that specific path entry unless +// passedThroughPrefix is used and applies to that entry. +// +// passedThroughPrefix is helpful when the field mask's paths cannot be mapped +// through the mask mapper for some reason (we don't know the mapping at compile +// time, for example) but we still want certain paths to be passed on. If a +// path entry isn't mapped to anything by the MaskManager but does contain +// a prefix which matches a passedThroughPrefix it will be added unmodified +// to the returned value. +func (m MaskManager) Translate(paths []string, passedThroughPrefix ...string) []string { var result []string for _, v := range paths { vSplit := strings.Split(v, ",") for _, v := range vSplit { - if ov, ok := m[strings.TrimSpace(v)]; ok { + candidate := strings.TrimSpace(v) + if ov, ok := m[candidate]; ok { result = append(result, ov) + } else { + for _, pre := range passedThroughPrefix { + if strings.HasPrefix(candidate, pre) { + result = append(result, candidate) + break + } + } } } } diff --git a/internal/servers/controller/handlers/mask_manager_test.go b/internal/servers/controller/handlers/mask_manager_test.go index 1948a1280d..a0638be737 100644 --- a/internal/servers/controller/handlers/mask_manager_test.go +++ b/internal/servers/controller/handlers/mask_manager_test.go @@ -17,6 +17,11 @@ func TestMaskManager(t *testing.T) { assert.Equal(t, []string(nil), mm.Translate([]string{"FiRsT_fIeLd"})) assert.Equal(t, []string{"other_second_field"}, mm.Translate([]string{"strangly_formatted_field"})) assert.Equal(t, []string{"other_second_field", "other_field_3"}, mm.Translate([]string{"strangly_formatted_field", "field3"})) + + // the passedThroughPrefix allows fields to be passed through unmodified + assert.Equal(t, []string{"OtherFirstField", "attributes.doesnt_exist"}, mm.Translate([]string{"first_field", "attributes.doesnt_exist"}, "attributes.")) + // the passedThroughPrefix is ignored if the field already matches a mapped value + assert.Equal(t, []string{"other_second_field", "other_field_3"}, mm.Translate([]string{"strangly_formatted_field", "field3"}, "strangely_")) } func TestMaskManager_Split(t *testing.T) {