Skip to content

Commit e323b24

Browse files
authored
fix: slice index patch (#79)
1 parent 2eb23ac commit e323b24

2 files changed

Lines changed: 16 additions & 33 deletions

File tree

patch_slice.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,23 @@ func (d *Differ) renderSlice(c *ChangeValue) {
1717

1818
//field better be an index of the slice
1919
if c.index, err = strconv.Atoi(field); err != nil {
20-
c.AddError(NewErrorf("invalid index in path. %s is not a number", field).
21-
WithCause(err))
20+
//if struct element is has identifier, use it instead
21+
if identifier(d.TagName, reflect.Zero(c.target.Type().Elem())) != nil {
22+
for c.index = 0; c.index < c.Len(); c.index++ {
23+
if identifier(d.TagName, c.Index(c.index)) == field {
24+
break
25+
}
26+
}
27+
} else {
28+
c.AddError(NewErrorf("invalid index in path. %s is not a number", field).
29+
WithCause(err))
30+
}
2231
}
2332
var x reflect.Value
2433
if c.Len() > c.index {
2534
x = c.Index(c.index)
35+
} else if c.change.Type == CREATE && !c.HasFlag(OptionNoCreate) {
36+
x = c.NewArrayElement()
2637
}
2738
if !x.IsValid() {
2839
if !c.HasFlag(OptionOmitUnequal) {

patch_test.go

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,143 +15,123 @@ func TestPatch(t *testing.T) {
1515
Name string
1616
A, B interface{}
1717
Changelog diff.Changelog
18-
Error error
1918
}{
2019
{
2120
"uint-slice-insert", &[]uint{1, 2, 3}, &[]uint{1, 2, 3, 4},
2221
diff.Changelog{
2322
diff.Change{Type: diff.CREATE, Path: []string{"3"}, To: uint(4)},
2423
},
25-
nil,
2624
},
2725
{
2826
"int-slice-insert", &[]int{1, 2, 3}, &[]int{1, 2, 3, 4},
2927
diff.Changelog{
3028
diff.Change{Type: diff.CREATE, Path: []string{"3"}, To: 4},
3129
},
32-
nil,
3330
},
3431
{
3532
"uint-slice-delete", &[]uint{1, 2, 3}, &[]uint{1, 3},
3633
diff.Changelog{
3734
diff.Change{Type: diff.DELETE, Path: []string{"1"}, From: uint(2)},
3835
},
39-
nil,
4036
},
4137
{
4238
"int-slice-delete", &[]int{1, 2, 3}, &[]int{1, 3},
4339
diff.Changelog{
4440
diff.Change{Type: diff.DELETE, Path: []string{"1"}, From: 2},
4541
},
46-
nil,
4742
},
4843
{
4944
"uint-slice-insert-delete", &[]uint{1, 2, 3}, &[]uint{1, 3, 4},
5045
diff.Changelog{
5146
diff.Change{Type: diff.DELETE, Path: []string{"1"}, From: uint(2)},
5247
diff.Change{Type: diff.CREATE, Path: []string{"2"}, To: uint(4)},
5348
},
54-
nil,
5549
},
5650
{
5751
"int-slice-insert-delete", &[]int{1, 2, 3}, &[]int{1, 3, 4},
5852
diff.Changelog{
5953
diff.Change{Type: diff.DELETE, Path: []string{"1"}, From: 2},
6054
diff.Change{Type: diff.CREATE, Path: []string{"2"}, To: 4},
6155
},
62-
nil,
6356
},
6457
{
6558
"string-slice-insert", &[]string{"1", "2", "3"}, &[]string{"1", "2", "3", "4"},
6659
diff.Changelog{
6760
diff.Change{Type: diff.CREATE, Path: []string{"3"}, To: "4"},
6861
},
69-
nil,
7062
},
7163
{
7264
"string-slice-delete", &[]string{"1", "2", "3"}, &[]string{"1", "3"},
7365
diff.Changelog{
7466
diff.Change{Type: diff.DELETE, Path: []string{"1"}, From: "2"},
7567
},
76-
nil,
7768
},
7869
{
7970
"string-slice-insert-delete", &[]string{"1", "2", "3"}, &[]string{"1", "3", "4"},
8071
diff.Changelog{
8172
diff.Change{Type: diff.DELETE, Path: []string{"1"}, From: "2"},
8273
diff.Change{Type: diff.CREATE, Path: []string{"2"}, To: "4"},
8374
},
84-
nil,
8575
},
8676
{
87-
"comparable-slice-update", &[]tistruct{{"one", 1}}, &[]tistruct{{"one", 50}},
77+
"comparable-slice-update", &[]tistruct{{"one", 1}, {"two", 2}}, &[]tistruct{{"one", 1}, {"two", 50}},
8878
diff.Changelog{
89-
diff.Change{Type: diff.UPDATE, Path: []string{"one", "value"}, From: 1, To: 50},
79+
diff.Change{Type: diff.UPDATE, Path: []string{"two", "value"}, From: 1, To: 50},
9080
},
91-
nil,
9281
},
9382
{
9483
"struct-string-update", &tstruct{Name: "one"}, &tstruct{Name: "two"},
9584
diff.Changelog{
9685
diff.Change{Type: diff.UPDATE, Path: []string{"name"}, From: "one", To: "two"},
9786
},
98-
nil,
9987
},
10088
{
10189
"struct-int-update", &tstruct{Value: 1}, &tstruct{Value: 50},
10290
diff.Changelog{
10391
diff.Change{Type: diff.UPDATE, Path: []string{"value"}, From: 1, To: 50},
10492
},
105-
nil,
10693
},
10794
{
10895
"struct-bool-update", &tstruct{Bool: true}, &tstruct{Bool: false},
10996
diff.Changelog{
11097
diff.Change{Type: diff.UPDATE, Path: []string{"bool"}, From: true, To: false},
11198
},
112-
nil,
11399
},
114100
{
115101
"struct-time-update", &tstruct{}, &tstruct{Time: currentTime},
116102
diff.Changelog{
117103
diff.Change{Type: diff.UPDATE, Path: []string{"time"}, From: time.Time{}, To: currentTime},
118104
},
119-
nil,
120105
},
121106
{
122107
"struct-nil-string-pointer-update", &tstruct{Pointer: nil}, &tstruct{Pointer: sptr("test")},
123108
diff.Changelog{
124109
diff.Change{Type: diff.UPDATE, Path: []string{"pointer"}, From: nil, To: sptr("test")},
125110
},
126-
nil,
127111
},
128112
{
129113
"struct-string-pointer-update-to-nil", &tstruct{Pointer: sptr("test")}, &tstruct{Pointer: nil},
130114
diff.Changelog{
131115
diff.Change{Type: diff.UPDATE, Path: []string{"pointer"}, From: sptr("test"), To: nil},
132116
},
133-
nil,
134117
}, {
135118
"struct-generic-slice-insert", &tstruct{Values: []string{"one"}}, &tstruct{Values: []string{"one", "two"}},
136119
diff.Changelog{
137120
diff.Change{Type: diff.CREATE, Path: []string{"values", "1"}, From: nil, To: "two"},
138121
},
139-
nil,
140122
},
141123
{
142124
"struct-generic-slice-delete", &tstruct{Values: []string{"one", "two"}}, &tstruct{Values: []string{"one"}},
143125
diff.Changelog{
144126
diff.Change{Type: diff.DELETE, Path: []string{"values", "1"}, From: "two", To: nil},
145127
},
146-
nil,
147128
},
148129
{
149130
"struct-unidentifiable-slice-insert-delete", &tstruct{Unidentifiables: []tuistruct{{1}, {2}, {3}}}, &tstruct{Unidentifiables: []tuistruct{{5}, {2}, {3}, {4}}},
150131
diff.Changelog{
151132
diff.Change{Type: diff.UPDATE, Path: []string{"unidentifiables", "0", "value"}, From: 1, To: 5},
152133
diff.Change{Type: diff.CREATE, Path: []string{"unidentifiables", "3", "value"}, From: nil, To: 4},
153134
},
154-
nil,
155135
},
156136
{
157137
"slice", &tstruct{}, &tstruct{Nested: tnstruct{Slice: []tmstruct{{"one", 1}, {"two", 2}}}},
@@ -161,14 +141,12 @@ func TestPatch(t *testing.T) {
161141
diff.Change{Type: diff.CREATE, Path: []string{"nested", "slice", "1", "foo"}, From: nil, To: "two"},
162142
diff.Change{Type: diff.CREATE, Path: []string{"nested", "slice", "1", "bar"}, From: nil, To: 2},
163143
},
164-
nil,
165144
},
166145
{
167146
"slice-duplicate-items", &[]int{1}, &[]int{1, 1},
168147
diff.Changelog{
169148
diff.Change{Type: diff.CREATE, Path: []string{"1"}, From: nil, To: 1},
170149
},
171-
nil,
172150
},
173151
{
174152
"embedded-struct-field",
@@ -179,7 +157,6 @@ func TestPatch(t *testing.T) {
179157
diff.Change{Type: diff.UPDATE, Path: []string{"bar"}, From: 2, To: 3},
180158
diff.Change{Type: diff.UPDATE, Path: []string{"baz"}, From: true, To: false},
181159
},
182-
nil,
183160
},
184161
{
185162
"custom-tags",
@@ -189,7 +166,6 @@ func TestPatch(t *testing.T) {
189166
diff.Change{Type: diff.UPDATE, Path: []string{"foo"}, From: "abc", To: "def"},
190167
diff.Change{Type: diff.UPDATE, Path: []string{"bar"}, From: 3, To: 4},
191168
},
192-
nil,
193169
},
194170
{
195171
"custom-types",
@@ -199,7 +175,6 @@ func TestPatch(t *testing.T) {
199175
diff.Change{Type: diff.UPDATE, Path: []string{"foo"}, From: CustomStringType("a"), To: CustomStringType("b")},
200176
diff.Change{Type: diff.UPDATE, Path: []string{"bar"}, From: CustomIntType(1), To: CustomIntType(2)},
201177
},
202-
nil,
203178
},
204179
{
205180
"map",
@@ -210,7 +185,6 @@ func TestPatch(t *testing.T) {
210185
diff.Change{Type: diff.CREATE, Path: []string{"2"}, From: nil, To: "two"},
211186
diff.Change{Type: diff.UPDATE, Path: []string{"3"}, From: "three", To: "tres"},
212187
},
213-
nil,
214188
},
215189
{
216190
"map-nested-create",
@@ -219,7 +193,6 @@ func TestPatch(t *testing.T) {
219193
diff.Changelog{
220194
diff.Change{Type: "create", Path: []string{"details", "secondary-attributes"}, From: nil, To: map[string]interface{}{"attrA": "A", "attrB": "B"}},
221195
},
222-
nil,
223196
},
224197
{
225198
"map-nested-update",
@@ -228,7 +201,6 @@ func TestPatch(t *testing.T) {
228201
diff.Changelog{
229202
diff.Change{Type: "update", Path: []string{"details", "attributes"}, From: map[string]interface{}{"attrA": "A", "attrB": "B"}, To: map[string]interface{}{"attrA": "C", "attrD": "X"}},
230203
},
231-
nil,
232204
},
233205
{
234206
"map-nested-delete",
@@ -237,7 +209,6 @@ func TestPatch(t *testing.T) {
237209
diff.Changelog{
238210
diff.Change{Type: "delete", Path: []string{"details", "attributes"}, From: map[string]interface{}{"attrA": "A", "attrB": "B"}, To: nil},
239211
},
240-
nil,
241212
},
242213
}
243214

@@ -261,6 +232,7 @@ func TestPatch(t *testing.T) {
261232

262233
assert.Equal(t, tc.B, tc.A)
263234
require.Equal(t, len(tc.Changelog), len(pl))
235+
assert.False(t, pl.HasErrors())
264236
})
265237
}
266238

0 commit comments

Comments
 (0)