diff --git a/perxis-proto b/perxis-proto index 2e4728f6f3d5d63dcb9d5548b17af9efce605280..d05d75325479800baef608bcde55c46b42b019e0 160000 --- a/perxis-proto +++ b/perxis-proto @@ -1 +1 @@ -Subproject commit 2e4728f6f3d5d63dcb9d5548b17af9efce605280 +Subproject commit d05d75325479800baef608bcde55c46b42b019e0 diff --git a/pkg/schema/localizer/localizer_test.go b/pkg/schema/localizer/localizer_test.go index ded5628dcdd2ec0686243a0da08ef8612d498777..fffda4b78c98f5f7a4ee6e10fcb3007297598123 100644 --- a/pkg/schema/localizer/localizer_test.go +++ b/pkg/schema/localizer/localizer_test.go @@ -762,6 +762,7 @@ func TestLocalizer_ExtractTranslations(t *testing.T) { s := schema.New( "a", field.String(), + "b", field.String(), ) tests := []struct { @@ -877,7 +878,7 @@ func TestLocalizer_ExtractTranslations(t *testing.T) { { name: "Extract fallback with same", data: map[string]interface{}{"a": "aaa"}, - translations: map[string]map[string]interface{}{"ru": {"a": "aaa"}, "en": {"a": "aaa"}}, + translations: map[string]map[string]interface{}{"ru": {"a": "aaa"}, "en": {"a": "aaa", "b": "bbb"}}, cfg: Config{ LocaleID: "ru", Schema: s, diff --git a/pkg/schema/walk/walk.go b/pkg/schema/walk/walk.go index 73bd1f9258d17d33fa4350a18a835e786f1082b5..ab11ebe6ee0614a702c4c2a0f5747afe0e994ea4 100644 --- a/pkg/schema/walk/walk.go +++ b/pkg/schema/walk/walk.go @@ -120,6 +120,7 @@ func (m *Walker) datawalk(w *WalkContext) (err error) { fields := p.GetFields(true) + var objChanged bool for k := range keys { f, ok := fields[k] if !ok { @@ -144,13 +145,16 @@ func (m *Walker) datawalk(w *WalkContext) (err error) { } if wc.Changed { + objChanged = true w.Changed = true } } - if len(res) > 0 { + + if objChanged || len(res) != len(d) { // in generic merge unknown fields are removed but change is not set w.Dst = res } + case *field.ArrayParameters: d, _ := w.Dst.([]interface{}) s, _ := w.Src.([]interface{}) @@ -175,7 +179,6 @@ func (m *Walker) datawalk(w *WalkContext) (err error) { w.Changed = true } } - } return diff --git a/pkg/schema/walk/walk_test.go b/pkg/schema/walk/walk_test.go index 3fd01bd577c3fe16abb1cae7b2e9785e0edc659c..be33aa2fed74abb6493cd9aa5dd2b3470847c3d8 100644 --- a/pkg/schema/walk/walk_test.go +++ b/pkg/schema/walk/walk_test.go @@ -56,10 +56,10 @@ func TestWalker_DataWalk(t *testing.T) { "a": "src_obj1_a", "b": "src_obj1_b", "obj2": map[string]interface{}{ - "a": "dst_obj1_obj2_a", + "a": "src_obj1_obj2_a", }, "obj3": map[string]interface{}{ - "e": "dst_obj1_obj3_e", + "e": "src_obj1_obj3_e", }, }, "inline_str_1": "src_inline_1", @@ -109,10 +109,10 @@ func TestWalker_DataWalk(t *testing.T) { "a": "src_obj1_a", "b": "src_obj1_b", "obj2": map[string]interface{}{ - "a": "dst_obj1_obj2_a", + "a": "src_obj1_obj2_a", }, "obj3": map[string]interface{}{ - "e": "dst_obj1_obj3_e", + "e": "src_obj1_obj3_e", }, }, "inline_str_1": "src_inline_1", @@ -162,10 +162,10 @@ func TestWalker_DataWalk(t *testing.T) { "a": "src_obj1_a", "b": "src_obj1_b", "obj2": map[string]interface{}{ - "a": "dst_obj1_obj2_a", + "a": "src_obj1_obj2_a", }, "obj3": map[string]interface{}{ - "e": "dst_obj1_obj3_e", + "e": "src_obj1_obj3_e", }, }, "inline_str_1": "src_inline_1", @@ -179,10 +179,10 @@ func TestWalker_DataWalk(t *testing.T) { "a": "src_obj1_a", "b": "src_obj1_b", "obj2": map[string]interface{}{ - "a": "dst_obj1_obj2_a", + "a": "src_obj1_obj2_a", }, "obj3": map[string]interface{}{ - "e": "dst_obj1_obj3_e", + "e": "src_obj1_obj3_e", }, }, "inline_str_1": "src_inline_1", @@ -196,10 +196,10 @@ func TestWalker_DataWalk(t *testing.T) { "a": "src_obj1_a", "b": "src_obj1_b", "obj2": map[string]interface{}{ - "a": "dst_obj1_obj2_a", + "a": "src_obj1_obj2_a", }, "obj3": map[string]interface{}{ - "e": "dst_obj1_obj3_e", + "e": "src_obj1_obj3_e", }, }, "inline_str_1": "src_inline_1", @@ -208,6 +208,220 @@ func TestWalker_DataWalk(t *testing.T) { }, false, false, }, + {"keep src nil", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "a": {Fn: KeepSrc}, + "obj1.a": {Fn: KeepSrc}, + "inline_str_1": {Fn: KeepSrc}, + "slice.1": {Fn: KeepSrc}, + }, + }, + map[string]interface{}{ + "b": "src_b", + "obj1": map[string]interface{}{ + "b": "src_obj1_b", + "obj2": map[string]interface{}{ + "a": "scr_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "src_obj1_obj3_e", + }, + }, + "slice": []interface{}{"src_s1"}, + }, + map[string]interface{}{ + "a": "dst_a", + "b": "dst_b", + "obj1": map[string]interface{}{ + "a": "dst_obj1_a", + "b": "dst_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"dst_s1", "dst_s2"}, + }, + map[string]interface{}{ + "b": "dst_b", + "obj1": map[string]interface{}{ + "b": "dst_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"dst_s1", nil}, + }, + true, false, + }, + {"keep src nil #2", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "a": {Fn: KeepSrc}, + }, + }, + map[string]interface{}{}, + map[string]interface{}{ + "a": "dst_a", + }, + map[string]interface{}{}, + true, false, + }, + {"keep src ni #3", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "obj1": {Fn: KeepSrc}, + "slice": {Fn: KeepSrc}, + }, + }, + map[string]interface{}{ + "b": "src_b", + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "obj1": map[string]interface{}{ + "a": "src_obj1_a", + "b": "src_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"src_s1", "src_s2"}, + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + }, + true, false, + }, + {"keep src ni #3", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "obj1.a": {Fn: KeepSrc}, + "obj1.b": {Fn: KeepSrc}, + "obj1.obj2": {Fn: KeepSrc}, + "obj1.obj3": {Fn: KeepSrc}, + }, + }, + map[string]interface{}{ + "b": "src_b", + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "obj1": map[string]interface{}{ + "a": "src_obj1_a", + "b": "src_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "obj1": map[string]interface{}{}, + }, + true, false, + }, + {"remove fields", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "a": {Fn: RemoveValue}, + "obj1.a": {Fn: RemoveValue}, + "inline_str_1": {Fn: RemoveValue}, + "slice.1": {Fn: RemoveValue}, + }, + }, + map[string]interface{}{}, + map[string]interface{}{ + "a": "dst_a", + "b": "dst_b", + "obj1": map[string]interface{}{ + "a": "dst_obj1_a", + "b": "dst_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"dst_s1", "dts_s2"}, + }, + map[string]interface{}{ + "b": "dst_b", + "obj1": map[string]interface{}{ + "b": "dst_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"dst_s1", nil}, + }, + true, false, + }, + {"remove fields #2", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "obj1": {Fn: RemoveValue}, + "slice": {Fn: RemoveValue}, + }, + }, + map[string]interface{}{ + "b": "src_b", + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "obj1": map[string]interface{}{ + "a": "src_obj1_a", + "b": "src_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"src_s1", "src_s2"}, + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + }, + true, false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {