Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d7c26a3

Browse files
committedMay 23, 2024·
POC
1 parent cf09e71 commit d7c26a3

File tree

2 files changed

+159
-2
lines changed

2 files changed

+159
-2
lines changed
 

‎typed/remove.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"sigs.k8s.io/structured-merge-diff/v4/value"
2020
)
2121

22+
var REMOVEKEEPEMPTYCOLLECTIONS = false
23+
2224
type removingWalker struct {
2325
value value.Value
2426
out interface{}
@@ -58,6 +60,9 @@ func (w *removingWalker) doList(t *schema.List) (errs ValidationErrors) {
5860
defer w.allocator.Free(l)
5961
// If list is null or empty just return
6062
if l == nil || l.Length() == 0 {
63+
if REMOVEKEEPEMPTYCOLLECTIONS {
64+
w.out = w.value.Unstructured()
65+
}
6166
return nil
6267
}
6368

@@ -66,6 +71,10 @@ func (w *removingWalker) doList(t *schema.List) (errs ValidationErrors) {
6671
if t.ElementRelationship == schema.Atomic {
6772
if w.shouldExtract {
6873
w.out = w.value.Unstructured()
74+
} else if !w.toRemove.Has(fieldpath.Path{}) && REMOVEKEEPEMPTYCOLLECTIONS {
75+
// If the atomic list itself wasn't being removed, then it
76+
// is being set to empty list (we only get here if a prefix of this fieldPath is in toRemove)
77+
w.out = []interface{}{}
6978
}
7079
return nil
7180
}
@@ -97,7 +106,7 @@ func (w *removingWalker) doList(t *schema.List) (errs ValidationErrors) {
97106
}
98107
newItems = append(newItems, item.Unstructured())
99108
}
100-
if len(newItems) > 0 {
109+
if len(newItems) > 0 || REMOVEKEEPEMPTYCOLLECTIONS {
101110
w.out = newItems
102111
}
103112
return nil
@@ -113,6 +122,9 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors {
113122
}
114123
// If map is null or empty just return
115124
if m == nil || m.Empty() {
125+
if REMOVEKEEPEMPTYCOLLECTIONS {
126+
w.out = w.value
127+
}
116128
return nil
117129
}
118130

@@ -121,6 +133,10 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors {
121133
if t.ElementRelationship == schema.Atomic {
122134
if w.shouldExtract {
123135
w.out = w.value.Unstructured()
136+
} else if !w.toRemove.Has(fieldpath.Path{}) && REMOVEKEEPEMPTYCOLLECTIONS {
137+
// If the atomic map itself wasn't being removed, then it
138+
// is being set to empty map (we only get here if a prefix of this fieldPath is in toRemove)
139+
w.out = map[string]interface{}{}
124140
}
125141
return nil
126142
}
@@ -158,7 +174,7 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors {
158174
newMap[k] = val.Unstructured()
159175
return true
160176
})
161-
if len(newMap) > 0 {
177+
if len(newMap) > 0 || REMOVEKEEPEMPTYCOLLECTIONS {
162178
w.out = newMap
163179
}
164180
return nil

‎typed/update_test.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package typed_test
2+
3+
import (
4+
"testing"
5+
6+
"sigs.k8s.io/structured-merge-diff/v4/internal/fixture"
7+
"sigs.k8s.io/structured-merge-diff/v4/typed"
8+
)
9+
10+
var updateParser = func() fixture.Parser {
11+
parser, err := typed.NewParser(`
12+
types:
13+
- name: nestedOptionalFields
14+
map:
15+
fields:
16+
- name: nestedList
17+
type:
18+
list:
19+
elementRelationship: associative
20+
keys:
21+
- name
22+
elementType:
23+
map:
24+
fields:
25+
- name: name
26+
type:
27+
scalar: string
28+
- name: value
29+
type:
30+
scalar: numeric
31+
- name: nestedMap
32+
type:
33+
map:
34+
elementType:
35+
scalar: numeric
36+
- name: nested
37+
type:
38+
map:
39+
fields:
40+
- name: numeric
41+
type:
42+
scalar: numeric
43+
- name: string
44+
type:
45+
scalar: string
46+
`)
47+
if err != nil {
48+
panic(err)
49+
}
50+
return fixture.SameVersionParser{T: parser.Type("nestedOptionalFields")}
51+
}()
52+
53+
func TestUpdate(t *testing.T) {
54+
tests := map[string]fixture.TestCase{
55+
"delete_nested_fields_struct": {
56+
Ops: []fixture.Operation{
57+
fixture.Apply{
58+
Manager: "default",
59+
APIVersion: "v1",
60+
Object: `
61+
nested:
62+
numeric: 1
63+
string: my string
64+
`,
65+
},
66+
fixture.Apply{
67+
Manager: "default",
68+
APIVersion: "v1",
69+
Object: `
70+
nested: {}
71+
`,
72+
},
73+
},
74+
APIVersion: `v1`,
75+
Object: `{nested: {}}`,
76+
},
77+
"delete_nested_fields_list": {
78+
Ops: []fixture.Operation{
79+
fixture.Apply{
80+
Manager: "default",
81+
APIVersion: "v1",
82+
Object: `
83+
nestedList:
84+
- name: first
85+
- name: second
86+
`,
87+
},
88+
fixture.Apply{
89+
Manager: "default",
90+
APIVersion: "v1",
91+
Object: `
92+
nestedList: []
93+
`,
94+
},
95+
},
96+
APIVersion: `v1`,
97+
Object: `{nestedList: []}`,
98+
},
99+
"delete_nested_fields_map": {
100+
Ops: []fixture.Operation{
101+
fixture.Apply{
102+
Manager: "default",
103+
APIVersion: "v1",
104+
Object: `
105+
nestedMap:
106+
first: 1
107+
second: 2
108+
109+
`,
110+
},
111+
fixture.Apply{
112+
Manager: "default",
113+
APIVersion: "v1",
114+
Object: `
115+
nestedMap: {}
116+
`,
117+
},
118+
},
119+
APIVersion: `v1`,
120+
Object: `{nestedMap: {}}`,
121+
},
122+
}
123+
124+
for name, tc := range tests {
125+
tc2 := tc
126+
t.Run(name, func(t *testing.T) {
127+
typed.REMOVEKEEPEMPTYCOLLECTIONS = true
128+
if err := tc.Test(updateParser); err != nil {
129+
t.Fatal(err)
130+
}
131+
})
132+
133+
t.Run(name+"Nil", func(t *testing.T) {
134+
typed.REMOVEKEEPEMPTYCOLLECTIONS = false
135+
if err := tc2.Test(updateParser); err != nil {
136+
t.Fatal(err)
137+
}
138+
})
139+
}
140+
141+
}

0 commit comments

Comments
 (0)
Please sign in to comment.